Bug Summary

File:home/maarten/src/libreoffice/core/include/tools/ref.hxx
Warning:line 56, column 30
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name DomainMapper_Impl.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/oox/generated -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/writerfilter/source -I /home/maarten/src/libreoffice/core/writerfilter/inc -I /home/maarten/src/libreoffice/core/writerfilter/source -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx

/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx

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 <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
21#include <com/sun/star/beans/XPropertySet.hpp>
22#include <com/sun/star/document/XDocumentProperties.hpp>
23#include <ooxml/resourceids.hxx>
24#include "DomainMapper_Impl.hxx"
25#include "ConversionHelper.hxx"
26#include "SdtHelper.hxx"
27#include "DomainMapperTableHandler.hxx"
28#include "TagLogger.hxx"
29#include <com/sun/star/uno/XComponentContext.hpp>
30#include <com/sun/star/graphic/XGraphic.hpp>
31#include <com/sun/star/beans/XPropertyState.hpp>
32#include <com/sun/star/container/XNamed.hpp>
33#include <com/sun/star/document/PrinterIndependentLayout.hpp>
34#include <com/sun/star/document/IndexedPropertyValues.hpp>
35#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
36#include <com/sun/star/embed/XEmbeddedObject.hpp>
37#include <com/sun/star/lang/XServiceInfo.hpp>
38#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
39#include <com/sun/star/style/LineNumberPosition.hpp>
40#include <com/sun/star/style/LineSpacing.hpp>
41#include <com/sun/star/style/LineSpacingMode.hpp>
42#include <com/sun/star/text/ChapterFormat.hpp>
43#include <com/sun/star/text/FilenameDisplayFormat.hpp>
44#include <com/sun/star/text/SetVariableType.hpp>
45#include <com/sun/star/text/XDocumentIndex.hpp>
46#include <com/sun/star/text/XDocumentIndexesSupplier.hpp>
47#include <com/sun/star/text/XFootnote.hpp>
48#include <com/sun/star/text/XLineNumberingProperties.hpp>
49#include <com/sun/star/style/XStyle.hpp>
50#include <com/sun/star/text/PageNumberType.hpp>
51#include <com/sun/star/text/HoriOrientation.hpp>
52#include <com/sun/star/text/VertOrientation.hpp>
53#include <com/sun/star/text/ReferenceFieldPart.hpp>
54#include <com/sun/star/text/RelOrientation.hpp>
55#include <com/sun/star/text/ReferenceFieldSource.hpp>
56#include <com/sun/star/text/SizeType.hpp>
57#include <com/sun/star/text/TextContentAnchorType.hpp>
58#include <com/sun/star/text/WrapTextMode.hpp>
59#include <com/sun/star/text/XDependentTextField.hpp>
60#include <com/sun/star/text/XParagraphCursor.hpp>
61#include <com/sun/star/text/XRedline.hpp>
62#include <com/sun/star/text/XTextFieldsSupplier.hpp>
63#include <com/sun/star/text/XTextFrame.hpp>
64#include <com/sun/star/text/RubyPosition.hpp>
65#include <com/sun/star/text/XTextRangeCompare.hpp>
66#include <com/sun/star/style/DropCapFormat.hpp>
67#include <com/sun/star/util/NumberFormatter.hpp>
68#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
69#include <com/sun/star/util/XNumberFormatter.hpp>
70#include <com/sun/star/document/XViewDataSupplier.hpp>
71#include <com/sun/star/container/XIndexContainer.hpp>
72#include <com/sun/star/text/ControlCharacter.hpp>
73#include <com/sun/star/text/XTextColumns.hpp>
74#include <com/sun/star/awt/CharSet.hpp>
75#include <com/sun/star/lang/XMultiServiceFactory.hpp>
76#include <editeng/flditem.hxx>
77#include <editeng/unotext.hxx>
78#include <o3tl/temporary.hxx>
79#include <oox/mathml/import.hxx>
80#include <xmloff/odffields.hxx>
81#include <rtl/uri.hxx>
82#include <dmapper/GraphicZOrderHelper.hxx>
83
84#include <oox/token/tokens.hxx>
85
86#include <cmath>
87#include <optional>
88#include <map>
89#include <tuple>
90#include <unordered_map>
91#include <regex>
92#include <algorithm>
93
94#include <officecfg/Office/Common.hxx>
95#include <filter/msfilter/util.hxx>
96#include <filter/msfilter/ww8fields.hxx>
97#include <comphelper/sequence.hxx>
98#include <comphelper/propertyvalue.hxx>
99#include <comphelper/propertysequence.hxx>
100#include <unotools/configmgr.hxx>
101#include <unotools/mediadescriptor.hxx>
102#include <tools/diagnose_ex.h>
103#include <sal/log.hxx>
104#include <com/sun/star/drawing/FillStyle.hpp>
105
106#include <unicode/errorcode.h>
107#include <unicode/regex.h>
108
109using namespace ::com::sun::star;
110using namespace oox;
111namespace writerfilter::dmapper{
112
113//line numbering for header/footer
114static void lcl_linenumberingHeaderFooter( const uno::Reference<container::XNameContainer>& xStyles, const OUString& rname, DomainMapper_Impl* dmapper )
115{
116 const StyleSheetEntryPtr pEntry = dmapper->GetStyleSheetTable()->FindStyleSheetByISTD( rname );
117 if (!pEntry)
118 return;
119 const StyleSheetPropertyMap* pStyleSheetProperties = dynamic_cast<const StyleSheetPropertyMap*>( pEntry->pProperties.get() );
120 if ( !pStyleSheetProperties )
121 return;
122 sal_Int32 nListId = pStyleSheetProperties->GetListId();
123 if( xStyles.is() )
124 {
125 if( xStyles->hasByName( rname ) )
126 {
127 uno::Reference< style::XStyle > xStyle;
128 xStyles->getByName( rname ) >>= xStyle;
129 if( !xStyle.is() )
130 return;
131 uno::Reference<beans::XPropertySet> xPropertySet( xStyle, uno::UNO_QUERY );
132 xPropertySet->setPropertyValue( getPropertyName( PROP_PARA_LINE_NUMBER_COUNT ), uno::makeAny( nListId >= 0 ) );
133 }
134 }
135}
136
137// Populate Dropdown Field properties from FFData structure
138static void lcl_handleDropdownField( const uno::Reference< beans::XPropertySet >& rxFieldProps, const FFDataHandler::Pointer_t& pFFDataHandler )
139{
140 if ( !rxFieldProps.is() )
141 return;
142
143 if ( !pFFDataHandler->getName().isEmpty() )
144 rxFieldProps->setPropertyValue( "Name", uno::makeAny( pFFDataHandler->getName() ) );
145
146 const FFDataHandler::DropDownEntries_t& rEntries = pFFDataHandler->getDropDownEntries();
147 uno::Sequence< OUString > sItems( rEntries.size() );
148 ::std::copy( rEntries.begin(), rEntries.end(), sItems.begin());
149 if ( sItems.hasElements() )
150 rxFieldProps->setPropertyValue( "Items", uno::makeAny( sItems ) );
151
152 sal_Int32 nResult = pFFDataHandler->getDropDownResult().toInt32();
153 if ( nResult )
154 rxFieldProps->setPropertyValue( "SelectedItem", uno::makeAny( sItems[ nResult ] ) );
155 if ( !pFFDataHandler->getHelpText().isEmpty() )
156 rxFieldProps->setPropertyValue( "Help", uno::makeAny( pFFDataHandler->getHelpText() ) );
157}
158
159static void lcl_handleTextField( const uno::Reference< beans::XPropertySet >& rxFieldProps, const FFDataHandler::Pointer_t& pFFDataHandler )
160{
161 if ( rxFieldProps.is() && pFFDataHandler )
162 {
163 rxFieldProps->setPropertyValue
164 (getPropertyName(PROP_HINT),
165 uno::makeAny(pFFDataHandler->getStatusText()));
166 rxFieldProps->setPropertyValue
167 (getPropertyName(PROP_HELP),
168 uno::makeAny(pFFDataHandler->getHelpText()));
169 rxFieldProps->setPropertyValue
170 (getPropertyName(PROP_CONTENT),
171 uno::makeAny(pFFDataHandler->getTextDefault()));
172 }
173}
174
175namespace {
176
177struct FieldConversion
178{
179 const char* cFieldServiceName;
180 FieldId eFieldId;
181};
182
183}
184
185typedef std::unordered_map<OUString, FieldConversion> FieldConversionMap_t;
186
187/// Gives access to the parent field context of the topmost one, if there is any.
188static FieldContextPtr GetParentFieldContext(const std::deque<FieldContextPtr>& rFieldStack)
189{
190 if (rFieldStack.size() < 2)
191 {
192 return nullptr;
193 }
194
195 return rFieldStack[rFieldStack.size() - 2];
196}
197
198/// Decides if the pInner field inside pOuter is allowed in Writer core, depending on their type.
199static bool IsFieldNestingAllowed(const FieldContextPtr& pOuter, const FieldContextPtr& pInner)
200{
201 if (!pOuter->GetFieldId())
202 {
203 return true;
204 }
205
206 if (!pInner->GetFieldId())
207 {
208 return true;
209 }
210
211 switch (*pOuter->GetFieldId())
212 {
213 case FIELD_IF:
214 {
215 switch (*pInner->GetFieldId())
216 {
217 case FIELD_MERGEFIELD:
218 {
219 return false;
220 }
221 default:
222 break;
223 }
224 break;
225 }
226 default:
227 break;
228 }
229
230 return true;
231}
232
233uno::Any FloatingTableInfo::getPropertyValue(const OUString &propertyName)
234{
235 for( beans::PropertyValue const & propVal : std::as_const(m_aFrameProperties) )
236 if( propVal.Name == propertyName )
237 return propVal.Value ;
238 return uno::Any() ;
239}
240
241DomainMapper_Impl::DomainMapper_Impl(
242 DomainMapper& rDMapper,
243 uno::Reference<uno::XComponentContext> const& xContext,
244 uno::Reference<lang::XComponent> const& xModel,
245 SourceDocumentType eDocumentType,
246 utl::MediaDescriptor const & rMediaDesc) :
247 m_eDocumentType( eDocumentType ),
248 m_rDMapper( rDMapper ),
249 m_xTextDocument( xModel, uno::UNO_QUERY ),
250 m_xTextFactory( xModel, uno::UNO_QUERY ),
251 m_xComponentContext( xContext ),
252 m_bForceGenericFields(!utl::ConfigManager::IsFuzzing() && officecfg::Office::Common::Filter::Microsoft::Import::ForceImportWWFieldsAsGenericFields::get(m_xComponentContext)),
253 m_bSetUserFieldContent( false ),
254 m_bSetCitation( false ),
255 m_bSetDateValue( false ),
256 m_bIsFirstSection( true ),
257 m_bIsColumnBreakDeferred( false ),
258 m_bIsPageBreakDeferred( false ),
259 m_bSdtEndDeferred(false),
260 m_bParaSdtEndDeferred(false),
261 m_bStartTOC(false),
262 m_bStartTOCHeaderFooter(false),
263 m_bStartedTOC(false),
264 m_bStartIndex(false),
265 m_bStartBibliography(false),
266 m_nStartGenericField(0),
267 m_bTextInserted(false),
268 m_sCurrentPermId(0),
269 m_pLastSectionContext( ),
270 m_pLastCharacterContext(),
271 m_sCurrentParaStyleName(),
272 m_sDefaultParaStyleName(),
273 m_bInStyleSheetImport( false ),
274 m_bInAnyTableImport( false ),
275 m_eInHeaderFooterImport( HeaderFooterImportState::none ),
276 m_bDiscardHeaderFooter( false ),
277 m_bInFootOrEndnote(false),
278 m_bHasFootnoteStyle(false),
279 m_bCheckFootnoteStyle(false),
280 m_eSkipFootnoteState(SkipFootnoteSeparator::OFF),
281 m_bLineNumberingSet( false ),
282 m_bIsInFootnoteProperties( false ),
283 m_bIsParaMarkerChange( false ),
284 m_bParaChanged( false ),
285 m_bIsFirstParaInSection( true ),
286 m_bIsFirstParaInSectionAfterRedline( true ),
287 m_bDummyParaAddedForTableInSection( false ),
288 m_bTextFrameInserted(false),
289 m_bIsPreviousParagraphFramed( false ),
290 m_bIsLastParaInSection( false ),
291 m_bIsLastSectionGroup( false ),
292 m_bIsInComments( false ),
293 m_bParaSectpr( false ),
294 m_bUsingEnhancedFields( false ),
295 m_bSdt(false),
296 m_bIsFirstRun(false),
297 m_bIsOutsideAParagraph(true),
298 m_xAnnotationField(),
299 m_nAnnotationId( -1 ),
300 m_aAnnotationPositions(),
301 m_aSmartTagHandler(m_xComponentContext, m_xTextDocument),
302 m_xInsertTextRange(rMediaDesc.getUnpackedValueOrDefault("TextInsertModeRange", uno::Reference<text::XTextRange>())),
303 m_bIsNewDoc(!rMediaDesc.getUnpackedValueOrDefault("InsertMode", false)),
304 m_bIsReadGlossaries(rMediaDesc.getUnpackedValueOrDefault("ReadGlossaries", false)),
305 m_nTableDepth(0),
306 m_nTableCellDepth(0),
307 m_nLastTableCellParagraphDepth(0),
308 m_bHasFtn(false),
309 m_bHasFtnSep(false),
310 m_bCheckFirstFootnoteTab(false),
311 m_bIgnoreNextTab(false),
312 m_bIsSplitPara(false),
313 m_bIsActualParagraphFramed( false ),
314 m_vTextFramesForChaining(),
315 m_bParaHadField(false),
316 m_bSaveParaHadField(false),
317 m_bParaAutoBefore(false),
318 m_bFirstParagraphInCell(true),
319 m_bSaveFirstParagraphInCell(false),
320 m_bParaWithInlineObject(false)
321
322{
323 m_aBaseUrl = rMediaDesc.getUnpackedValueOrDefault(
324 utl::MediaDescriptor::PROP_DOCUMENTBASEURL(), OUString());
325 if (m_aBaseUrl.isEmpty()) {
326 m_aBaseUrl = rMediaDesc.getUnpackedValueOrDefault(
327 utl::MediaDescriptor::PROP_URL(), OUString());
328 }
329
330 appendTableManager( );
331 GetBodyText();
332 uno::Reference< text::XTextAppend > xBodyTextAppend( m_xBodyText, uno::UNO_QUERY );
333 m_aTextAppendStack.push(TextAppendContext(xBodyTextAppend,
334 m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : m_xBodyText->createTextCursorByRange(m_xInsertTextRange)));
335
336 //todo: does it makes sense to set the body text as static text interface?
337 uno::Reference< text::XTextAppendAndConvert > xBodyTextAppendAndConvert( m_xBodyText, uno::UNO_QUERY );
338 m_pTableHandler = new DomainMapperTableHandler(xBodyTextAppendAndConvert, *this);
339 getTableManager( ).setHandler(m_pTableHandler);
340
341 getTableManager( ).startLevel();
342 m_bUsingEnhancedFields = !utl::ConfigManager::IsFuzzing() && officecfg::Office::Common::Filter::Microsoft::Import::ImportWWFieldsAsEnhancedFields::get(m_xComponentContext);
343
344 m_pSdtHelper = new SdtHelper(*this);
345
346 m_aRedlines.push(std::vector<RedlineParamsPtr>());
347}
348
349
350DomainMapper_Impl::~DomainMapper_Impl()
351{
352 ChainTextFrames();
353 // Don't remove last paragraph when pasting, sw expects that empty paragraph.
354 if (m_bIsNewDoc)
355 RemoveLastParagraph();
356 if (hasTableManager())
357 {
358 getTableManager().endLevel();
359 popTableManager();
360 }
361}
362
363uno::Reference< container::XNameContainer > const & DomainMapper_Impl::GetPageStyles()
364{
365 if(!m_xPageStyles1.is())
366 {
367 uno::Reference< style::XStyleFamiliesSupplier > xSupplier( m_xTextDocument, uno::UNO_QUERY );
368 if (xSupplier.is())
369 xSupplier->getStyleFamilies()->getByName("PageStyles") >>= m_xPageStyles1;
370 }
371 return m_xPageStyles1;
372}
373
374OUString DomainMapper_Impl::GetUnusedPageStyleName()
375{
376 static const char DEFAULT_STYLE[] = "Converted";
377 if (!m_xNextUnusedPageStyleNo)
378 {
379 const uno::Sequence< OUString > aPageStyleNames = GetPageStyles()->getElementNames();
380 sal_Int32 nMaxIndex = 0;
381 // find the highest number x in each style with the name "DEFAULT_STYLE+x" and
382 // return an incremented name
383
384 for ( const auto& rStyleName : aPageStyleNames )
385 {
386 if ( rStyleName.startsWith( DEFAULT_STYLE ) )
387 {
388 sal_Int32 nIndex = rStyleName.copy( strlen( DEFAULT_STYLE ) ).toInt32();
389 if ( nIndex > nMaxIndex )
390 nMaxIndex = nIndex;
391 }
392 }
393 m_xNextUnusedPageStyleNo = nMaxIndex + 1;
394 }
395
396 OUString sPageStyleName = DEFAULT_STYLE + OUString::number( *m_xNextUnusedPageStyleNo );
397 *m_xNextUnusedPageStyleNo = *m_xNextUnusedPageStyleNo + 1;
398 return sPageStyleName;
399}
400
401uno::Reference< text::XText > const & DomainMapper_Impl::GetBodyText()
402{
403 if(!m_xBodyText.is())
404 {
405 if (m_xInsertTextRange.is())
406 m_xBodyText = m_xInsertTextRange->getText();
407 else if (m_xTextDocument.is())
408 m_xBodyText = m_xTextDocument->getText();
409 }
410 return m_xBodyText;
411}
412
413
414uno::Reference< beans::XPropertySet > const & DomainMapper_Impl::GetDocumentSettings()
415{
416 if( !m_xDocumentSettings.is() && m_xTextFactory.is())
417 {
418 m_xDocumentSettings.set( m_xTextFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY );
419 }
420 return m_xDocumentSettings;
421}
422
423
424void DomainMapper_Impl::SetDocumentSettingsProperty( const OUString& rPropName, const uno::Any& rValue )
425{
426 uno::Reference< beans::XPropertySet > xSettings = GetDocumentSettings();
427 if( xSettings.is() )
428 {
429 try
430 {
431 xSettings->setPropertyValue( rPropName, rValue );
432 }
433 catch( const uno::Exception& )
434 {
435 }
436 }
437}
438void DomainMapper_Impl::RemoveDummyParaForTableInSection()
439{
440 SetIsDummyParaAddedForTableInSection(false);
441 PropertyMapPtr pContext = GetTopContextOfType(CONTEXT_SECTION);
442 SectionPropertyMap* pSectionContext = dynamic_cast< SectionPropertyMap* >( pContext.get() );
443 if (!pSectionContext)
444 return;
445
446 if (m_aTextAppendStack.empty())
447 return;
448 uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
449 if (!xTextAppend.is())
450 return;
451
452 uno::Reference< text::XTextCursor > xCursor = xTextAppend->createTextCursorByRange(pSectionContext->GetStartingRange());
453
454 // Remove the extra NumPicBullets from the document,
455 // which get attached to the first paragraph in the
456 // document
457 ListsManager::Pointer pListTable = GetListTable();
458 pListTable->DisposeNumPicBullets();
459
460 uno::Reference<container::XEnumerationAccess> xEnumerationAccess(xCursor, uno::UNO_QUERY);
461 if (xEnumerationAccess.is() && m_aTextAppendStack.size() == 1 )
462 {
463 uno::Reference<container::XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
464 uno::Reference<lang::XComponent> xParagraph(xEnumeration->nextElement(), uno::UNO_QUERY);
465 xParagraph->dispose();
466 }
467}
468void DomainMapper_Impl::AddDummyParaForTableInSection()
469{
470 // Shapes can't have sections.
471 if (IsInShape())
472 return;
473
474 if (!m_aTextAppendStack.empty())
475 {
476 uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
477 if (xTextAppend.is())
478 {
479 xTextAppend->finishParagraph( uno::Sequence< beans::PropertyValue >() );
480 SetIsDummyParaAddedForTableInSection(true);
481 }
482 }
483}
484
485void DomainMapper_Impl::RemoveLastParagraph( )
486{
487 if (m_bDiscardHeaderFooter)
488 return;
489
490 if (m_aTextAppendStack.empty())
491 return;
492 uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
493 if (!xTextAppend.is())
494 return;
495 try
496 {
497 uno::Reference< text::XTextCursor > xCursor;
498 if (m_bIsNewDoc)
499 {
500 xCursor = xTextAppend->createTextCursor();
501 xCursor->gotoEnd(false);
502 }
503 else
504 xCursor = m_aTextAppendStack.top().xCursor;
505 uno::Reference<container::XEnumerationAccess> xEnumerationAccess(xCursor, uno::UNO_QUERY);
506 // Keep the character properties of the last but one paragraph, even if
507 // it's empty. This works for headers/footers, and maybe in other cases
508 // as well, but surely not in textboxes.
509 // fdo#58327: also do this at the end of the document: when pasting,
510 // a table before the cursor position would be deleted
511 // (but only for paste/insert, not load; otherwise it can happen that
512 // flys anchored at the disposed paragraph are deleted (fdo47036.rtf))
513 bool const bEndOfDocument(m_aTextAppendStack.size() == 1);
514 if ((IsInHeaderFooter() || (bEndOfDocument && !m_bIsNewDoc))
515 && xEnumerationAccess.is())
516 {
517 uno::Reference<container::XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
518 uno::Reference<lang::XComponent> xParagraph(xEnumeration->nextElement(), uno::UNO_QUERY);
519 xParagraph->dispose();
520 }
521 else if (xCursor.is())
522 {
523 xCursor->goLeft( 1, true );
524 // If this is a text on a shape, possibly the text has the trailing
525 // newline removed already.
526 if (xCursor->getString() == SAL_NEWLINE_STRING"\n" ||
527 // tdf#105444 comments need an exception, if SAL_NEWLINE_STRING defined as "\r\n"
528 (sizeof(SAL_NEWLINE_STRING"\n")-1 == 2 && xCursor->getString() == "\n"))
529 {
530 uno::Reference<beans::XPropertySet> xDocProps(GetTextDocument(), uno::UNO_QUERY);
531 const OUString aRecordChanges("RecordChanges");
532 uno::Any aPreviousValue(xDocProps->getPropertyValue(aRecordChanges));
533
534 // disable redlining for this operation, otherwise we might
535 // end up with an unwanted recorded deletion
536 xDocProps->setPropertyValue(aRecordChanges, uno::Any(false));
537
538 // delete
539 xCursor->setString(OUString());
540
541 // restore again
542 xDocProps->setPropertyValue(aRecordChanges, aPreviousValue);
543 }
544 }
545 }
546 catch( const uno::Exception& )
547 {
548 }
549}
550
551
552void DomainMapper_Impl::SetIsLastSectionGroup( bool bIsLast )
553{
554 m_bIsLastSectionGroup = bIsLast;
555}
556
557void DomainMapper_Impl::SetIsLastParagraphInSection( bool bIsLast )
558{
559 m_bIsLastParaInSection = bIsLast;
560}
561
562
563void DomainMapper_Impl::SetIsFirstParagraphInSection( bool bIsFirst )
564{
565 m_bIsFirstParaInSection = bIsFirst;
566}
567
568void DomainMapper_Impl::SetIsFirstParagraphInSectionAfterRedline( bool bIsFirstAfterRedline )
569{
570 m_bIsFirstParaInSectionAfterRedline = bIsFirstAfterRedline;
571}
572
573bool DomainMapper_Impl::GetIsFirstParagraphInSection( bool bAfterRedline ) const
574{
575 // Anchored objects may include multiple paragraphs,
576 // and none of them should be considered the first para in section.
577 return ( bAfterRedline ? m_bIsFirstParaInSectionAfterRedline : m_bIsFirstParaInSection )
578 && !IsInShape()
579 && !m_bIsInComments
580 && !IsInFootOrEndnote();
581}
582
583void DomainMapper_Impl::SetIsFirstParagraphInShape(bool bIsFirst)
584{
585 m_bIsFirstParaInShape = bIsFirst;
586}
587
588void DomainMapper_Impl::SetIsDummyParaAddedForTableInSection( bool bIsAdded )
589{
590 m_bDummyParaAddedForTableInSection = bIsAdded;
591}
592
593
594void DomainMapper_Impl::SetIsTextFrameInserted( bool bIsInserted )
595{
596 m_bTextFrameInserted = bIsInserted;
597}
598
599
600void DomainMapper_Impl::SetParaSectpr(bool bParaSectpr)
601{
602 m_bParaSectpr = bParaSectpr;
603}
604
605
606void DomainMapper_Impl::SetSdt(bool bSdt)
607{
608 m_bSdt = bSdt;
609
610 if (m_bSdt && !m_aTextAppendStack.empty())
611 {
612 m_xSdtEntryStart = GetTopTextAppend()->getEnd();
613 }
614 else
615 {
616 m_xSdtEntryStart.clear();
617 }
618}
619
620
621void DomainMapper_Impl::PushProperties(ContextType eId)
622{
623 PropertyMapPtr pInsert(eId == CONTEXT_SECTION ?
624 (new SectionPropertyMap( m_bIsFirstSection )) :
625 eId == CONTEXT_PARAGRAPH ? new ParagraphPropertyMap : new PropertyMap);
626 if(eId == CONTEXT_SECTION)
627 {
628 if( m_bIsFirstSection )
629 m_bIsFirstSection = false;
630 // beginning with the second section group a section has to be inserted
631 // into the document
632 SectionPropertyMap* pSectionContext_ = dynamic_cast< SectionPropertyMap* >( pInsert.get() );
633 if (!m_aTextAppendStack.empty())
634 {
635 uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
636 if (xTextAppend.is() && pSectionContext_)
637 pSectionContext_->SetStart( xTextAppend->getEnd() );
638 }
639 }
640 if(eId == CONTEXT_PARAGRAPH && m_bIsSplitPara)
641 {
642 m_aPropertyStacks[eId].push( GetTopContextOfType(eId));
643 m_bIsSplitPara = false;
644 }
645 else
646 {
647 m_aPropertyStacks[eId].push( pInsert );
648 }
649 m_aContextStack.push(eId);
650
651 m_pTopContext = m_aPropertyStacks[eId].top();
652}
653
654
655void DomainMapper_Impl::PushStyleProperties( const PropertyMapPtr& pStyleProperties )
656{
657 m_aPropertyStacks[CONTEXT_STYLESHEET].push( pStyleProperties );
658 m_aContextStack.push(CONTEXT_STYLESHEET);
659
660 m_pTopContext = m_aPropertyStacks[CONTEXT_STYLESHEET].top();
661}
662
663
664void DomainMapper_Impl::PushListProperties(const PropertyMapPtr& pListProperties)
665{
666 m_aPropertyStacks[CONTEXT_LIST].push( pListProperties );
667 m_aContextStack.push(CONTEXT_LIST);
668 m_pTopContext = m_aPropertyStacks[CONTEXT_LIST].top();
669}
670
671
672void DomainMapper_Impl::PopProperties(ContextType eId)
673{
674 OSL_ENSURE(!m_aPropertyStacks[eId].empty(), "section stack already empty")do { if (true && (!(!m_aPropertyStacks[eId].empty()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "674" ": "), "%s", "section stack already empty"); } } while
(false)
;
675 if ( m_aPropertyStacks[eId].empty() )
676 return;
677
678 if ( eId == CONTEXT_SECTION )
679 {
680 if (m_aPropertyStacks[eId].size() == 1) // tdf#112202 only top level !!!
681 {
682 m_pLastSectionContext = m_aPropertyStacks[eId].top();
683 }
684 }
685 else if (eId == CONTEXT_CHARACTER)
686 {
687 m_pLastCharacterContext = m_aPropertyStacks[eId].top();
688 // Sadly an assert about deferredCharacterProperties being empty is not possible
689 // here, because appendTextPortion() may not be called for every character section.
690 deferredCharacterProperties.clear();
691 }
692
693 if (!IsInFootOrEndnote() && IsInCustomFootnote() && !m_aPropertyStacks[eId].empty())
694 {
695 PropertyMapPtr pRet = m_aPropertyStacks[eId].top();
696 if (pRet->GetFootnote().is() && m_pFootnoteContext.is())
697 EndCustomFootnote();
698 }
699
700 m_aPropertyStacks[eId].pop();
701 m_aContextStack.pop();
702 if(!m_aContextStack.empty() && !m_aPropertyStacks[m_aContextStack.top()].empty())
703
704 m_pTopContext = m_aPropertyStacks[m_aContextStack.top()].top();
705 else
706 {
707 // OSL_ENSURE(eId == CONTEXT_SECTION, "this should happen at a section context end");
708 m_pTopContext.clear();
709 }
710}
711
712
713PropertyMapPtr DomainMapper_Impl::GetTopContextOfType(ContextType eId)
714{
715 PropertyMapPtr pRet;
716 if(!m_aPropertyStacks[eId].empty())
717 pRet = m_aPropertyStacks[eId].top();
718 return pRet;
719}
720
721bool DomainMapper_Impl::HasTopText() const
722{
723 return !m_aTextAppendStack.empty();
724}
725
726uno::Reference< text::XTextAppend > const & DomainMapper_Impl::GetTopTextAppend()
727{
728 OSL_ENSURE(!m_aTextAppendStack.empty(), "text append stack is empty" )do { if (true && (!(!m_aTextAppendStack.empty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "728" ": "), "%s", "text append stack is empty"); } } while
(false)
;
729 return m_aTextAppendStack.top().xTextAppend;
730}
731
732FieldContextPtr const & DomainMapper_Impl::GetTopFieldContext()
733{
734 SAL_WARN_IF(m_aFieldStack.empty(), "writerfilter.dmapper", "Field stack is empty")do { if (true && (m_aFieldStack.empty())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "writerfilter.dmapper")) { case
SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Field stack is empty") == 1) { ::sal_detail_log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "734" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Field stack is empty"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"Field stack is empty"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "734" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Field stack is empty") == 1) { ::sal_detail_log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "734" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Field stack is empty"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"Field stack is empty"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "734" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
735 return m_aFieldStack.back();
736}
737
738bool DomainMapper_Impl::HasTopAnchoredObjects() const
739{
740 return !m_aTextAppendStack.empty() && !m_aTextAppendStack.top().m_aAnchoredObjects.empty();
741}
742
743void DomainMapper_Impl::InitTabStopFromStyle( const uno::Sequence< style::TabStop >& rInitTabStops )
744{
745 OSL_ENSURE(m_aCurrentTabStops.empty(), "tab stops already initialized")do { if (true && (!(m_aCurrentTabStops.empty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "745" ": "), "%s", "tab stops already initialized"); } }
while (false)
;
746 for( const auto& rTabStop : rInitTabStops)
747 {
748 m_aCurrentTabStops.emplace_back(rTabStop);
749 }
750}
751
752void DomainMapper_Impl::IncorporateTabStop( const DeletableTabStop & rTabStop )
753{
754 sal_Int32 nConverted = rTabStop.Position;
755 auto aIt = std::find_if(m_aCurrentTabStops.begin(), m_aCurrentTabStops.end(),
756 [&nConverted](const DeletableTabStop& rCurrentTabStop) { return rCurrentTabStop.Position == nConverted; });
757 if( aIt != m_aCurrentTabStops.end() )
758 {
759 if( rTabStop.bDeleted )
760 m_aCurrentTabStops.erase( aIt );
761 else
762 *aIt = rTabStop;
763 }
764 else
765 m_aCurrentTabStops.push_back( rTabStop );
766}
767
768
769uno::Sequence< style::TabStop > DomainMapper_Impl::GetCurrentTabStopAndClear()
770{
771 std::vector<style::TabStop> aRet;
772 for (const DeletableTabStop& rStop : m_aCurrentTabStops)
773 {
774 if (!rStop.bDeleted)
775 aRet.push_back(rStop);
776 }
777 m_aCurrentTabStops.clear();
778 return comphelper::containerToSequence(aRet);
779}
780
781OUString DomainMapper_Impl::GetCurrentParaStyleName()
782{
783 OUString sName;
784 // use saved currParaStyleName as a fallback, in case no particular para style name applied.
785 // tdf#134784 except in the case of first paragraph of shapes to avoid bad fallback.
786 // TODO fix this "highly inaccurate" m_sCurrentParaStyleName
787 if ( !m_bIsFirstParaInShape )
788 sName = m_sCurrentParaStyleName;
789
790 PropertyMapPtr pParaContext = GetTopContextOfType(CONTEXT_PARAGRAPH);
791 if ( pParaContext && pParaContext->isSet(PROP_PARA_STYLE_NAME) )
792 pParaContext->getProperty(PROP_PARA_STYLE_NAME)->second >>= sName;
793
794 // In rare situations the name might still be blank, so use the default style,
795 // despite documentation that states, "If this attribute is not specified for any style,
796 // then no properties shall be applied to objects of the specified type."
797 // Word, however, assigns "Normal" style even in these situations.
798 if ( !m_bInStyleSheetImport && sName.isEmpty() )
799 sName = GetDefaultParaStyleName();
800
801 return sName;
802}
803
804OUString DomainMapper_Impl::GetDefaultParaStyleName()
805{
806 // After import the default style won't change and is frequently requested: cache the LO style name.
807 // TODO assert !InStyleSheetImport? This function really only makes sense once import is finished anyway.
808 if ( m_sDefaultParaStyleName.isEmpty() )
809 {
810 const StyleSheetEntryPtr pEntry = GetStyleSheetTable()->FindDefaultParaStyle();
811 if ( pEntry && !pEntry->sConvertedStyleName.isEmpty() )
812 {
813 if ( !m_bInStyleSheetImport )
814 m_sDefaultParaStyleName = pEntry->sConvertedStyleName;
815 return pEntry->sConvertedStyleName;
816 }
817 else
818 return "Standard";
819 }
820 return m_sDefaultParaStyleName;
821}
822
823uno::Any DomainMapper_Impl::GetPropertyFromStyleSheet(PropertyIds eId, StyleSheetEntryPtr pEntry, const bool bDocDefaults, const bool bPara, bool* pIsDocDefault)
824{
825 while(pEntry)
826 {
827 if(pEntry->pProperties)
828 {
829 std::optional<PropertyMap::Property> aProperty =
830 pEntry->pProperties->getProperty(eId);
831 if( aProperty )
832 {
833 if (pIsDocDefault)
834 *pIsDocDefault = pEntry->pProperties->isDocDefault(eId);
835
836 return aProperty->second;
837 }
838 }
839 //search until the property is set or no parent is available
840 StyleSheetEntryPtr pNewEntry;
841 if ( !pEntry->sBaseStyleIdentifier.isEmpty() )
842 pNewEntry = GetStyleSheetTable()->FindStyleSheetByISTD(pEntry->sBaseStyleIdentifier);
843
844 SAL_WARN_IF( pEntry == pNewEntry, "writerfilter.dmapper", "circular loop in style hierarchy?")do { if (true && (pEntry == pNewEntry)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "writerfilter.dmapper")) { case
SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "circular loop in style hierarchy?") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "844" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "circular loop in style hierarchy?"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "circular loop in style hierarchy?"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"),
("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "844" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "circular loop in style hierarchy?") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "844" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "circular loop in style hierarchy?"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "circular loop in style hierarchy?"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"),
("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "844" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
845
846 if (pEntry == pNewEntry) //fdo#49587
847 break;
848
849 pEntry = pNewEntry;
850 }
851 // not found in style, try the document's DocDefault properties
852 if ( bDocDefaults && bPara )
853 {
854 const PropertyMapPtr& pDefaultParaProps = GetStyleSheetTable()->GetDefaultParaProps();
855 if ( pDefaultParaProps )
856 {
857 std::optional<PropertyMap::Property> aProperty = pDefaultParaProps->getProperty(eId);
858 if ( aProperty )
859 {
860 if (pIsDocDefault)
861 *pIsDocDefault = true;
862
863 return aProperty->second;
864 }
865 }
866 }
867 if ( bDocDefaults && isCharacterProperty(eId) )
868 {
869 const PropertyMapPtr& pDefaultCharProps = GetStyleSheetTable()->GetDefaultCharProps();
870 if ( pDefaultCharProps )
871 {
872 std::optional<PropertyMap::Property> aProperty = pDefaultCharProps->getProperty(eId);
873 if ( aProperty )
874 {
875 if (pIsDocDefault)
876 *pIsDocDefault = true;
877
878 return aProperty->second;
879 }
880 }
881 }
882
883 if (pIsDocDefault)
884 *pIsDocDefault = false;
885
886 return uno::Any();
887}
888
889uno::Any DomainMapper_Impl::GetPropertyFromParaStyleSheet(PropertyIds eId)
890{
891 StyleSheetEntryPtr pEntry;
892 if ( m_bInStyleSheetImport )
893 pEntry = GetStyleSheetTable()->GetCurrentEntry();
894 else
895 pEntry = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(GetCurrentParaStyleName());
896 return GetPropertyFromStyleSheet(eId, pEntry, /*bDocDefaults=*/true, /*bPara=*/true);
897}
898
899uno::Any DomainMapper_Impl::GetPropertyFromCharStyleSheet(PropertyIds eId, const PropertyMapPtr& rContext)
900{
901 if ( m_bInStyleSheetImport || eId == PROP_CHAR_STYLE_NAME || !isCharacterProperty(eId) )
902 return uno::Any();
903
904 StyleSheetEntryPtr pEntry;
905 OUString sCharStyleName;
906 if ( GetAnyProperty(PROP_CHAR_STYLE_NAME, rContext) >>= sCharStyleName )
907 pEntry = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(sCharStyleName);
908 return GetPropertyFromStyleSheet(eId, pEntry, /*bDocDefaults=*/false, /*bPara=*/false);
909}
910
911uno::Any DomainMapper_Impl::GetAnyProperty(PropertyIds eId, const PropertyMapPtr& rContext)
912{
913 // first look in directly applied attributes
914 if ( rContext )
915 {
916 std::optional<PropertyMap::Property> aProperty = rContext->getProperty(eId);
917 if ( aProperty )
918 return aProperty->second;
919 }
920
921 // then look whether it was inherited from a directly applied character style
922 if ( eId != PROP_CHAR_STYLE_NAME && isCharacterProperty(eId) )
923 {
924 uno::Any aRet = GetPropertyFromCharStyleSheet(eId, rContext);
925 if ( aRet.hasValue() )
926 return aRet;
927 }
928
929 // then look in current paragraph style, and docDefaults
930 return GetPropertyFromParaStyleSheet(eId);
931}
932
933OUString DomainMapper_Impl::GetListStyleName(sal_Int32 nListId)
934{
935 auto const pList(GetListTable()->GetList( nListId ));
936 return pList ? pList->GetStyleName() : OUString();
937}
938
939ListsManager::Pointer const & DomainMapper_Impl::GetListTable()
940{
941 if(!m_pListTable)
942 m_pListTable =
943 new ListsManager( m_rDMapper, m_xTextFactory );
944 return m_pListTable;
945}
946
947
948void DomainMapper_Impl::deferBreak( BreakType deferredBreakType)
949{
950 switch (deferredBreakType)
951 {
952 case COLUMN_BREAK:
953 m_bIsColumnBreakDeferred = true;
954 break;
955 case PAGE_BREAK:
956 // See SwWW8ImplReader::HandlePageBreakChar(), page break should be
957 // ignored inside tables.
958 if (m_nTableDepth > 0)
959 return;
960
961 m_bIsPageBreakDeferred = true;
962 break;
963 default:
964 return;
965 }
966}
967
968bool DomainMapper_Impl::isBreakDeferred( BreakType deferredBreakType )
969{
970 switch (deferredBreakType)
971 {
972 case COLUMN_BREAK:
973 return m_bIsColumnBreakDeferred;
974 case PAGE_BREAK:
975 return m_bIsPageBreakDeferred;
976 default:
977 return false;
978 }
979}
980
981void DomainMapper_Impl::clearDeferredBreak(BreakType deferredBreakType)
982{
983 switch (deferredBreakType)
984 {
985 case COLUMN_BREAK:
986 m_bIsColumnBreakDeferred = false;
987 break;
988 case PAGE_BREAK:
989 m_bIsPageBreakDeferred = false;
990 break;
991 default:
992 break;
993 }
994}
995
996void DomainMapper_Impl::clearDeferredBreaks()
997{
998 m_bIsColumnBreakDeferred = false;
999 m_bIsPageBreakDeferred = false;
1000}
1001
1002void DomainMapper_Impl::setSdtEndDeferred(bool bSdtEndDeferred)
1003{
1004 m_bSdtEndDeferred = bSdtEndDeferred;
1005}
1006
1007bool DomainMapper_Impl::isSdtEndDeferred() const
1008{
1009 return m_bSdtEndDeferred;
1010}
1011
1012void DomainMapper_Impl::setParaSdtEndDeferred(bool bParaSdtEndDeferred)
1013{
1014 m_bParaSdtEndDeferred = bParaSdtEndDeferred;
1015}
1016
1017bool DomainMapper_Impl::isParaSdtEndDeferred() const
1018{
1019 return m_bParaSdtEndDeferred;
1020}
1021
1022static void lcl_MoveBorderPropertiesToFrame(std::vector<beans::PropertyValue>& rFrameProperties,
1023 uno::Reference<text::XTextRange> const& xStartTextRange,
1024 uno::Reference<text::XTextRange> const& xEndTextRange )
1025{
1026 try
1027 {
1028 if (!xStartTextRange.is()) //rhbz#1077780
1029 return;
1030 uno::Reference<text::XTextCursor> xRangeCursor = xStartTextRange->getText()->createTextCursorByRange( xStartTextRange );
1031 xRangeCursor->gotoRange( xEndTextRange, true );
1032
1033 uno::Reference<beans::XPropertySet> xTextRangeProperties(xRangeCursor, uno::UNO_QUERY);
1034 if(!xTextRangeProperties.is())
1035 return ;
1036
1037 static PropertyIds const aBorderProperties[] =
1038 {
1039 PROP_LEFT_BORDER,
1040 PROP_RIGHT_BORDER,
1041 PROP_TOP_BORDER,
1042 PROP_BOTTOM_BORDER,
1043 PROP_LEFT_BORDER_DISTANCE,
1044 PROP_RIGHT_BORDER_DISTANCE,
1045 PROP_TOP_BORDER_DISTANCE,
1046 PROP_BOTTOM_BORDER_DISTANCE
1047 };
1048
1049 for( size_t nProperty = 0; nProperty < SAL_N_ELEMENTS( aBorderProperties )(sizeof(sal_n_array_size(aBorderProperties))); ++nProperty)
1050 {
1051 OUString sPropertyName = getPropertyName(aBorderProperties[nProperty]);
1052 beans::PropertyValue aValue;
1053 aValue.Name = sPropertyName;
1054 aValue.Value = xTextRangeProperties->getPropertyValue(sPropertyName);
1055 rFrameProperties.push_back(aValue);
1056 if( nProperty < 4 )
1057 xTextRangeProperties->setPropertyValue( sPropertyName, uno::makeAny(table::BorderLine2()));
1058 }
1059 }
1060 catch( const uno::Exception& )
1061 {
1062 }
1063}
1064
1065
1066static void lcl_AddRangeAndStyle(
1067 ParagraphPropertiesPtr const & pToBeSavedProperties,
1068 uno::Reference< text::XTextAppend > const& xTextAppend,
1069 const PropertyMapPtr& pPropertyMap,
1070 TextAppendContext const & rAppendContext)
1071{
1072 uno::Reference<text::XParagraphCursor> xParaCursor(
1073 xTextAppend->createTextCursorByRange( rAppendContext.xInsertPosition.is() ? rAppendContext.xInsertPosition : xTextAppend->getEnd()), uno::UNO_QUERY_THROW );
1074 pToBeSavedProperties->SetEndingRange(xParaCursor->getStart());
1075 xParaCursor->gotoStartOfParagraph( false );
1076
1077 pToBeSavedProperties->SetStartingRange(xParaCursor->getStart());
1078 if(pPropertyMap)
1079 {
1080 std::optional<PropertyMap::Property> aParaStyle = pPropertyMap->getProperty(PROP_PARA_STYLE_NAME);
1081 if( aParaStyle )
1082 {
1083 OUString sName;
1084 aParaStyle->second >>= sName;
1085 pToBeSavedProperties->SetParaStyleName(sName);
1086 }
1087 }
1088}
1089
1090
1091//define some default frame width - 0cm ATM: this allow the frame to be wrapped around the text
1092constexpr sal_Int32 DEFAULT_FRAME_MIN_WIDTH = 0;
1093constexpr sal_Int32 DEFAULT_FRAME_MIN_HEIGHT = 0;
1094constexpr sal_Int32 DEFAULT_VALUE = 0;
1095
1096void DomainMapper_Impl::CheckUnregisteredFrameConversion( )
1097{
1098 if (m_aTextAppendStack.empty())
1099 return;
1100 TextAppendContext& rAppendContext = m_aTextAppendStack.top();
1101 // n#779642: ignore fly frame inside table as it could lead to messy situations
1102 if (!rAppendContext.pLastParagraphProperties)
1103 return;
1104 if (!rAppendContext.pLastParagraphProperties->IsFrameMode())
1105 return;
1106 if (!hasTableManager())
1107 return;
1108 if (getTableManager().isInTable())
1109 return;
1110 try
1111 {
1112 StyleSheetEntryPtr pParaStyle =
1113 GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(rAppendContext.pLastParagraphProperties->GetParaStyleName());
1114
1115 std::vector<beans::PropertyValue> aFrameProperties;
1116
1117 if ( pParaStyle )
1118 {
1119 const ParagraphProperties* pStyleProperties = dynamic_cast<const ParagraphProperties*>( pParaStyle->pProperties.get() );
1120 if (!pStyleProperties)
1121 return;
1122 sal_Int32 nWidth =
1123 rAppendContext.pLastParagraphProperties->Getw() > 0 ?
1124 rAppendContext.pLastParagraphProperties->Getw() :
1125 pStyleProperties->Getw();
1126 bool bAutoWidth = nWidth < 1;
1127 if( bAutoWidth )
1128 nWidth = DEFAULT_FRAME_MIN_WIDTH;
1129 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_WIDTH), nWidth));
1130
1131 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HEIGHT),
1132 rAppendContext.pLastParagraphProperties->Geth() > 0 ?
1133 rAppendContext.pLastParagraphProperties->Geth() :
1134 pStyleProperties->Geth() > 0 ? pStyleProperties->Geth() : DEFAULT_FRAME_MIN_HEIGHT));
1135
1136 sal_Int16 nhRule = sal_Int16(
1137 rAppendContext.pLastParagraphProperties->GethRule() >= 0 ?
1138 rAppendContext.pLastParagraphProperties->GethRule() :
1139 pStyleProperties->GethRule());
1140 if ( nhRule < 0 )
1141 {
1142 if ( rAppendContext.pLastParagraphProperties->Geth() >= 0 ||
1143 pStyleProperties->GethRule() >= 0 )
1144 {
1145 // [MS-OE376] Word uses a default value of "atLeast" for
1146 // this attribute when the value of the h attribute is not 0.
1147 nhRule = text::SizeType::MIN;
1148 }
1149 else
1150 {
1151 nhRule = text::SizeType::VARIABLE;
1152 }
1153 }
1154 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_SIZE_TYPE), nhRule));
1155
1156 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_WIDTH_TYPE), bAutoWidth ? text::SizeType::MIN : text::SizeType::FIX));
1157
1158 if (const std::optional<sal_Int16> nDirection = PopFrameDirection())
1159 {
1160 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_FRM_DIRECTION), *nDirection));
1161 }
1162
1163 sal_Int16 nHoriOrient = sal_Int16(
1164 rAppendContext.pLastParagraphProperties->GetxAlign() >= 0 ?
1165 rAppendContext.pLastParagraphProperties->GetxAlign() :
1166 pStyleProperties->GetxAlign() >= 0 ? pStyleProperties->GetxAlign() : text::HoriOrientation::NONE );
1167 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT), nHoriOrient));
1168
1169 //set a non negative default value
1170 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT_POSITION),
1171 rAppendContext.pLastParagraphProperties->IsxValid() ?
1172 rAppendContext.pLastParagraphProperties->Getx() :
1173 pStyleProperties->IsxValid() ? pStyleProperties->Getx() : DEFAULT_VALUE));
1174
1175 //Default the anchor in case FramePr_hAnchor is missing ECMA 17.3.1.11
1176 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT_RELATION), sal_Int16(
1177 rAppendContext.pLastParagraphProperties->GethAnchor() >= 0 ?
1178 rAppendContext.pLastParagraphProperties->GethAnchor() :
1179 pStyleProperties->GethAnchor() >=0 ? pStyleProperties->GethAnchor() : text::RelOrientation::FRAME )));
1180
1181 sal_Int16 nVertOrient = sal_Int16(
1182 rAppendContext.pLastParagraphProperties->GetyAlign() >= 0 ?
1183 rAppendContext.pLastParagraphProperties->GetyAlign() :
1184 pStyleProperties->GetyAlign() >= 0 ? pStyleProperties->GetyAlign() : text::VertOrientation::NONE );
1185 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT), nVertOrient));
1186
1187 //set a non negative default value
1188 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT_POSITION),
1189 rAppendContext.pLastParagraphProperties->IsyValid() ?
1190 rAppendContext.pLastParagraphProperties->Gety() :
1191 pStyleProperties->IsyValid() ? pStyleProperties->Gety() : DEFAULT_VALUE));
1192
1193 //Default the anchor in case FramePr_vAnchor is missing ECMA 17.3.1.11
1194 if (rAppendContext.pLastParagraphProperties->GetWrap() == text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE &&
1195 pStyleProperties->GetWrap() == text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE)
1196 {
1197 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT_RELATION), sal_Int16(
1198 rAppendContext.pLastParagraphProperties->GetvAnchor() >= 0 ?
1199 rAppendContext.pLastParagraphProperties->GetvAnchor() :
1200 pStyleProperties->GetvAnchor() >= 0 ? pStyleProperties->GetvAnchor() : text::RelOrientation::FRAME)));
1201 }
1202 else
1203 {
1204 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT_RELATION), sal_Int16(
1205 rAppendContext.pLastParagraphProperties->GetvAnchor() >= 0 ?
1206 rAppendContext.pLastParagraphProperties->GetvAnchor() :
1207 pStyleProperties->GetvAnchor() >= 0 ? pStyleProperties->GetvAnchor() : text::RelOrientation::PAGE_PRINT_AREA)));
1208 }
1209
1210 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_SURROUND),
1211 rAppendContext.pLastParagraphProperties->GetWrap() != text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE
1212 ? rAppendContext.pLastParagraphProperties->GetWrap()
1213 : pStyleProperties->GetWrap() != text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE
1214 ? pStyleProperties->GetWrap()
1215 : text::WrapTextMode_NONE ));
1216
1217 /** FDO#73546 : distL & distR should be unsigned integers <Ecma 20.4.3.6>
1218 Swapped the array elements 11,12 & 13,14 since 11 & 12 are
1219 LEFT & RIGHT margins and 13,14 are TOP and BOTTOM margins respectively.
1220 */
1221 sal_Int32 nRightDist;
1222 sal_Int32 nLeftDist = nRightDist =
1223 rAppendContext.pLastParagraphProperties->GethSpace() >= 0 ?
1224 rAppendContext.pLastParagraphProperties->GethSpace() :
1225 pStyleProperties->GethSpace() >= 0 ? pStyleProperties->GethSpace() : 0;
1226
1227 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_LEFT_MARGIN), nHoriOrient == text::HoriOrientation::LEFT ? 0 : nLeftDist));
1228 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_RIGHT_MARGIN), nHoriOrient == text::HoriOrientation::RIGHT ? 0 : nRightDist));
1229
1230 sal_Int32 nBottomDist;
1231 sal_Int32 nTopDist = nBottomDist =
1232 rAppendContext.pLastParagraphProperties->GetvSpace() >= 0 ?
1233 rAppendContext.pLastParagraphProperties->GetvSpace() :
1234 pStyleProperties->GetvSpace() >= 0 ? pStyleProperties->GetvSpace() : 0;
1235
1236 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_TOP_MARGIN), nVertOrient == text::VertOrientation::TOP ? 0 : nTopDist));
1237 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_BOTTOM_MARGIN), nVertOrient == text::VertOrientation::BOTTOM ? 0 : nBottomDist));
1238 // If there is no fill, the Word default is 100% transparency.
1239 // Otherwise CellColorHandler has priority, and this setting
1240 // will be ignored.
1241 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_BACK_COLOR_TRANSPARENCY), sal_Int32(100)));
1242
1243 uno::Sequence<beans::PropertyValue> aGrabBag( comphelper::InitPropertySequence({
1244 { "ParaFrameProperties", uno::Any(rAppendContext.pLastParagraphProperties->IsFrameMode()) }
1245 }));
1246 aFrameProperties.push_back(comphelper::makePropertyValue("FrameInteropGrabBag", aGrabBag));
1247
1248 lcl_MoveBorderPropertiesToFrame(aFrameProperties,
1249 rAppendContext.pLastParagraphProperties->GetStartingRange(),
1250 rAppendContext.pLastParagraphProperties->GetEndingRange());
1251 }
1252 else
1253 {
1254 sal_Int32 nWidth = rAppendContext.pLastParagraphProperties->Getw();
1255 bool bAutoWidth = nWidth < 1;
1256 if( bAutoWidth )
1257 nWidth = DEFAULT_FRAME_MIN_WIDTH;
1258 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_WIDTH), nWidth));
1259
1260 sal_Int16 nhRule = sal_Int16(rAppendContext.pLastParagraphProperties->GethRule());
1261 if ( nhRule < 0 )
1262 {
1263 if ( rAppendContext.pLastParagraphProperties->Geth() >= 0 )
1264 {
1265 // [MS-OE376] Word uses a default value of atLeast for
1266 // this attribute when the value of the h attribute is not 0.
1267 nhRule = text::SizeType::MIN;
1268 }
1269 else
1270 {
1271 nhRule = text::SizeType::VARIABLE;
1272 }
1273 }
1274 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_SIZE_TYPE), nhRule));
1275
1276 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_WIDTH_TYPE), bAutoWidth ? text::SizeType::MIN : text::SizeType::FIX));
1277
1278 sal_Int16 nHoriOrient = sal_Int16(
1279 rAppendContext.pLastParagraphProperties->GetxAlign() >= 0 ?
1280 rAppendContext.pLastParagraphProperties->GetxAlign() :
1281 text::HoriOrientation::NONE );
1282 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT), nHoriOrient));
1283
1284 sal_Int16 nVertOrient = sal_Int16(
1285 rAppendContext.pLastParagraphProperties->GetyAlign() >= 0 ?
1286 rAppendContext.pLastParagraphProperties->GetyAlign() :
1287 text::VertOrientation::NONE );
1288 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT), nVertOrient));
1289
1290 sal_Int32 nVertDist = rAppendContext.pLastParagraphProperties->GethSpace();
1291 if( nVertDist < 0 )
1292 nVertDist = 0;
1293 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_LEFT_MARGIN), nVertOrient == text::VertOrientation::TOP ? 0 : nVertDist));
1294 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_RIGHT_MARGIN), nVertOrient == text::VertOrientation::BOTTOM ? 0 : nVertDist));
1295
1296 sal_Int32 nHoriDist = rAppendContext.pLastParagraphProperties->GetvSpace();
1297 if( nHoriDist < 0 )
1298 nHoriDist = 0;
1299 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_TOP_MARGIN), nHoriOrient == text::HoriOrientation::LEFT ? 0 : nHoriDist));
1300 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_BOTTOM_MARGIN), nHoriOrient == text::HoriOrientation::RIGHT ? 0 : nHoriDist));
1301
1302 if( rAppendContext.pLastParagraphProperties->Geth() > 0 )
1303 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HEIGHT), rAppendContext.pLastParagraphProperties->Geth()));
1304
1305 if( rAppendContext.pLastParagraphProperties->IsxValid() )
1306 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT_POSITION), rAppendContext.pLastParagraphProperties->Getx()));
1307
1308 if( rAppendContext.pLastParagraphProperties->GethAnchor() >= 0 )
1309 aFrameProperties.push_back(comphelper::makePropertyValue("HoriOrientRelation", sal_Int16(rAppendContext.pLastParagraphProperties->GethAnchor())));
1310
1311 if( rAppendContext.pLastParagraphProperties->IsyValid() )
1312 aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT_POSITION), rAppendContext.pLastParagraphProperties->Gety()));
1313
1314 if( rAppendContext.pLastParagraphProperties->GetvAnchor() >= 0 )
1315 aFrameProperties.push_back(comphelper::makePropertyValue("VertOrientRelation", sal_Int16(rAppendContext.pLastParagraphProperties->GetvAnchor())));
1316
1317 if( rAppendContext.pLastParagraphProperties->GetWrap() >= text::WrapTextMode_NONE )
1318 aFrameProperties.push_back(comphelper::makePropertyValue("Surround", rAppendContext.pLastParagraphProperties->GetWrap()));
1319
1320 lcl_MoveBorderPropertiesToFrame(aFrameProperties,
1321 rAppendContext.pLastParagraphProperties->GetStartingRange(),
1322 rAppendContext.pLastParagraphProperties->GetEndingRange());
1323 }
1324
1325 //frame conversion has to be executed after table conversion
1326 RegisterFrameConversion(
1327 rAppendContext.pLastParagraphProperties->GetStartingRange(),
1328 rAppendContext.pLastParagraphProperties->GetEndingRange(),
1329 aFrameProperties );
1330 }
1331 catch( const uno::Exception& )
1332 {
1333 }
1334}
1335
1336/// Check if the style or its parent has a list id, recursively.
1337static sal_Int32 lcl_getListId(const StyleSheetEntryPtr& rEntry, const StyleSheetTablePtr& rStyleTable, bool & rNumberingFromBaseStyle)
1338{
1339 const StyleSheetPropertyMap* pEntryProperties = dynamic_cast<const StyleSheetPropertyMap*>(rEntry->pProperties.get());
1340 if (!pEntryProperties)
1341 return -1;
1342
1343 sal_Int32 nListId = pEntryProperties->GetListId();
1344 // The style itself has a list id.
1345 if (nListId >= 0)
1346 return nListId;
1347
1348 // The style has no parent.
1349 if (rEntry->sBaseStyleIdentifier.isEmpty())
1350 return -1;
1351
1352 const StyleSheetEntryPtr pParent = rStyleTable->FindStyleSheetByISTD(rEntry->sBaseStyleIdentifier);
1353 // No such parent style or loop in the style hierarchy.
1354 if (!pParent || pParent == rEntry)
1355 return -1;
1356
1357 rNumberingFromBaseStyle = true;
1358
1359 return lcl_getListId(pParent, rStyleTable, rNumberingFromBaseStyle);
1360}
1361
1362void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, const bool bRemove )
1363{
1364 if (m_bDiscardHeaderFooter)
1365 return;
1366
1367 if (!m_aFieldStack.empty())
1368 {
1369 FieldContextPtr pFieldContext = m_aFieldStack.back();
1370 if (pFieldContext && !pFieldContext->IsCommandCompleted())
1371 {
1372 std::vector<OUString> aCommandParts = pFieldContext->GetCommandParts();
1373 if (!aCommandParts.empty() && aCommandParts[0] == "IF")
1374 {
1375 // Conditional text field conditions don't support linebreaks in Writer.
1376 return;
1377 }
1378 }
1379
1380 if (pFieldContext && pFieldContext->IsCommandCompleted())
1381 {
1382 if (pFieldContext->GetFieldId() == FIELD_IF)
1383 {
1384 // Conditional text fields can't contain newlines, finish the paragraph later.
1385 FieldParagraph aFinish{pPropertyMap, bRemove};
1386 pFieldContext->GetParagraphsToFinish().push_back(aFinish);
1387 return;
1388 }
1389 }
1390 }
1391
1392#ifdef DBG_UTIL
1393 TagLogger::getInstance().startElement("finishParagraph");
1394#endif
1395
1396 m_nLastTableCellParagraphDepth = m_nTableCellDepth;
1397 ParagraphPropertyMap* pParaContext = dynamic_cast< ParagraphPropertyMap* >( pPropertyMap.get() );
1398 if (m_aTextAppendStack.empty())
1399 return;
1400 TextAppendContext& rAppendContext = m_aTextAppendStack.top();
1401 uno::Reference< text::XTextAppend > xTextAppend(rAppendContext.xTextAppend);
1402#ifdef DBG_UTIL
1403 TagLogger::getInstance().attribute("isTextAppend", sal_uInt32(xTextAppend.is()));
1404#endif
1405
1406 const StyleSheetEntryPtr pEntry = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName( GetCurrentParaStyleName() );
1407 OSL_ENSURE( pEntry, "no style sheet found" )do { if (true && (!(pEntry))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "1407" ": "), "%s", "no style sheet found"); } } while (
false)
;
1408 const StyleSheetPropertyMap* pStyleSheetProperties = dynamic_cast<const StyleSheetPropertyMap*>(pEntry ? pEntry->pProperties.get() : nullptr);
1409 bool isNumberingViaStyle(false);
1410 bool isNumberingViaRule = pParaContext && pParaContext->GetListId() > -1;
1411 sal_Int32 nListId = -1;
1412 if ( !bRemove && pStyleSheetProperties && pParaContext )
1413 {
1414 //apply numbering level/style to paragraph if it was set at the style, but only if the paragraph itself
1415 //does not specify the numbering
1416 const sal_Int16 nListLevel = pStyleSheetProperties->GetListLevel();
1417 if ( !isNumberingViaRule && nListLevel >= 0 )
1418 pParaContext->Insert( PROP_NUMBERING_LEVEL, uno::makeAny(nListLevel), false );
1419
1420 bool bNumberingFromBaseStyle = false;
1421 nListId = pEntry ? lcl_getListId(pEntry, GetStyleSheetTable(), bNumberingFromBaseStyle) : -1;
1422 auto const pList(GetListTable()->GetList(nListId));
1423 if (pList && nListId >= 0 && !pParaContext->isSet(PROP_NUMBERING_STYLE_NAME))
1424 {
1425 if ( !isNumberingViaRule )
1426 {
1427 isNumberingViaStyle = true;
1428 // Since LO7.0/tdf#131321 fixed the loss of numbering in styles, this OUGHT to be obsolete,
1429 // but now other new/critical LO7.0 code expects it, and perhaps some corner cases still need it as well.
1430 // So we skip it only for default outline styles, which are recognized by NumberingManager.
1431 if (!GetCurrentParaStyleName().startsWith("Heading ") || nListLevel >= pList->GetDefaultParentLevels())
1432 pParaContext->Insert( PROP_NUMBERING_STYLE_NAME, uno::makeAny(pList->GetStyleName()), true );
1433 }
1434 else if ( !pList->isOutlineNumbering(nListLevel) )
1435 {
1436 // After ignoring anything related to the special Outline levels,
1437 // we have direct numbering, as well as paragraph-style numbering.
1438 // Apply the style if it uses the same list as the direct numbering,
1439 // otherwise the directly-applied-to-paragraph status will be lost,
1440 // and the priority of the numbering-style-indents will be lowered. tdf#133000
1441 if ( nListId == pParaContext->GetListId() )
1442 pParaContext->Insert( PROP_NUMBERING_STYLE_NAME, uno::makeAny(pList->GetStyleName()), true );
1443 }
1444 }
1445
1446 if ( isNumberingViaStyle )
1447 {
1448 // When numbering is defined by the paragraph style, then the para-style indents have priority.
1449 // But since import has just copied para-style's PROP_NUMBERING_STYLE_NAME directly onto the paragraph,
1450 // the numbering indents now have the priority.
1451 // So now import must also copy the para-style indents directly onto the paragraph to compensate.
1452 std::optional<PropertyMap::Property> oProperty;
1453 const StyleSheetEntryPtr pParent = (!pEntry->sBaseStyleIdentifier.isEmpty()) ? GetStyleSheetTable()->FindStyleSheetByISTD(pEntry->sBaseStyleIdentifier) : nullptr;
1454 const StyleSheetPropertyMap* pParentProperties = dynamic_cast<const StyleSheetPropertyMap*>(pParent ? pParent->pProperties.get() : nullptr);
1455 if (!pEntry->sBaseStyleIdentifier.isEmpty())
1456 {
1457 oProperty = pStyleSheetProperties->getProperty(PROP_PARA_FIRST_LINE_INDENT);
1458 if ( oProperty
1459 // If the numbering comes from a base style, indent of the base style has also priority.
1460 || (bNumberingFromBaseStyle && pParentProperties && (oProperty = pParentProperties->getProperty(PROP_PARA_FIRST_LINE_INDENT))) )
1461 pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, oProperty->second, /*bOverwrite=*/false);
1462 }
1463 oProperty = pStyleSheetProperties->getProperty(PROP_PARA_LEFT_MARGIN);
1464 if ( oProperty
1465 || (bNumberingFromBaseStyle && pParentProperties && (oProperty = pParentProperties->getProperty(PROP_PARA_LEFT_MARGIN))) )
1466 pParaContext->Insert(PROP_PARA_LEFT_MARGIN, oProperty->second, /*bOverwrite=*/false);
1467
1468 // We're inheriting properties from a numbering style. Make sure a possible right margin is inherited from the base style.
1469 sal_Int32 nParaRightMargin;
1470 if ( pParentProperties && (oProperty = pParentProperties->getProperty(PROP_PARA_RIGHT_MARGIN)) && (nParaRightMargin = oProperty->second.get<sal_Int32>()) != 0 )
1471 {
1472 // If we're setting the right margin, we should set the first / left margin as well from the numbering style.
1473 const sal_Int32 nFirstLineIndent = getNumberingProperty(nListId, nListLevel, "FirstLineIndent");
1474 const sal_Int32 nParaLeftMargin = getNumberingProperty(nListId, nListLevel, "IndentAt");
1475 if (nFirstLineIndent != 0)
1476 pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::makeAny(nFirstLineIndent), /*bOverwrite=*/false);
1477 if (nParaLeftMargin != 0)
1478 pParaContext->Insert(PROP_PARA_LEFT_MARGIN, uno::makeAny(nParaLeftMargin), /*bOverwrite=*/false);
1479
1480 pParaContext->Insert(PROP_PARA_RIGHT_MARGIN, uno::makeAny(nParaRightMargin), /*bOverwrite=*/false);
1481 }
1482 }
1483 // Paragraph style based right paragraph indentation affects not paragraph style based lists in DOCX.
1484 // Apply it as direct formatting, also left and first line indentation of numbering to keep them.
1485 else if (isNumberingViaRule)
1486 {
1487 uno::Any aRightMargin = GetPropertyFromParaStyleSheet(PROP_PARA_RIGHT_MARGIN);
1488 if ( aRightMargin != uno::Any() )
1489 {
1490 pParaContext->Insert(PROP_PARA_RIGHT_MARGIN, aRightMargin, /*bOverwrite=*/false);
1491
1492 sal_Int32 nListId2(static_cast<ParagraphPropertyMap*>(pPropertyMap.get())->GetListId());
1493
1494 const sal_Int32 nFirstLineIndent = getNumberingProperty(nListId2, nListLevel, "FirstLineIndent");
1495 const sal_Int32 nParaLeftMargin = getNumberingProperty(nListId2, nListLevel, "IndentAt");
1496 if (nFirstLineIndent != 0)
1497 pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::makeAny(nFirstLineIndent), /*bOverwrite=*/false);
1498 if (nParaLeftMargin != 0)
1499 pParaContext->Insert(PROP_PARA_LEFT_MARGIN, uno::makeAny(nParaLeftMargin), /*bOverwrite=*/false);
1500 }
1501 }
1502 }
1503
1504 // apply AutoSpacing: it has priority over all other margin settings
1505 // (note that numbering with autoSpacing is handled separately later on)
1506 const bool bAllowAdjustments = !GetSettingsTable()->GetDoNotUseHTMLParagraphAutoSpacing();
1507 sal_Int32 nBeforeAutospacing = -1;
1508 bool bIsAutoSet = pParaContext && pParaContext->isSet(PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING);
1509 // apply INHERITED autospacing only if top margin is not set
1510 if ( bIsAutoSet || (pParaContext && !pParaContext->isSet(PROP_PARA_TOP_MARGIN)) )
1511 GetAnyProperty(PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING, pPropertyMap) >>= nBeforeAutospacing;
1512 if ( nBeforeAutospacing > -1 && pParaContext )
1513 {
1514 if ( bAllowAdjustments )
1515 {
1516 if ( GetIsFirstParagraphInShape() ||
1517 (GetIsFirstParagraphInSection() && GetSectionContext() && GetSectionContext()->IsFirstSection()) ||
1518 (m_bFirstParagraphInCell && m_nTableDepth > 0 && m_nTableDepth == m_nTableCellDepth) )
1519 {
1520 nBeforeAutospacing = 0;
1521 // export requires grabbag to match top_margin, so keep them in sync
1522 if ( bIsAutoSet )
1523 pParaContext->Insert( PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING, uno::makeAny( sal_Int32(0) ),true, PARA_GRAB_BAG );
1524 }
1525 }
1526 pParaContext->Insert(PROP_PARA_TOP_MARGIN, uno::makeAny(nBeforeAutospacing));
1527 }
1528
1529 sal_Int32 nAfterAutospacing = -1;
1530 bIsAutoSet = pParaContext && pParaContext->isSet(PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING);
1531 bool bApplyAutospacing = bIsAutoSet || (pParaContext && !pParaContext->isSet(PROP_PARA_BOTTOM_MARGIN));
1532 if ( bApplyAutospacing )
1533 GetAnyProperty(PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING, pPropertyMap) >>= nAfterAutospacing;
1534 if ( nAfterAutospacing > -1 && pParaContext )
1535 {
1536 pParaContext->Insert(PROP_PARA_BOTTOM_MARGIN, uno::makeAny(nAfterAutospacing));
1537 bApplyAutospacing = bAllowAdjustments;
1538 }
1539 else
1540 bApplyAutospacing = false;
1541
1542 // tell TableManager to reset the bottom margin if it determines that this is the cell's last paragraph.
1543 if ( hasTableManager() && getTableManager().isInCell() )
1544 getTableManager().setCellLastParaAfterAutospacing( bApplyAutospacing );
1545
1546 if (xTextAppend.is() && pParaContext && hasTableManager() && !getTableManager().isIgnore())
1547 {
1548 try
1549 {
1550 /*the following combinations of previous and current frame settings can occur:
1551 (1) - no old frame and no current frame -> no special action
1552 (2) - no old frame and current DropCap -> save DropCap for later use, don't call finishParagraph
1553 remove character properties of the DropCap?
1554 (3) - no old frame and current Frame -> save Frame for later use
1555 (4) - old DropCap and no current frame -> add DropCap to the properties of the finished paragraph, delete previous setting
1556 (5) - old DropCap and current frame -> add DropCap to the properties of the finished paragraph, save current frame settings
1557 (6) - old Frame and new DropCap -> add old Frame, save DropCap for later use
1558 (7) - old Frame and new same Frame -> continue
1559 (8) - old Frame and new different Frame -> add old Frame, save new Frame for later use
1560 (9) - old Frame and no current frame -> add old Frame, delete previous settings
1561
1562 old _and_ new DropCap must not occur
1563 */
1564
1565 bool bIsDropCap =
1566 pParaContext->IsFrameMode() &&
1567 sal::static_int_cast<Id>(pParaContext->GetDropCap()) != NS_ooxml::LN_Value_doc_ST_DropCap_none;
1568
1569 style::DropCapFormat aDrop;
1570 ParagraphPropertiesPtr pToBeSavedProperties;
1571 bool bKeepLastParagraphProperties = false;
1572 if( bIsDropCap )
1573 {
1574 uno::Reference<text::XParagraphCursor> xParaCursor(
1575 xTextAppend->createTextCursorByRange(xTextAppend->getEnd()), uno::UNO_QUERY_THROW);
1576 //select paragraph
1577 xParaCursor->gotoStartOfParagraph( true );
1578 uno::Reference< beans::XPropertyState > xParaProperties( xParaCursor, uno::UNO_QUERY_THROW );
1579 xParaProperties->setPropertyToDefault(getPropertyName(PROP_CHAR_ESCAPEMENT));
1580 xParaProperties->setPropertyToDefault(getPropertyName(PROP_CHAR_HEIGHT));
1581 //handles (2) and part of (6)
1582 pToBeSavedProperties = new ParagraphProperties(*pParaContext);
1583 sal_Int32 nCount = xParaCursor->getString().getLength();
1584 pToBeSavedProperties->SetDropCapLength(nCount > 0 && nCount < 255 ? static_cast<sal_Int8>(nCount) : 1);
1585 }
1586 if( rAppendContext.pLastParagraphProperties )
1587 {
1588 if( sal::static_int_cast<Id>(rAppendContext.pLastParagraphProperties->GetDropCap()) != NS_ooxml::LN_Value_doc_ST_DropCap_none)
1589 {
1590 //handles (4) and part of (5)
1591 //create a DropCap property, add it to the property sequence of finishParagraph
1592 sal_Int32 nLines = rAppendContext.pLastParagraphProperties->GetLines();
1593 aDrop.Lines = nLines > 0 && nLines < SAL_MAX_INT8((sal_Int8) 0x7F) ? static_cast<sal_Int8>(nLines) : 2;
1594 aDrop.Count = rAppendContext.pLastParagraphProperties->GetDropCapLength();
1595 sal_Int32 nHSpace = rAppendContext.pLastParagraphProperties->GethSpace();
1596 aDrop.Distance = nHSpace > 0 && nHSpace < SAL_MAX_INT16((sal_Int16) 0x7FFF) ? static_cast<sal_Int16>(nHSpace) : 0;
1597 //completes (5)
1598 if( pParaContext->IsFrameMode() )
1599 pToBeSavedProperties = new ParagraphProperties(*pParaContext);
1600 }
1601 else if(*rAppendContext.pLastParagraphProperties == *pParaContext )
1602 {
1603 //handles (7)
1604 rAppendContext.pLastParagraphProperties->SetEndingRange(rAppendContext.xInsertPosition.is() ? rAppendContext.xInsertPosition : xTextAppend->getEnd());
1605 bKeepLastParagraphProperties = true;
1606 }
1607 else
1608 {
1609 //handles (8)(9) and completes (6)
1610 CheckUnregisteredFrameConversion( );
1611
1612 // If different frame properties are set on this paragraph, keep them.
1613 if ( !bIsDropCap && pParaContext->IsFrameMode() )
1614 {
1615 pToBeSavedProperties = new ParagraphProperties(*pParaContext);
1616 lcl_AddRangeAndStyle(pToBeSavedProperties, xTextAppend, pPropertyMap, rAppendContext);
1617 }
1618 }
1619 }
1620 else
1621 {
1622 // (1) doesn't need handling
1623
1624 if( !bIsDropCap && pParaContext->IsFrameMode() )
1625 {
1626 pToBeSavedProperties = new ParagraphProperties(*pParaContext);
1627 lcl_AddRangeAndStyle(pToBeSavedProperties, xTextAppend, pPropertyMap, rAppendContext);
1628 }
1629 }
1630 std::vector<beans::PropertyValue> aProperties;
1631 if (pPropertyMap)
1632 {
1633 aProperties = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(pPropertyMap->GetPropertyValues());
1634 }
1635 // TODO: this *should* work for RTF but there are test failures, maybe rtftok doesn't distinguish between formatting for the paragraph marker and for the paragraph as a whole; needs investigation
1636 if (pPropertyMap && IsOOXMLImport())
1637 {
1638 // tdf#64222 filter out the "paragraph marker" formatting and
1639 // set it as a separate paragraph property, not a empty hint at
1640 // end of paragraph
1641 std::vector<beans::NamedValue> charProperties;
1642 for (auto it = aProperties.begin(); it != aProperties.end(); )
1643 {
1644 // this condition isn't ideal but as it happens all
1645 // RES_CHRATR_* have names that start with "Char"
1646 if (it->Name.startsWith("Char"))
1647 {
1648 charProperties.emplace_back(it->Name, it->Value);
1649 // as testN793262 demonstrates, font size in rPr must
1650 // affect the paragraph size => also insert empty hint!
1651// it = aProperties.erase(it);
1652 }
1653 ++it;
1654 }
1655 if (!charProperties.empty())
1656 {
1657 aProperties.push_back(beans::PropertyValue("ListAutoFormat",
1658 0, uno::makeAny(comphelper::containerToSequence(charProperties)), beans::PropertyState_DIRECT_VALUE));
1659 }
1660 }
1661 if( !bIsDropCap )
1662 {
1663 if( aDrop.Lines > 1 )
1664 {
1665 beans::PropertyValue aValue;
1666 aValue.Name = getPropertyName(PROP_DROP_CAP_FORMAT);
1667 aValue.Value <<= aDrop;
1668 aProperties.push_back(aValue);
1669 }
1670 uno::Reference< text::XTextRange > xTextRange;
1671 if (rAppendContext.xInsertPosition.is())
1672 {
1673 xTextRange = xTextAppend->finishParagraphInsert( comphelper::containerToSequence(aProperties), rAppendContext.xInsertPosition );
1674 rAppendContext.xCursor->gotoNextParagraph(false);
1675 if (rAppendContext.pLastParagraphProperties)
1676 rAppendContext.pLastParagraphProperties->SetEndingRange(xTextRange->getEnd());
1677 }
1678 else
1679 {
1680 uno::Reference<text::XTextCursor> xCursor;
1681 if (m_bParaHadField && !m_bIsInComments && !xTOCMarkerCursor.is())
1682 {
1683 // Workaround to make sure char props of the field are not lost.
1684 // Not relevant for editeng-based comments.
1685 // Not relevant for fields inside a TOC field.
1686 xCursor = xTextAppend->getText()->createTextCursor();
1687 if (xCursor.is())
1688 xCursor->gotoEnd(false);
1689 PropertyMapPtr pEmpty(new PropertyMap());
1690 appendTextPortion("X", pEmpty);
1691 }
1692
1693 // Check if top / bottom margin has to be updated, now that we know the numbering status of both the previous and
1694 // the current text node.
1695 auto itNumberingRules = std::find_if(aProperties.begin(), aProperties.end(), [](const beans::PropertyValue& rValue)
1696 {
1697 return rValue.Name == "NumberingRules";
1698 });
1699
1700 assert( isNumberingViaRule == (itNumberingRules != aProperties.end()) )(static_cast <bool> (isNumberingViaRule == (itNumberingRules
!= aProperties.end())) ? void (0) : __assert_fail ("isNumberingViaRule == (itNumberingRules != aProperties.end())"
, "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 1700, __extension__ __PRETTY_FUNCTION__))
;
1701 isNumberingViaRule = (itNumberingRules != aProperties.end());
1702 if (m_xPreviousParagraph.is() && (isNumberingViaRule || isNumberingViaStyle))
1703 {
1704 // This textnode has numbering. Look up the numbering style name of the current and previous paragraph.
1705 OUString aCurrentNumberingName;
1706 OUString aPreviousNumberingName;
1707 if (isNumberingViaRule)
1708 {
1709 uno::Reference<container::XNamed> xCurrentNumberingRules(itNumberingRules->Value, uno::UNO_QUERY);
1710 if (xCurrentNumberingRules.is())
1711 aCurrentNumberingName = xCurrentNumberingRules->getName();
1712 if (m_xPreviousParagraph.is())
1713 {
1714 uno::Reference<container::XNamed> xPreviousNumberingRules(m_xPreviousParagraph->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
1715 if (xPreviousNumberingRules.is())
1716 aPreviousNumberingName = xPreviousNumberingRules->getName();
1717 }
1718 }
1719 else if ( m_xPreviousParagraph->getPropertySetInfo()->hasPropertyByName("NumberingStyleName") &&
1720 // don't update before tables
1721 (m_nTableDepth == 0 || !m_bFirstParagraphInCell))
1722 {
1723 aCurrentNumberingName = GetListStyleName(nListId);
1724 m_xPreviousParagraph->getPropertyValue("NumberingStyleName") >>= aPreviousNumberingName;
1725 }
1726
1727 if (!aPreviousNumberingName.isEmpty() && aCurrentNumberingName == aPreviousNumberingName)
1728 {
1729 uno::Sequence<beans::PropertyValue> aPrevPropertiesSeq;
1730 m_xPreviousParagraph->getPropertyValue("ParaInteropGrabBag") >>= aPrevPropertiesSeq;
1731 auto aPrevProperties = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aPrevPropertiesSeq);
1732 bool bParaAutoBefore = m_bParaAutoBefore || std::any_of(aPrevProperties.begin(), aPrevProperties.end(), [](const beans::PropertyValue& rValue)
1733 {
1734 return rValue.Name == "ParaTopMarginBeforeAutoSpacing";
1735 });
1736 // if style based spacing was set to auto in the previous paragraph, style of the actual paragraph must be the same
1737 if (bParaAutoBefore && !m_bParaAutoBefore && m_xPreviousParagraph->getPropertySetInfo()->hasPropertyByName("ParaStyleName"))
1738 {
1739 auto itParaStyle = std::find_if(aProperties.begin(), aProperties.end(), [](const beans::PropertyValue& rValue)
1740 {
1741 return rValue.Name == "ParaStyleName";
1742 });
1743 bParaAutoBefore = itParaStyle != aProperties.end() &&
1744 m_xPreviousParagraph->getPropertyValue("ParaStyleName") == itParaStyle->Value;
1745 }
1746 // There was a previous textnode and it had the same numbering.
1747 if (bParaAutoBefore)
1748 {
1749 // This before spacing is set to auto, set before space to 0.
1750 auto itParaTopMargin = std::find_if(aProperties.begin(), aProperties.end(), [](const beans::PropertyValue& rValue)
1751 {
1752 return rValue.Name == "ParaTopMargin";
1753 });
1754 if (itParaTopMargin != aProperties.end())
1755 itParaTopMargin->Value <<= static_cast<sal_Int32>(0);
1756 else
1757 aProperties.push_back(comphelper::makePropertyValue("ParaTopMargin", static_cast<sal_Int32>(0)));
1758 }
1759
1760 bool bPrevParaAutoAfter = std::any_of(aPrevProperties.begin(), aPrevProperties.end(), [](const beans::PropertyValue& rValue)
1761 {
1762 return rValue.Name == "ParaBottomMarginAfterAutoSpacing";
1763 });
1764 if (bPrevParaAutoAfter)
1765 {
1766 // Previous after spacing is set to auto, set previous after space to 0.
1767 m_xPreviousParagraph->setPropertyValue("ParaBottomMargin", uno::makeAny(static_cast<sal_Int32>(0)));
1768 }
1769 }
1770 }
1771
1772 xTextRange = xTextAppend->finishParagraph( comphelper::containerToSequence(aProperties) );
1773 m_xPreviousParagraph.set(xTextRange, uno::UNO_QUERY);
1774
1775 if (m_xPreviousParagraph.is() && // null for SvxUnoTextBase
1776 (isNumberingViaStyle || isNumberingViaRule))
1777 {
1778 assert(dynamic_cast<ParagraphPropertyMap*>(pPropertyMap.get()))(static_cast <bool> (dynamic_cast<ParagraphPropertyMap
*>(pPropertyMap.get())) ? void (0) : __assert_fail ("dynamic_cast<ParagraphPropertyMap*>(pPropertyMap.get())"
, "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 1778, __extension__ __PRETTY_FUNCTION__))
;
1779 // Use lcl_getListId(), so we find the list ID in parent styles as well.
1780 bool bNumberingFromBaseStyle = false;
1781 sal_Int32 const nListId2( isNumberingViaStyle
1782 ? lcl_getListId(pEntry, GetStyleSheetTable(), bNumberingFromBaseStyle)
1783 : static_cast<ParagraphPropertyMap*>(pPropertyMap.get())->GetListId());
1784 if (ListDef::Pointer const& pList = m_pListTable->GetList(nListId2))
1785 { // styles could refer to non-existing lists...
1786 AbstractListDef::Pointer const& pAbsList =
1787 pList->GetAbstractDefinition();
1788 if (pAbsList &&
1789 // SvxUnoTextRange doesn't have ListId
1790 m_xPreviousParagraph->getPropertySetInfo()->hasPropertyByName("ListId"))
1791 {
1792 OUString paraId;
1793 m_xPreviousParagraph->getPropertyValue("ListId") >>= paraId;
1794 if (!paraId.isEmpty()) // must be on some list?
1795 {
1796 OUString const listId = pAbsList->MapListId(paraId);
1797 if (listId != paraId)
1798 {
1799 m_xPreviousParagraph->setPropertyValue("ListId", uno::makeAny(listId));
1800 }
1801 }
1802 }
1803 if (pList->GetCurrentLevel())
1804 {
1805 sal_Int16 nOverrideLevel = pList->GetCurrentLevel()->GetStartOverride();
1806 if (nOverrideLevel != -1 && m_aListOverrideApplied.find(nListId2) == m_aListOverrideApplied.end())
1807 {
1808 // Apply override: we have override instruction for this level
1809 // And this was not done for this list before: we can do this only once on first occurrence
1810 // of list with override
1811 // TODO: Not tested variant with different levels override in different lists.
1812 // Probably m_aListOverrideApplied as a set of overridden listids is not sufficient
1813 // and we need to register level overrides separately.
1814 m_xPreviousParagraph->setPropertyValue("ParaIsNumberingRestart", uno::makeAny(true));
1815 m_xPreviousParagraph->setPropertyValue("NumberingStartValue", uno::makeAny(nOverrideLevel));
1816 m_aListOverrideApplied.insert(nListId2);
1817 }
1818 }
1819 }
1820 }
1821
1822 if (!rAppendContext.m_aAnchoredObjects.empty() && !IsInHeaderFooter())
1823 {
1824 // Remember what objects are anchored to this paragraph.
1825 // That list is only used for Word compat purposes, and
1826 // it is only relevant for body text.
1827 AnchoredObjectsInfo aInfo;
1828 aInfo.m_xParagraph = xTextRange;
1829 aInfo.m_aAnchoredObjects = rAppendContext.m_aAnchoredObjects;
1830 m_aAnchoredObjectAnchors.push_back(aInfo);
1831 rAppendContext.m_aAnchoredObjects.clear();
1832 }
1833
1834 // We're no longer right after a table conversion.
1835 m_bConvertedTable = false;
1836
1837 if (xCursor.is())
1838 {
1839 xCursor->goLeft(1, true);
1840 xCursor->setString(OUString());
1841 }
1842 }
1843 getTableManager( ).handle(xTextRange);
1844 m_aSmartTagHandler.handle(xTextRange);
1845
1846 if (xTextRange.is())
1847 {
1848 // Get the end of paragraph character inserted
1849 uno::Reference< text::XTextCursor > xCur = xTextRange->getText( )->createTextCursor( );
1850 if (rAppendContext.xInsertPosition.is())
1851 xCur->gotoRange( rAppendContext.xInsertPosition, false );
1852 else
1853 xCur->gotoEnd( false );
1854
1855 // tdf#77417 trim right white spaces in table cells in 2010 compatibility mode
1856 sal_Int32 nMode = GetSettingsTable()->GetWordCompatibilityMode();
1857 if ( m_nTableDepth > 0 && nMode > 0 && nMode <= 14 )
1858 {
1859 // skip new line
1860 xCur->goLeft(1, false);
1861 while ( xCur->goLeft(1, true) )
1862 {
1863 OUString sChar = xCur->getString();
1864 if ( sChar == " " || sChar == "\t" || sChar == OUStringChar(u'\x00A0') )
1865 xCur->setString("");
1866 else
1867 break;
1868 }
1869 xCur->goRight(2, false);
1870 }
1871
1872 xCur->goLeft( 1 , true );
1873 // Extend the redline ranges for empty paragraphs
1874 if ( !m_bParaChanged && m_previousRedline )
1875 CreateRedline( xCur, m_previousRedline );
1876 CheckParaMarkerRedline( xCur );
1877 }
1878
1879 css::uno::Reference<css::beans::XPropertySet> xParaProps(xTextRange, uno::UNO_QUERY);
1880
1881 // table style precedence and not hidden shapes anchored to hidden empty table paragraphs
1882 if (xParaProps && (m_nTableDepth > 0 || !m_aAnchoredObjectAnchors.empty()) )
1883 {
1884 // table style has got bigger precedence than docDefault style
1885 // collect these pending paragraph properties to process in endTable()
1886 uno::Reference<text::XTextCursor> xCur = xTextRange->getText( )->createTextCursor( );
1887 xCur->gotoEnd(false);
1888 xCur->goLeft(1, false);
1889 uno::Reference<text::XTextCursor> xCur2 = xTextRange->getText()->createTextCursorByRange(xCur);
1890 uno::Reference<text::XParagraphCursor> xParaCursor(xCur2, uno::UNO_QUERY_THROW);
1891 xParaCursor->gotoStartOfParagraph(false);
1892 if (m_nTableDepth > 0)
1893 {
1894 TableParagraph aPending{xParaCursor, xCur, pParaContext, xParaProps, std::set<OUString>()};
1895 getTableManager().getCurrentParagraphs()->push_back(aPending);
1896 }
1897
1898 // hidden empty paragraph with a not hidden shape, set as not hidden
1899 std::optional<PropertyMap::Property> pHidden;
1900 if ( !m_aAnchoredObjectAnchors.empty() && (pHidden = pParaContext->getProperty(PROP_CHAR_HIDDEN)) )
1901 {
1902 bool bIsHidden = {}; // -Werror=maybe-uninitialized
1903 pHidden->second >>= bIsHidden;
1904 if (bIsHidden)
1905 {
1906 bIsHidden = false;
1907 pHidden = GetTopContext()->getProperty(PROP_CHAR_HIDDEN);
1908 if (pHidden)
1909 pHidden->second >>= bIsHidden;
1910 if (!bIsHidden)
1911 {
1912 uno::Reference<text::XTextCursor> xCur3 = xTextRange->getText()->createTextCursorByRange(xParaCursor);
1913 xCur3->goRight(1, true);
1914 if (xCur3->getString() == SAL_NEWLINE_STRING"\n")
1915 {
1916 uno::Reference< beans::XPropertySet > xProp( xCur3, uno::UNO_QUERY );
1917 xProp->setPropertyValue(getPropertyName(PROP_CHAR_HIDDEN), uno::makeAny(false));
1918 }
1919 }
1920 }
1921 }
1922 }
1923
1924 // tdf#118521 set paragraph top or bottom margin based on the paragraph style
1925 // if we already set the other margin with direct formatting
1926 if (xParaProps)
1927 {
1928 const bool bTopSet = pParaContext->isSet(PROP_PARA_TOP_MARGIN);
1929 const bool bBottomSet = pParaContext->isSet(PROP_PARA_BOTTOM_MARGIN);
1930 const bool bContextSet = pParaContext->isSet(PROP_PARA_CONTEXT_MARGIN);
1931 if ( bTopSet != bBottomSet || bBottomSet != bContextSet )
1932 {
1933
1934 if ( !bTopSet )
1935 {
1936 uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_TOP_MARGIN);
1937 if ( aMargin != uno::Any() )
1938 xParaProps->setPropertyValue("ParaTopMargin", aMargin);
1939 }
1940 if ( !bBottomSet )
1941 {
1942 uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_BOTTOM_MARGIN);
1943 if ( aMargin != uno::Any() )
1944 xParaProps->setPropertyValue("ParaBottomMargin", aMargin);
1945 }
1946 if ( !bContextSet )
1947 {
1948 uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_CONTEXT_MARGIN);
1949 if ( aMargin != uno::Any() )
1950 xParaProps->setPropertyValue("ParaContextMargin", aMargin);
1951 }
1952 }
1953 }
1954
1955 // Left, Right, and Hanging settings are also grouped. Ensure that all or none are set.
1956 if (xParaProps)
1957 {
1958 const bool bLeftSet = pParaContext->isSet(PROP_PARA_LEFT_MARGIN);
1959 const bool bRightSet = pParaContext->isSet(PROP_PARA_RIGHT_MARGIN);
1960 const bool bFirstSet = pParaContext->isSet(PROP_PARA_FIRST_LINE_INDENT);
1961 if ( bLeftSet != bRightSet || bRightSet != bFirstSet )
1962 {
1963 if ( !bLeftSet )
1964 {
1965 uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_LEFT_MARGIN);
1966 if ( aMargin != uno::Any() )
1967 xParaProps->setPropertyValue("ParaLeftMargin", aMargin);
1968 else if (isNumberingViaStyle)
1969 {
1970 const sal_Int32 nParaLeftMargin = getNumberingProperty(nListId, pStyleSheetProperties->GetListLevel(), "IndentAt");
1971 if (nParaLeftMargin != 0)
1972 xParaProps->setPropertyValue("ParaLeftMargin", uno::makeAny(nParaLeftMargin));
1973 }
1974 }
1975 if ( !bRightSet )
1976 {
1977 uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_RIGHT_MARGIN);
1978 if ( aMargin != uno::Any() )
1979 xParaProps->setPropertyValue("ParaRightMargin", aMargin);
1980 }
1981 if ( !bFirstSet )
1982 {
1983 uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_FIRST_LINE_INDENT);
1984 if ( aMargin != uno::Any() )
1985 xParaProps->setPropertyValue("ParaFirstLineIndent", aMargin);
1986 else if (isNumberingViaStyle)
1987 {
1988 const sal_Int32 nFirstLineIndent = getNumberingProperty(nListId, pStyleSheetProperties->GetListLevel(), "FirstLineIndent");
1989 if (nFirstLineIndent != 0)
1990 xParaProps->setPropertyValue("ParaFirstLineIndent", uno::makeAny(nFirstLineIndent));
1991 }
1992 }
1993 }
1994 }
1995
1996 // fix table paragraph properties
1997 if ( xTextRange.is() && xParaProps && m_nTableDepth > 0 )
1998 {
1999 uno::Sequence< beans::PropertyValue > aParaProps = pParaContext->GetPropertyValues(false);
2000 uno::Reference<text::XTextCursor> xCur = xTextRange->getText()->createTextCursorByRange(xTextRange);
2001 uno::Reference< beans::XPropertyState > xRunProperties( xCur, uno::UNO_QUERY_THROW );
2002 // tdf#90069 in tables, apply paragraph level character style also on
2003 // paragraph level to support its copy during insertion of new table rows
2004 for( const auto& rParaProp : std::as_const(aParaProps) )
2005 {
2006 if ( rParaProp.Name.startsWith("Char") && rParaProp.Name != "CharStyleName" && rParaProp.Name != "CharInteropGrabBag" &&
2007 // all text portions contain the same value, so next setPropertyValue() won't overwrite part of them
2008 xRunProperties->getPropertyState(rParaProp.Name) == css::beans::PropertyState_DIRECT_VALUE )
2009 {
2010 uno::Reference<beans::XPropertySet> xRunPropertySet(xCur, uno::UNO_QUERY);
2011 xParaProps->setPropertyValue( rParaProp.Name, xRunPropertySet->getPropertyValue(rParaProp.Name) );
2012 // remember this for table style handling
2013 getTableManager().getCurrentParagraphs()->back().m_aParaOverrideApplied.insert(rParaProp.Name);
2014 }
2015 }
2016
2017 // tdf#128959 table paragraphs haven't got window and orphan controls
2018 uno::Any aAny = uno::makeAny(static_cast<sal_Int8>(0));
2019 xParaProps->setPropertyValue("ParaOrphans", aAny);
2020 xParaProps->setPropertyValue("ParaWidows", aAny);
2021 }
2022 }
2023 if( !bKeepLastParagraphProperties )
2024 rAppendContext.pLastParagraphProperties = pToBeSavedProperties;
2025 }
2026 catch(const lang::IllegalArgumentException&)
2027 {
2028 OSL_FAIL( "IllegalArgumentException in DomainMapper_Impl::finishParagraph" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2028" ": "), "%s", "IllegalArgumentException in DomainMapper_Impl::finishParagraph"
); } } while (false)
;
2029 }
2030 catch(const uno::Exception&)
2031 {
2032 TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "finishParagraph()" )do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "finishParagraph()"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2032" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "finishParagraph()" << " " <<
exceptionToString(tools_warn_exception)), 0); } else { ::std
::ostringstream sal_detail_stream; sal_detail_stream <<
"finishParagraph()" << " " << exceptionToString(
tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2032" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "finishParagraph()" << " " << exceptionToString
(tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2032" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "finishParagraph()" << " " <<
exceptionToString(tools_warn_exception)), 0); } else { ::std
::ostringstream sal_detail_stream; sal_detail_stream <<
"finishParagraph()" << " " << exceptionToString(
tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2032" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
2033 }
2034
2035 }
2036
2037 bool bIgnoreFrameState = IsInHeaderFooter();
2038 if( (!bIgnoreFrameState && pParaContext && pParaContext->IsFrameMode()) || (bIgnoreFrameState && GetIsPreviousParagraphFramed()) )
2039 SetIsPreviousParagraphFramed(true);
2040 else
2041 SetIsPreviousParagraphFramed(false);
2042
2043 m_bParaChanged = false;
2044 m_bRemoveThisParagraph = false;
2045 if( !IsInHeaderFooter() && !IsInShape() && (!pParaContext || !pParaContext->IsFrameMode()) )
2046 { // If the paragraph is in a frame, shape or header/footer, it's not a paragraph of the section itself.
2047 SetIsFirstParagraphInSection(false);
2048 // count first not deleted paragraph as first paragraph in section to avoid of
2049 // its deletion later, resulting loss of the associated page break
2050 if (!m_previousRedline)
2051 {
2052 SetIsFirstParagraphInSectionAfterRedline(false);
2053 SetIsLastParagraphInSection(false);
2054 }
2055 }
2056 m_previousRedline.clear();
2057
2058 if (m_bIsFirstParaInShape)
2059 m_bIsFirstParaInShape = false;
2060
2061 if (pParaContext)
2062 {
2063 // Reset the frame properties for the next paragraph
2064 pParaContext->ResetFrameProperties();
2065 }
2066
2067 SetIsOutsideAParagraph(true);
2068 m_bParaHadField = false;
2069
2070 // don't overwrite m_bFirstParagraphInCell in table separator nodes
2071 if (m_nTableDepth > 0 && m_nTableDepth == m_nTableCellDepth)
2072 m_bFirstParagraphInCell = false;
2073
2074 m_bParaAutoBefore = false;
2075 m_bParaWithInlineObject = false;
2076
2077#ifdef DBG_UTIL
2078 TagLogger::getInstance().endElement();
2079#endif
2080
2081}
2082
2083void DomainMapper_Impl::appendTextPortion( const OUString& rString, const PropertyMapPtr& pPropertyMap )
2084{
2085 if (m_bDiscardHeaderFooter)
2086 return;
2087
2088 if (m_aTextAppendStack.empty())
2089 return;
2090 // Before placing call to processDeferredCharacterProperties(), TopContextType should be CONTEXT_CHARACTER
2091 // processDeferredCharacterProperties() invokes only if character inserted
2092 if( pPropertyMap == m_pTopContext && !deferredCharacterProperties.empty() && (GetTopContextType() == CONTEXT_CHARACTER) )
2093 processDeferredCharacterProperties();
2094 uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
2095 if (!xTextAppend.is() || !hasTableManager() || getTableManager().isIgnore())
2096 return;
2097
2098 try
2099 {
2100 // If we are in comments, then disable CharGrabBag, comment text doesn't support that.
2101 uno::Sequence< beans::PropertyValue > aValues = pPropertyMap->GetPropertyValues(/*bCharGrabBag=*/!m_bIsInComments);
2102
2103 if (m_bStartTOC || m_bStartIndex || m_bStartBibliography)
2104 for( auto& rValue : aValues )
2105 {
2106 if (rValue.Name == "CharHidden")
2107 rValue.Value <<= false;
2108 }
2109
2110 uno::Reference< text::XTextRange > xTextRange;
2111 if (m_aTextAppendStack.top().xInsertPosition.is())
2112 {
2113 xTextRange = xTextAppend->insertTextPortion(rString, aValues, m_aTextAppendStack.top().xInsertPosition);
2114 m_aTextAppendStack.top().xCursor->gotoRange(xTextRange->getEnd(), true);
2115 }
2116 else
2117 {
2118 if (m_bStartTOC || m_bStartIndex || m_bStartBibliography || m_nStartGenericField != 0)
2119 {
2120 if (IsInHeaderFooter() && !m_bStartTOCHeaderFooter)
2121 {
2122 xTextRange = xTextAppend->appendTextPortion(rString, aValues);
2123 }
2124 else
2125 {
2126 m_bStartedTOC = true;
2127 uno::Reference< text::XTextCursor > xTOCTextCursor = xTextAppend->getEnd()->getText( )->createTextCursor( );
2128 assert(xTOCTextCursor.is())(static_cast <bool> (xTOCTextCursor.is()) ? void (0) : __assert_fail
("xTOCTextCursor.is()", "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 2128, __extension__ __PRETTY_FUNCTION__))
;
2129 xTOCTextCursor->gotoEnd(false);
2130 if (m_nStartGenericField != 0)
2131 {
2132 xTOCTextCursor->goLeft(1, false);
2133 }
2134 xTextRange = xTextAppend->insertTextPortion(rString, aValues, xTOCTextCursor);
2135 SAL_WARN_IF(!xTextRange.is(), "writerfilter.dmapper", "insertTextPortion failed")do { if (true && (!xTextRange.is())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "writerfilter.dmapper")) { case
SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "insertTextPortion failed") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2135" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "insertTextPortion failed"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"insertTextPortion failed"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2135" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "insertTextPortion failed") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2135" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "insertTextPortion failed"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"insertTextPortion failed"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2135" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2136 if (!xTextRange.is())
2137 throw uno::Exception("insertTextPortion failed", nullptr);
2138 m_bTextInserted = true;
2139 xTOCTextCursor->gotoRange(xTextRange->getEnd(), true);
2140 if (m_nStartGenericField == 0)
2141 {
2142 m_aTextAppendStack.push(TextAppendContext(xTextAppend, xTOCTextCursor));
2143 }
2144 }
2145 }
2146 else
2147 {
2148#if !defined(MACOSX) // TODO: check layout differences and support all platforms, if needed
2149 sal_Int32 nPos = 0;
2150 OUString sFontName;
2151 OUString sDoubleSpace(" ");
2152 PropertyMapPtr pContext = GetTopContextOfType(CONTEXT_CHARACTER);
2153 // tdf#123703 workaround for longer space sequences of the old or compatible RTF documents
2154 if (GetSettingsTable()->GetLongerSpaceSequence() && !IsOpenFieldCommand() && (nPos = rString.indexOf(sDoubleSpace)) != -1 &&
2155 // monospaced fonts have no longer space sequences, regardless of \fprq2 (not monospaced) font setting
2156 // fix for the base monospaced font Courier
2157 (!pContext || !pContext->isSet(PROP_CHAR_FONT_NAME) ||
2158 ((pContext->getProperty(PROP_CHAR_FONT_NAME)->second >>= sFontName) && sFontName.indexOf("Courier") == -1)))
2159 {
2160 // an RTF space character is longer by an extra six-em-space in an old-style RTF space sequence,
2161 // insert them to keep RTF document layout formatted by consecutive spaces
2162 const sal_Unicode aExtraSpace[5] = { 0x2006, 0x20, 0x2006, 0x20, 0 };
2163 const sal_Unicode aExtraSpace2[4] = { 0x20, 0x2006, 0x20, 0 };
2164 xTextRange = xTextAppend->appendTextPortion(rString.replaceAll(sDoubleSpace, aExtraSpace, nPos)
2165 .replaceAll(sDoubleSpace, aExtraSpace2, nPos), aValues);
2166 }
2167 else
2168#endif
2169 xTextRange = xTextAppend->appendTextPortion(rString, aValues);
2170 }
2171 }
2172
2173 // reset moveFrom data of non-terminating runs of the paragraph
2174 if ( m_pParaMarkerRedlineMoveFrom )
2175 {
2176 m_pParaMarkerRedlineMoveFrom.clear();
2177 }
2178 CheckRedline( xTextRange );
2179 m_bParaChanged = true;
2180
2181 //getTableManager( ).handle(xTextRange);
2182 }
2183 catch(const lang::IllegalArgumentException&)
2184 {
2185 OSL_FAIL( "IllegalArgumentException in DomainMapper_Impl::appendTextPortion" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2185" ": "), "%s", "IllegalArgumentException in DomainMapper_Impl::appendTextPortion"
); } } while (false)
;
2186 }
2187 catch(const uno::Exception&)
2188 {
2189 OSL_FAIL( "Exception in DomainMapper_Impl::appendTextPortion" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2189" ": "), "%s", "Exception in DomainMapper_Impl::appendTextPortion"
); } } while (false)
;
2190 }
2191}
2192
2193void DomainMapper_Impl::appendTextContent(
2194 const uno::Reference< text::XTextContent >& xContent,
2195 const uno::Sequence< beans::PropertyValue >& xPropertyValues
2196 )
2197{
2198 SAL_WARN_IF(m_aTextAppendStack.empty(), "writerfilter.dmapper", "no text append stack")do { if (true && (m_aTextAppendStack.empty())) { switch
(sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "writerfilter.dmapper"
)) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "no text append stack") == 1) { ::sal_detail_log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2198" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no text append stack"), 0); } else {
::std::ostringstream sal_detail_stream; sal_detail_stream <<
"no text append stack"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2198" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "no text append stack") == 1) { ::sal_detail_log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2198" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no text append stack"), 0); } else {
::std::ostringstream sal_detail_stream; sal_detail_stream <<
"no text append stack"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2198" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2199 if (m_aTextAppendStack.empty())
2200 return;
2201 uno::Reference< text::XTextAppendAndConvert > xTextAppendAndConvert( m_aTextAppendStack.top().xTextAppend, uno::UNO_QUERY );
2202 OSL_ENSURE( xTextAppendAndConvert.is(), "trying to append a text content without XTextAppendAndConvert" )do { if (true && (!(xTextAppendAndConvert.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2202" ": "), "%s", "trying to append a text content without XTextAppendAndConvert"
); } } while (false)
;
2203 if (!xTextAppendAndConvert.is() || !hasTableManager() || getTableManager().isIgnore())
2204 return;
2205
2206 try
2207 {
2208 if (m_aTextAppendStack.top().xInsertPosition.is())
2209 xTextAppendAndConvert->insertTextContentWithProperties( xContent, xPropertyValues, m_aTextAppendStack.top().xInsertPosition );
2210 else
2211 xTextAppendAndConvert->appendTextContent( xContent, xPropertyValues );
2212 }
2213 catch(const lang::IllegalArgumentException&)
2214 {
2215 }
2216 catch(const uno::Exception&)
2217 {
2218 }
2219}
2220
2221void DomainMapper_Impl::appendOLE( const OUString& rStreamName, const std::shared_ptr<OLEHandler>& pOLEHandler )
2222{
2223 try
2224 {
2225 uno::Reference< text::XTextContent > xOLE( m_xTextFactory->createInstance("com.sun.star.text.TextEmbeddedObject"), uno::UNO_QUERY_THROW );
2226 uno::Reference< beans::XPropertySet > xOLEProperties(xOLE, uno::UNO_QUERY_THROW);
2227
2228 OUString aCLSID = pOLEHandler->getCLSID(m_xComponentContext);
2229 if (aCLSID.isEmpty())
2230 xOLEProperties->setPropertyValue(getPropertyName( PROP_STREAM_NAME ),
2231 uno::makeAny( rStreamName ));
2232 else
2233 xOLEProperties->setPropertyValue("CLSID", uno::makeAny(aCLSID));
2234
2235 OUString aDrawAspect = pOLEHandler->GetDrawAspect();
2236 if(!aDrawAspect.isEmpty())
2237 xOLEProperties->setPropertyValue("DrawAspect", uno::makeAny(aDrawAspect));
2238
2239 awt::Size aSize = pOLEHandler->getSize();
2240 if( !aSize.Width )
2241 aSize.Width = 1000;
2242 if( !aSize.Height )
2243 aSize.Height = 1000;
2244 xOLEProperties->setPropertyValue(getPropertyName( PROP_WIDTH ),
2245 uno::makeAny(aSize.Width));
2246 xOLEProperties->setPropertyValue(getPropertyName( PROP_HEIGHT ),
2247 uno::makeAny(aSize.Height));
2248
2249 OUString aVisAreaWidth = pOLEHandler->GetVisAreaWidth();
2250 if(!aVisAreaWidth.isEmpty())
2251 xOLEProperties->setPropertyValue("VisibleAreaWidth", uno::makeAny(aVisAreaWidth));
2252
2253 OUString aVisAreaHeight = pOLEHandler->GetVisAreaHeight();
2254 if(!aVisAreaHeight.isEmpty())
2255 xOLEProperties->setPropertyValue("VisibleAreaHeight", uno::makeAny(aVisAreaHeight));
2256
2257 uno::Reference< graphic::XGraphic > xGraphic = pOLEHandler->getReplacement();
2258 xOLEProperties->setPropertyValue(getPropertyName( PROP_GRAPHIC ),
2259 uno::makeAny(xGraphic));
2260 uno::Reference<beans::XPropertySet> xReplacementProperties(pOLEHandler->getShape(), uno::UNO_QUERY);
2261 if (xReplacementProperties.is())
2262 {
2263 table::BorderLine2 aBorderProps;
2264 xReplacementProperties->getPropertyValue("LineColor") >>= aBorderProps.Color;
2265 xReplacementProperties->getPropertyValue("LineWidth") >>= aBorderProps.LineWidth;
2266 xReplacementProperties->getPropertyValue("LineStyle") >>= aBorderProps.LineStyle;
2267
2268 xOLEProperties->setPropertyValue("RightBorder", uno::Any(aBorderProps));
2269 xOLEProperties->setPropertyValue("TopBorder", uno::Any(aBorderProps));
2270 xOLEProperties->setPropertyValue("LeftBorder", uno::Any(aBorderProps));
2271 xOLEProperties->setPropertyValue("BottomBorder", uno::Any(aBorderProps));
2272
2273 OUString pProperties[] = {
2274 "AnchorType",
2275 "Surround",
2276 "SurroundContour",
2277 "HoriOrient",
2278 "HoriOrientPosition",
2279 "VertOrient",
2280 "VertOrientPosition",
2281 "VertOrientRelation",
2282 "HoriOrientRelation",
2283 "LeftMargin",
2284 "RightMargin",
2285 "TopMargin",
2286 "BottomMargin",
2287 "FillStyle",
2288 "FillColor",
2289 "FillColor2",
2290 "LineStyle",
2291 };
2292 for (const OUString& s : pProperties)
2293 {
2294 const uno::Any aVal = xReplacementProperties->getPropertyValue(s);
2295 xOLEProperties->setPropertyValue(s, aVal);
2296 }
2297 }
2298 else
2299 // mimic the treatment of graphics here... it seems anchoring as character
2300 // gives a better ( visually ) result
2301 xOLEProperties->setPropertyValue(getPropertyName( PROP_ANCHOR_TYPE ), uno::makeAny( text::TextContentAnchorType_AS_CHARACTER ) );
2302 // remove ( if valid ) associated shape ( used for graphic replacement )
2303 SAL_WARN_IF(m_aAnchoredStack.empty(), "writerfilter.dmapper", "no anchor stack")do { if (true && (m_aAnchoredStack.empty())) { switch
(sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "writerfilter.dmapper"
)) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "no anchor stack") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2303" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no anchor stack"), 0); } else { ::std
::ostringstream sal_detail_stream; sal_detail_stream <<
"no anchor stack"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2303" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "no anchor stack") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2303" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no anchor stack"), 0); } else { ::std
::ostringstream sal_detail_stream; sal_detail_stream <<
"no anchor stack"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2303" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2304 if (!m_aAnchoredStack.empty())
2305 m_aAnchoredStack.top( ).bToRemove = true;
2306 RemoveLastParagraph();
2307 SAL_WARN_IF(m_aTextAppendStack.empty(), "writerfilter.dmapper", "no text stack")do { if (true && (m_aTextAppendStack.empty())) { switch
(sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "writerfilter.dmapper"
)) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "no text stack") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2307" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no text stack"), 0); } else { ::std
::ostringstream sal_detail_stream; sal_detail_stream <<
"no text stack"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2307" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "no text stack") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2307" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no text stack"), 0); } else { ::std
::ostringstream sal_detail_stream; sal_detail_stream <<
"no text stack"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2307" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2308 if (!m_aTextAppendStack.empty())
2309 m_aTextAppendStack.pop();
2310
2311 appendTextContent( xOLE, uno::Sequence< beans::PropertyValue >() );
2312
2313 if (!aCLSID.isEmpty())
2314 pOLEHandler->importStream(m_xComponentContext, GetTextDocument(), xOLE);
2315
2316 }
2317 catch( const uno::Exception& )
2318 {
2319 OSL_FAIL( "Exception in creation of OLE object" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2319" ": "), "%s", "Exception in creation of OLE object"
); } } while (false)
;
2320 }
2321
2322}
2323
2324void DomainMapper_Impl::appendStarMath( const Value& val )
2325{
2326 uno::Reference< embed::XEmbeddedObject > formula;
2327 val.getAny() >>= formula;
2328 if( !formula.is() )
2329 return;
2330
2331 try
2332 {
2333 uno::Reference< text::XTextContent > xStarMath( m_xTextFactory->createInstance("com.sun.star.text.TextEmbeddedObject"), uno::UNO_QUERY_THROW );
2334 uno::Reference< beans::XPropertySet > xStarMathProperties(xStarMath, uno::UNO_QUERY_THROW);
2335
2336 xStarMathProperties->setPropertyValue(getPropertyName( PROP_EMBEDDED_OBJECT ),
2337 val.getAny());
2338 // tdf#66405: set zero margins for embedded object
2339 xStarMathProperties->setPropertyValue(getPropertyName( PROP_LEFT_MARGIN ),
2340 uno::makeAny(sal_Int32(0)));
2341 xStarMathProperties->setPropertyValue(getPropertyName( PROP_RIGHT_MARGIN ),
2342 uno::makeAny(sal_Int32(0)));
2343 xStarMathProperties->setPropertyValue(getPropertyName( PROP_TOP_MARGIN ),
2344 uno::makeAny(sal_Int32(0)));
2345 xStarMathProperties->setPropertyValue(getPropertyName( PROP_BOTTOM_MARGIN ),
2346 uno::makeAny(sal_Int32(0)));
2347
2348 uno::Reference< uno::XInterface > xInterface( formula->getComponent(), uno::UNO_QUERY );
2349 // set zero margins for object's component
2350 uno::Reference< beans::XPropertySet > xComponentProperties( xInterface, uno::UNO_QUERY_THROW );
2351 xComponentProperties->setPropertyValue(getPropertyName( PROP_LEFT_MARGIN ),
2352 uno::makeAny(sal_Int32(0)));
2353 xComponentProperties->setPropertyValue(getPropertyName( PROP_RIGHT_MARGIN ),
2354 uno::makeAny(sal_Int32(0)));
2355 xComponentProperties->setPropertyValue(getPropertyName( PROP_TOP_MARGIN ),
2356 uno::makeAny(sal_Int32(0)));
2357 xComponentProperties->setPropertyValue(getPropertyName( PROP_BOTTOM_MARGIN ),
2358 uno::makeAny(sal_Int32(0)));
2359 Size size( 1000, 1000 );
2360 if( oox::FormulaImportBase* formulaimport = dynamic_cast< oox::FormulaImportBase* >( xInterface.get()))
2361 size = formulaimport->getFormulaSize();
2362 xStarMathProperties->setPropertyValue(getPropertyName( PROP_WIDTH ),
2363 uno::makeAny( sal_Int32(size.Width())));
2364 xStarMathProperties->setPropertyValue(getPropertyName( PROP_HEIGHT ),
2365 uno::makeAny( sal_Int32(size.Height())));
2366 xStarMathProperties->setPropertyValue(getPropertyName(PROP_ANCHOR_TYPE),
2367 uno::makeAny(text::TextContentAnchorType_AS_CHARACTER));
2368 // mimic the treatment of graphics here... it seems anchoring as character
2369 // gives a better ( visually ) result
2370 appendTextContent(xStarMath, uno::Sequence<beans::PropertyValue>());
2371 }
2372 catch( const uno::Exception& )
2373 {
2374 OSL_FAIL( "Exception in creation of StarMath object" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2374" ": "), "%s", "Exception in creation of StarMath object"
); } } while (false)
;
2375 }
2376}
2377
2378void DomainMapper_Impl::adjustLastPara(sal_Int8 nAlign)
2379{
2380 PropertyMapPtr pLastPara = GetTopContextOfType(dmapper::CONTEXT_PARAGRAPH);
2381 pLastPara->Insert(PROP_PARA_ADJUST, uno::makeAny(nAlign), true);
2382}
2383
2384uno::Reference< beans::XPropertySet > DomainMapper_Impl::appendTextSectionAfter(
2385 uno::Reference< text::XTextRange > const & xBefore )
2386{
2387 uno::Reference< beans::XPropertySet > xRet;
2388 if (m_aTextAppendStack.empty())
2389 return xRet;
2390 uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
2391 if(xTextAppend.is())
2392 {
2393 try
2394 {
2395 uno::Reference< text::XParagraphCursor > xCursor(
2396 xTextAppend->createTextCursorByRange( xBefore ), uno::UNO_QUERY_THROW);
2397 //the cursor has been moved to the end of the paragraph because of the appendTextPortion() calls
2398 xCursor->gotoStartOfParagraph( false );
2399 if (m_aTextAppendStack.top().xInsertPosition.is())
2400 xCursor->gotoRange( m_aTextAppendStack.top().xInsertPosition, true );
2401 else
2402 xCursor->gotoEnd( true );
2403 //the paragraph after this new section is already inserted
2404 xCursor->goLeft(1, true);
2405 css::uno::Reference<css::text::XTextRange> xTextRange(xCursor, css::uno::UNO_QUERY_THROW);
2406
2407 if (css::uno::Reference<css::text::XDocumentIndexesSupplier> xIndexSupplier{
2408 GetTextDocument(), css::uno::UNO_QUERY })
2409 {
2410 css::uno::Reference<css::text::XTextRangeCompare> xCompare(
2411 xTextAppend, css::uno::UNO_QUERY);
2412 const auto xIndexAccess = xIndexSupplier->getDocumentIndexes();
2413 for (sal_Int32 i = xIndexAccess->getCount(); i > 0; --i)
2414 {
2415 if (css::uno::Reference<css::text::XDocumentIndex> xIndex{
2416 xIndexAccess->getByIndex(i - 1), css::uno::UNO_QUERY })
2417 {
2418 const auto xIndexTextRange = xIndex->getAnchor();
2419 if (xCompare->compareRegionStarts(xTextRange, xIndexTextRange) == 0
2420 && xCompare->compareRegionEnds(xTextRange, xIndexTextRange) == 0)
2421 {
2422 // The boundaries coincide with an index: trying to attach a section
2423 // to the range will insert the section inside the index. goRight will
2424 // extend the range outside of the index, so that created section will
2425 // be around it. Alternatively we could return index section itself
2426 // instead : xRet.set(xIndex, uno::UNO_QUERY) - to set its properties,
2427 // like columns/fill.
2428 xCursor->goRight(1, true);
2429 break;
2430 }
2431 }
2432 }
2433 }
2434
2435 uno::Reference< text::XTextContent > xSection( m_xTextFactory->createInstance("com.sun.star.text.TextSection"), uno::UNO_QUERY_THROW );
2436 xSection->attach( xTextRange );
2437 xRet.set(xSection, uno::UNO_QUERY );
2438 }
2439 catch(const uno::Exception&)
2440 {
2441 }
2442
2443 }
2444
2445 return xRet;
2446}
2447
2448void DomainMapper_Impl::appendGlossaryEntry()
2449{
2450 appendTextSectionAfter(m_xGlossaryEntryStart);
2451}
2452
2453void DomainMapper_Impl::PushPageHeaderFooter(bool bHeader, SectionPropertyMap::PageType eType)
2454{
2455 m_bSaveParaHadField = m_bParaHadField;
2456 m_aHeaderFooterStack.push(HeaderFooterContext(m_bTextInserted, m_nTableDepth));
2457 m_bTextInserted = false;
2458 m_nTableDepth = 0;
2459
2460 const PropertyIds ePropIsOn = bHeader? PROP_HEADER_IS_ON: PROP_FOOTER_IS_ON;
2461 const PropertyIds ePropShared = bHeader? PROP_HEADER_IS_SHARED: PROP_FOOTER_IS_SHARED;
2462 const PropertyIds ePropTextLeft = bHeader? PROP_HEADER_TEXT_LEFT: PROP_FOOTER_TEXT_LEFT;
2463 const PropertyIds ePropText = bHeader? PROP_HEADER_TEXT: PROP_FOOTER_TEXT;
2464
2465 m_bDiscardHeaderFooter = true;
2466 m_eInHeaderFooterImport
2467 = bHeader ? HeaderFooterImportState::header : HeaderFooterImportState::footer;
2468
2469 //get the section context
2470 PropertyMapPtr pContext = DomainMapper_Impl::GetTopContextOfType(CONTEXT_SECTION);
2471 //ask for the header/footer name of the given type
2472 SectionPropertyMap* pSectionContext = dynamic_cast< SectionPropertyMap* >( pContext.get() );
2473 if(!pSectionContext)
2474 return;
2475
2476 // clear the "Link To Previous" flag so that the header/footer
2477 // content is not copied from the previous section
2478 pSectionContext->ClearHeaderFooterLinkToPrevious(bHeader, eType);
2479
2480 if (!m_bIsNewDoc)
2481 {
2482 return; // TODO sw cannot Undo insert header/footer without crashing
2483 }
2484
2485 uno::Reference< beans::XPropertySet > xPageStyle =
2486 pSectionContext->GetPageStyle(
2487 *this,
2488 eType == SectionPropertyMap::PAGE_FIRST );
2489 if (!xPageStyle.is())
2490 return;
2491 try
2492 {
2493 bool bLeft = eType == SectionPropertyMap::PAGE_LEFT;
2494 bool bFirst = eType == SectionPropertyMap::PAGE_FIRST;
2495 if ((!bLeft && !GetSettingsTable()->GetEvenAndOddHeaders()) || (GetSettingsTable()->GetEvenAndOddHeaders()))
2496 {
2497 //switch on header/footer use
2498 xPageStyle->setPropertyValue(
2499 getPropertyName(ePropIsOn),
2500 uno::makeAny(true));
2501
2502 // If the 'Different Even & Odd Pages' flag is turned on - do not ignore it
2503 // Even if the 'Even' header/footer is blank - the flag should be imported (so it would look in LO like in Word)
2504 if (!bFirst && GetSettingsTable()->GetEvenAndOddHeaders())
2505 xPageStyle->setPropertyValue(getPropertyName(ePropShared), uno::makeAny(false));
2506
2507 //set the interface
2508 uno::Reference< text::XText > xText;
2509 xPageStyle->getPropertyValue(getPropertyName(bLeft? ePropTextLeft: ePropText)) >>= xText;
2510
2511 m_aTextAppendStack.push(TextAppendContext(uno::Reference< text::XTextAppend >(xText, uno::UNO_QUERY_THROW),
2512 m_bIsNewDoc
2513 ? uno::Reference<text::XTextCursor>()
2514 : xText->createTextCursorByRange(xText->getStart())));
2515 m_bDiscardHeaderFooter = false; // set only on success!
2516 }
2517 }
2518 catch( const uno::Exception& )
2519 {
2520 DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper")DbgUnhandledException( DbgGetCaughtException(), __func__, "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2520" ": ", "writerfilter.dmapper" );
;
2521 }
2522}
2523
2524void DomainMapper_Impl::PushPageHeader(SectionPropertyMap::PageType eType)
2525{
2526 PushPageHeaderFooter(/* bHeader = */ true, eType);
2527}
2528
2529void DomainMapper_Impl::PushPageFooter(SectionPropertyMap::PageType eType)
2530{
2531 PushPageHeaderFooter(/* bHeader = */ false, eType);
2532}
2533
2534void DomainMapper_Impl::PopPageHeaderFooter()
2535{
2536 //header and footer always have an empty paragraph at the end
2537 //this has to be removed
2538 RemoveLastParagraph( );
2539
2540 if (!m_aTextAppendStack.empty())
2541 {
2542 if (!m_bDiscardHeaderFooter)
2543 {
2544 m_aTextAppendStack.pop();
2545 }
2546 m_bDiscardHeaderFooter = false;
2547 }
2548 m_eInHeaderFooterImport = HeaderFooterImportState::none;
2549
2550 if (!m_aHeaderFooterStack.empty())
2551 {
2552 m_bTextInserted = m_aHeaderFooterStack.top().getTextInserted();
2553 m_nTableDepth = m_aHeaderFooterStack.top().getTableDepth();
2554 m_aHeaderFooterStack.pop();
2555 }
2556
2557 m_bParaHadField = m_bSaveParaHadField;
2558}
2559
2560void DomainMapper_Impl::PushFootOrEndnote( bool bIsFootnote )
2561{
2562 SAL_WARN_IF(m_bInFootOrEndnote, "writerfilter.dmapper", "PushFootOrEndnote() is called from another foot or endnote")do { if (true && (m_bInFootOrEndnote)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "writerfilter.dmapper")) { case
SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "PushFootOrEndnote() is called from another foot or endnote"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2562" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "PushFootOrEndnote() is called from another foot or endnote"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "PushFootOrEndnote() is called from another foot or endnote"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2562" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "PushFootOrEndnote() is called from another foot or endnote"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2562" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "PushFootOrEndnote() is called from another foot or endnote"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "PushFootOrEndnote() is called from another foot or endnote"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2562" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1
Assuming field 'm_bInFootOrEndnote' is false
2
Taking false branch
3
Loop condition is false. Exiting loop
2563 m_bInFootOrEndnote = true;
2564 m_bCheckFirstFootnoteTab = true;
2565 m_bSaveFirstParagraphInCell = m_bFirstParagraphInCell;
2566 try
2567 {
2568 // Redlines outside the footnote should not affect footnote content
2569 m_aRedlines.push(std::vector< RedlineParamsPtr >());
2570
2571 // IMHO character styles from footnote labels should be ignored in the edit view of Writer.
2572 // This adds a hack on top of the following hack to save the style name in the context.
2573 PropertyMapPtr pTopContext = GetTopContext();
2574 OUString sFootnoteCharStyleName;
2575 std::optional< PropertyMap::Property > aProp = pTopContext->getProperty(PROP_CHAR_STYLE_NAME);
2576 if (aProp)
4
Assuming the condition is false
5
Taking false branch
2577 aProp->second >>= sFootnoteCharStyleName;
2578
2579 // Remove style reference, if any. This reference did appear here as a side effect of tdf#43017
2580 // Seems it is not required by LO, but causes side effects during editing. So remove it
2581 // for footnotes/endnotes to restore original LO behavior here.
2582 pTopContext->Erase(PROP_CHAR_STYLE_NAME);
2583
2584 uno::Reference< text::XText > xFootnoteText;
2585 if (GetTextFactory().is())
6
Taking true branch
2586 xFootnoteText.set( GetTextFactory()->createInstance(
2587 bIsFootnote ?
7
Assuming 'bIsFootnote' is true
8
'?' condition is true
2588 OUString( "com.sun.star.text.Footnote" ) : OUString( "com.sun.star.text.Endnote" )),
2589 uno::UNO_QUERY_THROW );
2590 uno::Reference< text::XFootnote > xFootnote( xFootnoteText, uno::UNO_QUERY_THROW );
2591 pTopContext->SetFootnote(xFootnote, sFootnoteCharStyleName);
2592 uno::Sequence< beans::PropertyValue > aFontProperties = pTopContext->GetPropertyValues();
2593 appendTextContent( uno::Reference< text::XTextContent >( xFootnoteText, uno::UNO_QUERY_THROW ), aFontProperties );
2594 m_aTextAppendStack.push(TextAppendContext(uno::Reference< text::XTextAppend >( xFootnoteText, uno::UNO_QUERY_THROW ),
2595 xFootnoteText->createTextCursorByRange(xFootnoteText->getStart())));
2596
2597 // Redlines for the footnote anchor in the main text content
2598 std::vector< RedlineParamsPtr > aFootnoteRedline = std::move(m_aRedlines.top());
2599 m_aRedlines.pop();
2600 CheckRedline( xFootnote->getAnchor( ) );
2601 m_aRedlines.push( aFootnoteRedline );
2602
2603 // Try scanning for custom footnote labels
2604 if (!sFootnoteCharStyleName.isEmpty())
9
Taking true branch
2605 StartCustomFootnote(pTopContext);
10
Calling '~SvRef'
19
Returning from '~SvRef'
2606 else
2607 EndCustomFootnote();
2608 }
20
Calling '~SvRef'
2609 catch( const uno::Exception& )
2610 {
2611 TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "PushFootOrEndnote")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "PushFootOrEndnote"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2611" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "PushFootOrEndnote" << " " <<
exceptionToString(tools_warn_exception)), 0); } else { ::std
::ostringstream sal_detail_stream; sal_detail_stream <<
"PushFootOrEndnote" << " " << exceptionToString(
tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2611" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "PushFootOrEndnote" << " " << exceptionToString
(tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2611" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "PushFootOrEndnote" << " " <<
exceptionToString(tools_warn_exception)), 0); } else { ::std
::ostringstream sal_detail_stream; sal_detail_stream <<
"PushFootOrEndnote" << " " << exceptionToString(
tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2611" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
2612 }
2613}
2614
2615void DomainMapper_Impl::CreateRedline(uno::Reference<text::XTextRange> const& xRange,
2616 const RedlineParamsPtr& pRedline)
2617{
2618 if ( !pRedline )
2619 return;
2620
2621 try
2622 {
2623 OUString sType;
2624 switch ( pRedline->m_nToken & 0xffff )
2625 {
2626 case XML_mod:
2627 sType = getPropertyName( PROP_FORMAT );
2628 break;
2629 case XML_moveTo:
2630 case XML_ins:
2631 sType = getPropertyName( PROP_INSERT );
2632 break;
2633 case XML_moveFrom:
2634 m_pParaMarkerRedlineMoveFrom = pRedline.get();
2635 [[fallthrough]];
2636 case XML_del:
2637 sType = getPropertyName( PROP_DELETE );
2638 break;
2639 case XML_ParagraphFormat:
2640 sType = getPropertyName( PROP_PARAGRAPH_FORMAT );
2641 break;
2642 default:
2643 throw lang::IllegalArgumentException("illegal redline token type", nullptr, 0);
2644 }
2645 beans::PropertyValues aRedlineProperties( 3 );
2646 beans::PropertyValue * pRedlineProperties = aRedlineProperties.getArray( );
2647 pRedlineProperties[0].Name = getPropertyName( PROP_REDLINE_AUTHOR );
2648 pRedlineProperties[0].Value <<= pRedline->m_sAuthor;
2649 pRedlineProperties[1].Name = getPropertyName( PROP_REDLINE_DATE_TIME );
2650 pRedlineProperties[1].Value <<= ConversionHelper::ConvertDateStringToDateTime( pRedline->m_sDate );
2651 pRedlineProperties[2].Name = getPropertyName( PROP_REDLINE_REVERT_PROPERTIES );
2652 pRedlineProperties[2].Value <<= pRedline->m_aRevertProperties;
2653 if (!m_bIsActualParagraphFramed)
2654 {
2655 uno::Reference < text::XRedline > xRedline( xRange, uno::UNO_QUERY_THROW );
2656 xRedline->makeRedline( sType, aRedlineProperties );
2657 }
2658 // store frame and (possible floating) table redline data for restoring them after frame conversion
2659 if (m_bIsActualParagraphFramed || (hasTableManager() && getTableManager().isInTable()))
2660 {
2661 aFramedRedlines.push_back( uno::makeAny(xRange) );
2662 aFramedRedlines.push_back( uno::makeAny(sType) );
2663 aFramedRedlines.push_back( uno::makeAny(aRedlineProperties) );
2664 }
2665 }
2666 catch( const uno::Exception & )
2667 {
2668 OSL_FAIL( "Exception in makeRedline" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2668" ": "), "%s", "Exception in makeRedline"); } } while
(false)
;
2669 }
2670}
2671
2672void DomainMapper_Impl::CheckParaMarkerRedline( uno::Reference< text::XTextRange > const& xRange )
2673{
2674 if ( m_pParaMarkerRedline )
2675 {
2676 CreateRedline( xRange, m_pParaMarkerRedline );
2677 if ( m_pParaMarkerRedline )
2678 {
2679 m_pParaMarkerRedline.clear();
2680 m_currentRedline.clear();
2681 }
2682 }
2683 else if ( m_pParaMarkerRedlineMoveFrom )
2684 {
2685 // terminating moveFrom redline removes also the paragraph mark
2686 m_pParaMarkerRedlineMoveFrom->m_nToken = XML_del;
2687 CreateRedline( xRange, m_pParaMarkerRedlineMoveFrom );
2688 }
2689 if ( m_pParaMarkerRedlineMoveFrom )
2690 {
2691 m_pParaMarkerRedlineMoveFrom.clear();
2692 }
2693}
2694
2695void DomainMapper_Impl::CheckRedline( uno::Reference< text::XTextRange > const& xRange )
2696{
2697 // Writer core "officially" does not like overlapping redlines, and its UNO interface is stupid enough
2698 // to not prevent that. However, in practice in fact everything appears to work fine (except for the debug warnings
2699 // about redline table corruption, which may possibly be harmless in reality). So leave this as it is, since this
2700 // is a better representation of how the changes happened. If this will ever become a problem, overlapping redlines
2701 // will need to be merged into one, just like doing the changes in the UI does, which will lose some information
2702 // (and so if that happens, it may be better to fix Writer).
2703 // Create the redlines here from lowest (formats) to highest (inserts/removals) priority, since the last one is
2704 // what Writer presents graphically, so this will show deletes as deleted text and not as just formatted text being there.
2705 bool bUsedRange = m_aRedlines.top().size() > 0 || (GetTopContextOfType(CONTEXT_CHARACTER) &&
2706 GetTopContextOfType(CONTEXT_CHARACTER)->Redlines().size() > 0);
2707
2708 // only export ParagraphFormat, when there is no other redline in the same text portion to avoid missing redline compression,
2709 // but always export the first ParagraphFormat redline in a paragraph to keep the paragraph style change data for rejection
2710 if( (!bUsedRange || !m_bParaChanged) && GetTopContextOfType(CONTEXT_PARAGRAPH) )
2711 {
2712 std::vector<RedlineParamsPtr>& avRedLines = GetTopContextOfType(CONTEXT_PARAGRAPH)->Redlines();
2713 for( const auto& rRedline : avRedLines )
2714 CreateRedline( xRange, rRedline );
2715 }
2716 if( GetTopContextOfType(CONTEXT_CHARACTER) )
2717 {
2718 std::vector<RedlineParamsPtr>& avRedLines = GetTopContextOfType(CONTEXT_CHARACTER)->Redlines();
2719 for( const auto& rRedline : avRedLines )
2720 CreateRedline( xRange, rRedline );
2721 }
2722 for (const auto& rRedline : m_aRedlines.top() )
2723 CreateRedline( xRange, rRedline );
2724}
2725
2726void DomainMapper_Impl::StartParaMarkerChange( )
2727{
2728 m_bIsParaMarkerChange = true;
2729}
2730
2731void DomainMapper_Impl::EndParaMarkerChange( )
2732{
2733 m_bIsParaMarkerChange = false;
2734 m_previousRedline = m_currentRedline;
2735 m_currentRedline.clear();
2736}
2737
2738void DomainMapper_Impl::StartCustomFootnote(const PropertyMapPtr pContext)
2739{
2740 if (pContext == m_pFootnoteContext)
2741 return;
2742
2743 assert(pContext->GetFootnote().is())(static_cast <bool> (pContext->GetFootnote().is()) ?
void (0) : __assert_fail ("pContext->GetFootnote().is()",
"/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 2743, __extension__ __PRETTY_FUNCTION__))
;
2744 m_bHasFootnoteStyle = true;
2745 m_bCheckFootnoteStyle = !pContext->GetFootnoteStyle().isEmpty();
2746 m_pFootnoteContext = pContext;
2747}
2748
2749void DomainMapper_Impl::EndCustomFootnote()
2750{
2751 m_bHasFootnoteStyle = false;
2752 m_bCheckFootnoteStyle = false;
2753}
2754
2755void DomainMapper_Impl::PushAnnotation()
2756{
2757 try
2758 {
2759 m_bIsInComments = true;
2760 if (!GetTextFactory().is())
2761 return;
2762 m_xAnnotationField.set( GetTextFactory()->createInstance( "com.sun.star.text.TextField.Annotation" ),
2763 uno::UNO_QUERY_THROW );
2764 uno::Reference< text::XText > xAnnotationText;
2765 m_xAnnotationField->getPropertyValue("TextRange") >>= xAnnotationText;
2766 m_aTextAppendStack.push(TextAppendContext(uno::Reference< text::XTextAppend >( xAnnotationText, uno::UNO_QUERY_THROW ),
2767 m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : xAnnotationText->createTextCursorByRange(xAnnotationText->getStart())));
2768 }
2769 catch( const uno::Exception&)
2770 {
2771 DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper")DbgUnhandledException( DbgGetCaughtException(), __func__, "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2771" ": ", "writerfilter.dmapper" );
;
2772 }
2773}
2774
2775
2776void DomainMapper_Impl::PopFootOrEndnote()
2777{
2778 if (!IsRTFImport())
2779 RemoveLastParagraph();
2780
2781 // In case the foot or endnote did not contain a tab.
2782 m_bIgnoreNextTab = false;
2783
2784 if (!m_aTextAppendStack.empty())
2785 m_aTextAppendStack.pop();
2786
2787 if (m_aRedlines.size() == 1)
2788 {
2789 SAL_WARN("writerfilter.dmapper", "PopFootOrEndnote() is called without PushFootOrEndnote()?")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "PopFootOrEndnote() is called without PushFootOrEndnote()?"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2789" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "PopFootOrEndnote() is called without PushFootOrEndnote()?"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "PopFootOrEndnote() is called without PushFootOrEndnote()?"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2789" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "PopFootOrEndnote() is called without PushFootOrEndnote()?"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2789" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "PopFootOrEndnote() is called without PushFootOrEndnote()?"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "PopFootOrEndnote() is called without PushFootOrEndnote()?"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2789" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2790 return;
2791 }
2792 m_aRedlines.pop();
2793 m_eSkipFootnoteState = SkipFootnoteSeparator::OFF;
2794 m_bInFootOrEndnote = false;
2795 m_pFootnoteContext = nullptr;
2796 m_bFirstParagraphInCell = m_bSaveFirstParagraphInCell;
2797}
2798
2799void DomainMapper_Impl::PopAnnotation()
2800{
2801 RemoveLastParagraph();
2802
2803 m_bIsInComments = false;
2804 m_aTextAppendStack.pop();
2805
2806 try
2807 {
2808 // See if the annotation will be a single position or a range.
2809 if (m_nAnnotationId == -1 || !m_aAnnotationPositions[m_nAnnotationId].m_xStart.is() || !m_aAnnotationPositions[m_nAnnotationId].m_xEnd.is())
2810 {
2811 uno::Sequence< beans::PropertyValue > aEmptyProperties;
2812 uno::Reference< text::XTextContent > xContent( m_xAnnotationField, uno::UNO_QUERY_THROW );
2813 appendTextContent( xContent, aEmptyProperties );
2814 CheckRedline( xContent->getAnchor( ) );
2815 }
2816 else
2817 {
2818 AnnotationPosition& aAnnotationPosition = m_aAnnotationPositions[m_nAnnotationId];
2819 // Create a range that points to the annotation start/end.
2820 uno::Reference<text::XText> const xText = aAnnotationPosition.m_xStart->getText();
2821 uno::Reference<text::XTextCursor> const xCursor = xText->createTextCursorByRange(aAnnotationPosition.m_xStart);
2822
2823 bool bMarker = false;
2824 uno::Reference<text::XTextRangeCompare> xTextRangeCompare(xText, uno::UNO_QUERY);
2825 if (xTextRangeCompare->compareRegionStarts(aAnnotationPosition.m_xStart, aAnnotationPosition.m_xEnd) == 0)
2826 {
2827 // Insert a marker so that comment around an anchored image is not collapsed during
2828 // insertion.
2829 xText->insertString(xCursor, "x", false);
2830 bMarker = true;
2831 }
2832
2833 xCursor->gotoRange(aAnnotationPosition.m_xEnd, true);
2834 uno::Reference<text::XTextRange> const xTextRange(xCursor, uno::UNO_QUERY_THROW);
2835
2836 // Attach the annotation to the range.
2837 uno::Reference<text::XTextAppend> const xTextAppend = m_aTextAppendStack.top().xTextAppend;
2838 xTextAppend->insertTextContent(xTextRange, uno::Reference<text::XTextContent>(m_xAnnotationField, uno::UNO_QUERY_THROW), !xCursor->isCollapsed());
2839
2840 if (bMarker)
2841 {
2842 // Remove the marker.
2843 xCursor->goLeft(1, true);
2844 xCursor->setString(OUString());
2845 }
2846 }
2847 m_aAnnotationPositions.erase( m_nAnnotationId );
2848 }
2849 catch (uno::Exception const&)
2850 {
2851 TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "Cannot insert annotation field")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Cannot insert annotation field"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2851" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Cannot insert annotation field" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Cannot insert annotation field" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2851" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Cannot insert annotation field" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2851" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Cannot insert annotation field" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Cannot insert annotation field" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2851" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
2852 }
2853
2854 m_xAnnotationField.clear();
2855 m_nAnnotationId = -1;
2856}
2857
2858void DomainMapper_Impl::PushPendingShape( const uno::Reference< drawing::XShape > & xShape )
2859{
2860 m_aPendingShapes.push_back(xShape);
2861}
2862
2863uno::Reference<drawing::XShape> DomainMapper_Impl::PopPendingShape()
2864{
2865 uno::Reference<drawing::XShape> xRet;
2866 if (!m_aPendingShapes.empty())
2867 {
2868 xRet = m_aPendingShapes.front();
2869 m_aPendingShapes.pop_front();
2870 }
2871 return xRet;
2872}
2873
2874void DomainMapper_Impl::PushShapeContext( const uno::Reference< drawing::XShape > & xShape )
2875{
2876 // Append these early, so the context and the table manager stack will be
2877 // in sync, even if the text append stack is empty.
2878 appendTableManager();
2879 appendTableHandler();
2880 getTableManager().startLevel();
2881
2882 if (m_aTextAppendStack.empty())
2883 return;
2884 uno::Reference<text::XTextAppend> xTextAppend = m_aTextAppendStack.top().xTextAppend;
2885
2886 try
2887 {
2888 uno::Reference< lang::XServiceInfo > xSInfo( xShape, uno::UNO_QUERY_THROW );
2889 if (xSInfo->supportsService("com.sun.star.drawing.GroupShape"))
2890 {
2891 // Textboxes in shapes do not support styles, so check saved style information and apply properties directly to the child shapes.
2892 const uno::Reference<drawing::XShapes> xShapes(xShape, uno::UNO_QUERY);
2893 const sal_uInt32 nShapeCount = xShapes.is() ? xShapes->getCount() : 0;
2894 for ( sal_uInt32 i = 0; i < nShapeCount; ++i )
2895 {
2896 try
2897 {
2898 uno::Reference<beans::XPropertySet> xSyncedPropertySet(xShapes->getByIndex(i), uno::UNO_QUERY_THROW);
2899 comphelper::SequenceAsHashMap aGrabBag( xSyncedPropertySet->getPropertyValue("CharInteropGrabBag") );
2900
2901 // only VML import has checked for style. Don't apply default parastyle properties to other imported shapes
2902 // - except for fontsize - to maintain compatibility with previous versions of LibreOffice.
2903 const bool bOnlyApplyCharHeight = !aGrabBag["mso-pStyle"].hasValue();
2904
2905 OUString sStyleName;
2906 aGrabBag["mso-pStyle"] >>= sStyleName;
2907 StyleSheetEntryPtr pEntry = GetStyleSheetTable()->FindStyleSheetByISTD( sStyleName );
2908 if ( !pEntry )
2909 {
2910 // Use default style even in ambiguous cases (where multiple styles were defined) since MOST styles inherit
2911 // MOST of their properties from the default style. In the ambiguous case, we have to accept some kind of compromise
2912 // and the default paragraph style ought to be the safest one... (compared to DocDefaults or program defaults)
2913 pEntry = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName( GetDefaultParaStyleName() );
2914 }
2915 if ( pEntry )
2916 {
2917 // The Ids here come from oox/source/vml/vmltextbox.cxx.
2918 // It probably could safely expand to all Ids that shapes support.
2919 const PropertyIds eIds[] = {
2920 PROP_CHAR_HEIGHT,
2921 PROP_CHAR_FONT_NAME,
2922 PROP_CHAR_WEIGHT,
2923 PROP_CHAR_CHAR_KERNING,
2924 PROP_CHAR_COLOR,
2925 PROP_PARA_ADJUST
2926 };
2927 const uno::Reference<beans::XPropertyState> xSyncedPropertyState(xSyncedPropertySet, uno::UNO_QUERY_THROW);
2928 for ( const auto& eId : eIds )
2929 {
2930 try
2931 {
2932 if ( bOnlyApplyCharHeight && eId != PROP_CHAR_HEIGHT )
2933 continue;
2934
2935 const OUString sPropName = getPropertyName(eId);
2936 if ( beans::PropertyState_DEFAULT_VALUE == xSyncedPropertyState->getPropertyState(sPropName) )
2937 {
2938 const uno::Any aProp = GetPropertyFromStyleSheet(eId, pEntry, /*bDocDefaults=*/true, /*bPara=*/true);
2939 if ( aProp.hasValue() )
2940 xSyncedPropertySet->setPropertyValue( sPropName, aProp );
2941 }
2942 }
2943 catch (const uno::Exception&)
2944 {
2945 TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "PushShapeContext() text stylesheet property exception" )do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "PushShapeContext() text stylesheet property exception"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2945" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "PushShapeContext() text stylesheet property exception"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "PushShapeContext() text stylesheet property exception"
<< " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2945" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "PushShapeContext() text stylesheet property exception"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2945" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "PushShapeContext() text stylesheet property exception"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "PushShapeContext() text stylesheet property exception"
<< " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2945" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
2946 }
2947 }
2948 }
2949 }
2950 catch (const uno::Exception&)
2951 {
2952 TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "PushShapeContext()" )do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "PushShapeContext()"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2952" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "PushShapeContext()" << " " <<
exceptionToString(tools_warn_exception)), 0); } else { ::std
::ostringstream sal_detail_stream; sal_detail_stream <<
"PushShapeContext()" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2952" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "PushShapeContext()" << " " << exceptionToString
(tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2952" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "PushShapeContext()" << " " <<
exceptionToString(tools_warn_exception)), 0); } else { ::std
::ostringstream sal_detail_stream; sal_detail_stream <<
"PushShapeContext()" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "2952" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
2953 }
2954 }
2955
2956 // A GroupShape doesn't implement text::XTextRange, but appending
2957 // an empty reference to the stacks still makes sense, because this
2958 // way bToRemove can be set, and we won't end up with duplicated
2959 // shapes for OLE objects.
2960 m_aTextAppendStack.push(TextAppendContext(uno::Reference<text::XTextAppend>(xShape, uno::UNO_QUERY), uno::Reference<text::XTextCursor>()));
2961 uno::Reference<text::XTextContent> xTxtContent(xShape, uno::UNO_QUERY);
2962 m_aAnchoredStack.push(AnchoredContext(xTxtContent));
2963 }
2964 else if (xSInfo->supportsService("com.sun.star.drawing.OLE2Shape"))
2965 {
2966 // OLE2Shape from oox should be converted to a TextEmbeddedObject for sw.
2967 m_aTextAppendStack.push(TextAppendContext(uno::Reference<text::XTextAppend>(xShape, uno::UNO_QUERY), uno::Reference<text::XTextCursor>()));
2968 uno::Reference<text::XTextContent> xTextContent(xShape, uno::UNO_QUERY);
2969 m_aAnchoredStack.push(AnchoredContext(xTextContent));
2970 uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
2971
2972 m_xEmbedded.set(m_xTextFactory->createInstance("com.sun.star.text.TextEmbeddedObject"), uno::UNO_QUERY_THROW);
2973 uno::Reference<beans::XPropertySet> xEmbeddedProperties(m_xEmbedded, uno::UNO_QUERY_THROW);
2974 xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_EMBEDDED_OBJECT), xShapePropertySet->getPropertyValue(getPropertyName(PROP_EMBEDDED_OBJECT)));
2975 xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_ANCHOR_TYPE), uno::makeAny(text::TextContentAnchorType_AS_CHARACTER));
2976 // So that the original bitmap-only shape will be replaced by the embedded object.
2977 m_aAnchoredStack.top().bToRemove = true;
2978 m_aTextAppendStack.pop();
2979 appendTextContent(m_xEmbedded, uno::Sequence<beans::PropertyValue>());
2980 }
2981 else
2982 {
2983 uno::Reference< text::XTextRange > xShapeText( xShape, uno::UNO_QUERY_THROW);
2984 // Add the shape to the text append stack
2985 m_aTextAppendStack.push( TextAppendContext(uno::Reference< text::XTextAppend >( xShape, uno::UNO_QUERY_THROW ),
2986 m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : m_xBodyText->createTextCursorByRange(xShapeText->getStart() )));
2987
2988 // Add the shape to the anchored objects stack
2989 uno::Reference< text::XTextContent > xTxtContent( xShape, uno::UNO_QUERY_THROW );
2990 m_aAnchoredStack.push( AnchoredContext(xTxtContent) );
2991
2992 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW );
2993#ifdef DBG_UTIL
2994 TagLogger::getInstance().unoPropertySet(xProps);
2995#endif
2996 text::TextContentAnchorType nAnchorType(text::TextContentAnchorType_AT_PARAGRAPH);
2997 xProps->getPropertyValue(getPropertyName( PROP_ANCHOR_TYPE )) >>= nAnchorType;
2998 bool checkZOrderStatus = false;
2999 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
3000 {
3001 SetIsTextFrameInserted(true);
3002 // Extract the special "btLr text frame" mode, requested by oox, if needed.
3003 // Extract vml ZOrder from FrameInteropGrabBag
3004 uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
3005 uno::Sequence<beans::PropertyValue> aGrabBag;
3006 xShapePropertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
3007
3008 for (const auto& rProp : std::as_const(aGrabBag))
3009 {
3010 if (rProp.Name == "VML-Z-ORDER")
3011 {
3012 GraphicZOrderHelper* pZOrderHelper = m_rDMapper.graphicZOrderHelper();
3013 sal_Int32 zOrder(0);
3014 rProp.Value >>= zOrder;
3015 xShapePropertySet->setPropertyValue( "ZOrder", uno::makeAny(pZOrderHelper->findZOrder(zOrder)));
3016 pZOrderHelper->addItem(xShapePropertySet, zOrder);
3017 xShapePropertySet->setPropertyValue(getPropertyName( PROP_OPAQUE ), uno::makeAny( zOrder >= 0 ) );
3018 checkZOrderStatus = true;
3019 }
3020 else if ( rProp.Name == "TxbxHasLink" )
3021 {
3022 //Chaining of textboxes will happen in ~DomainMapper_Impl
3023 //i.e when all the textboxes are read and all its attributes
3024 //have been set ( basically the Name/LinkedDisplayName )
3025 //which is set in Graphic Import.
3026 m_vTextFramesForChaining.push_back(xShape);
3027 }
3028 }
3029
3030 uno::Reference<text::XTextContent> xTextContent(xShape, uno::UNO_QUERY_THROW);
3031 uno::Reference<text::XTextRange> xTextRange(xTextAppend->createTextCursorByRange(xTextAppend->getEnd()), uno::UNO_QUERY_THROW);
3032 xTextAppend->insertTextContent(xTextRange, xTextContent, false);
3033
3034 uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
3035 // we need to re-set this value to xTextContent, then only values are preserved.
3036 xPropertySet->setPropertyValue("FrameInteropGrabBag",uno::makeAny(aGrabBag));
3037 }
3038 else if (nAnchorType == text::TextContentAnchorType_AS_CHARACTER)
3039 {
3040 // Fix spacing for as-character objects. If the paragraph has CT_Spacing_after set,
3041 // it needs to be set on the object too, as that's what object placement code uses.
3042 PropertyMapPtr paragraphContext = GetTopContextOfType( CONTEXT_PARAGRAPH );
3043 std::optional<PropertyMap::Property> aPropMargin = paragraphContext->getProperty(PROP_PARA_BOTTOM_MARGIN);
3044 if(aPropMargin)
3045 xProps->setPropertyValue( getPropertyName( PROP_BOTTOM_MARGIN ), aPropMargin->second );
3046 }
3047 else
3048 {
3049 uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
3050 uno::Sequence<beans::PropertyValue> aGrabBag;
3051 xShapePropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
3052 for (const auto& rProp : std::as_const(aGrabBag))
3053 {
3054 if (rProp.Name == "VML-Z-ORDER")
3055 {
3056 GraphicZOrderHelper* pZOrderHelper = m_rDMapper.graphicZOrderHelper();
3057 sal_Int32 zOrder(0);
3058 rProp.Value >>= zOrder;
3059 xShapePropertySet->setPropertyValue( "ZOrder", uno::makeAny(pZOrderHelper->findZOrder(zOrder)));
3060 pZOrderHelper->addItem(xShapePropertySet, zOrder);
3061 xShapePropertySet->setPropertyValue(getPropertyName( PROP_OPAQUE ), uno::makeAny( zOrder >= 0 ) );
3062 checkZOrderStatus = true;
3063 }
3064 else if ( rProp.Name == "TxbxHasLink" )
3065 {
3066 //Chaining of textboxes will happen in ~DomainMapper_Impl
3067 //i.e when all the textboxes are read and all its attributes
3068 //have been set ( basically the Name/LinkedDisplayName )
3069 //which is set in Graphic Import.
3070 m_vTextFramesForChaining.push_back(xShape);
3071 }
3072 }
3073
3074 if(IsSdtEndBefore())
3075 {
3076 uno::Reference< beans::XPropertySetInfo > xPropSetInfo;
3077 if(xShapePropertySet.is())
3078 {
3079 xPropSetInfo = xShapePropertySet->getPropertySetInfo();
3080 if (xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("InteropGrabBag"))
3081 {
3082 uno::Sequence<beans::PropertyValue> aShapeGrabBag( comphelper::InitPropertySequence({
3083 { "SdtEndBefore", uno::Any(true) }
3084 }));
3085 xShapePropertySet->setPropertyValue("InteropGrabBag",uno::makeAny(aShapeGrabBag));
3086 }
3087 }
3088 }
3089 }
3090 if (!IsInHeaderFooter() && !checkZOrderStatus)
3091 xProps->setPropertyValue(
3092 getPropertyName( PROP_OPAQUE ),
3093 uno::makeAny( true ) );
3094 }
3095 m_bParaChanged = true;
3096 getTableManager().setIsInShape(true);
3097 }
3098 catch ( const uno::Exception& )
3099 {
3100 TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "Exception when adding shape")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Exception when adding shape"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3100" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Exception when adding shape" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Exception when adding shape" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3100" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Exception when adding shape" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3100" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Exception when adding shape" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Exception when adding shape" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3100" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
3101 }
3102}
3103/*
3104 * Updating chart height and width after reading the actual values from wp:extent
3105*/
3106void DomainMapper_Impl::UpdateEmbeddedShapeProps(const uno::Reference< drawing::XShape > & xShape)
3107{
3108 if (!xShape.is())
3109 return;
3110
3111 uno::Reference<beans::XPropertySet> xEmbeddedProperties(m_xEmbedded, uno::UNO_QUERY_THROW);
3112 awt::Size aSize = xShape->getSize( );
3113 xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_WIDTH), uno::makeAny(sal_Int32(aSize.Width)));
3114 xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_HEIGHT), uno::makeAny(sal_Int32(aSize.Height)));
3115}
3116
3117
3118void DomainMapper_Impl::PopShapeContext()
3119{
3120 if (hasTableManager())
3121 {
3122 getTableManager().endLevel();
3123 popTableManager();
3124 }
3125 if ( m_aAnchoredStack.empty() )
3126 return;
3127
3128 // For OLE object replacement shape, the text append context was already removed
3129 // or the OLE object couldn't be inserted.
3130 if ( !m_aAnchoredStack.top().bToRemove )
3131 {
3132 RemoveLastParagraph();
3133 if (!m_aTextAppendStack.empty())
3134 m_aTextAppendStack.pop();
3135 }
3136
3137 uno::Reference< text::XTextContent > xObj = m_aAnchoredStack.top( ).xTextContent;
3138 try
3139 {
3140 appendTextContent( xObj, uno::Sequence< beans::PropertyValue >() );
3141 }
3142 catch ( const uno::RuntimeException& )
3143 {
3144 // this is normal: the shape is already attached
3145 }
3146
3147 const uno::Reference<drawing::XShape> xShape( xObj, uno::UNO_QUERY_THROW );
3148 // Remove the shape if required (most likely replacement shape for OLE object)
3149 // or anchored to a discarded header or footer
3150 if ( m_aAnchoredStack.top().bToRemove || m_bDiscardHeaderFooter )
3151 {
3152 try
3153 {
3154 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(m_xTextDocument, uno::UNO_QUERY_THROW);
3155 uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
3156 if ( xDrawPage.is() )
3157 xDrawPage->remove( xShape );
3158 }
3159 catch( const uno::Exception& )
3160 {
3161 }
3162 }
3163
3164 // Relative width calculations deferred until section's margins are defined.
3165 // Being cautious: only deferring undefined/minimum-width shapes in order to avoid causing potential regressions
3166 css::awt::Size aShapeSize;
3167 try
3168 {
3169 aShapeSize = xShape->getSize();
3170 }
3171 catch (const css::uno::RuntimeException& e)
3172 {
3173 // May happen e.g. when text frame has no frame format
3174 // See sw/qa/extras/ooxmlimport/data/n779627.docx
3175 SAL_WARN("writerfilter.dmapper", "getSize failed. " << e.Message)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "getSize failed. "
<< e.Message) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3175" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getSize failed. " << e.Message
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "getSize failed. " << e.Message; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3175" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "getSize failed. " << e.Message) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3175" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getSize failed. " << e.Message
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "getSize failed. " << e.Message; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3175" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3176 }
3177 if( aShapeSize.Width <= 2 )
3178 {
3179 const uno::Reference<beans::XPropertySet> xShapePropertySet( xShape, uno::UNO_QUERY );
3180 SectionPropertyMap* pSectionContext = GetSectionContext();
3181 if ( pSectionContext && (!hasTableManager() || !getTableManager().isInTable()) &&
3182 xShapePropertySet->getPropertySetInfo()->hasPropertyByName(getPropertyName(PROP_RELATIVE_WIDTH)) )
3183 {
3184 pSectionContext->addRelativeWidthShape(xShape);
3185 }
3186 }
3187
3188 m_aAnchoredStack.pop();
3189}
3190
3191bool DomainMapper_Impl::IsSdtEndBefore()
3192{
3193 bool bIsSdtEndBefore = false;
3194 PropertyMapPtr pContext = GetTopContextOfType(CONTEXT_CHARACTER);
3195 if(pContext)
3196 {
3197 const uno::Sequence< beans::PropertyValue > currentCharProps = pContext->GetPropertyValues();
3198 for (const auto& rCurrentCharProp : currentCharProps)
3199 {
3200 if (rCurrentCharProp.Name == "CharInteropGrabBag")
3201 {
3202 uno::Sequence<beans::PropertyValue> aCharGrabBag;
3203 rCurrentCharProp.Value >>= aCharGrabBag;
3204 for (const auto& rProp : std::as_const(aCharGrabBag))
3205 {
3206 if(rProp.Name == "SdtEndBefore")
3207 {
3208 rProp.Value >>= bIsSdtEndBefore;
3209 }
3210 }
3211 }
3212 }
3213 }
3214 return bIsSdtEndBefore;
3215}
3216
3217bool DomainMapper_Impl::IsDiscardHeaderFooter() const
3218{
3219 return m_bDiscardHeaderFooter;
3220}
3221
3222// called from TableManager::closeCell()
3223void DomainMapper_Impl::ClearPreviousParagraph()
3224{
3225 // in table cells, set bottom auto margin of last paragraph to 0, except in paragraphs with numbering
3226 if ((m_nTableDepth == (m_nTableCellDepth + 1))
3227 && m_xPreviousParagraph.is()
3228 && hasTableManager() && getTableManager().isCellLastParaAfterAutospacing())
3229 {
3230 uno::Reference<container::XNamed> xPreviousNumberingRules(m_xPreviousParagraph->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
3231 if ( !xPreviousNumberingRules.is() || xPreviousNumberingRules->getName().isEmpty() )
3232 m_xPreviousParagraph->setPropertyValue("ParaBottomMargin", uno::makeAny(static_cast<sal_Int32>(0)));
3233 }
3234
3235 m_xPreviousParagraph.clear();
3236
3237 // next table paragraph will be first paragraph in a cell
3238 m_bFirstParagraphInCell = true;
3239}
3240
3241static sal_Int16 lcl_ParseNumberingType( const OUString& rCommand )
3242{
3243 sal_Int16 nRet = style::NumberingType::PAGE_DESCRIPTOR;
3244
3245 // The command looks like: " PAGE \* Arabic "
3246 // tdf#132185: but may as well be "PAGE \* Arabic"
3247 OUString sNumber;
3248 constexpr OUStringLiteral rSeparator(u"\\* ");
3249 if (sal_Int32 nStartIndex = rCommand.indexOf(rSeparator); nStartIndex >= 0)
3250 {
3251 nStartIndex += rSeparator.getLength();
3252 sNumber = rCommand.getToken(0, ' ', nStartIndex);
3253 }
3254
3255 if( !sNumber.isEmpty() )
3256 {
3257 //todo: might make sense to hash this list, too
3258 struct NumberingPairs
3259 {
3260 const char* cWordName;
3261 sal_Int16 nType;
3262 };
3263 static const NumberingPairs aNumberingPairs[] =
3264 {
3265 {"Arabic", style::NumberingType::ARABIC}
3266 ,{"ROMAN", style::NumberingType::ROMAN_UPPER}
3267 ,{"roman", style::NumberingType::ROMAN_LOWER}
3268 ,{"ALPHABETIC", style::NumberingType::CHARS_UPPER_LETTER}
3269 ,{"alphabetic", style::NumberingType::CHARS_LOWER_LETTER}
3270 ,{"CircleNum", style::NumberingType::CIRCLE_NUMBER}
3271 ,{"ThaiArabic", style::NumberingType::CHARS_THAI}
3272 ,{"ThaiCardText", style::NumberingType::CHARS_THAI}
3273 ,{"ThaiLetter", style::NumberingType::CHARS_THAI}
3274// ,{"SBCHAR", style::NumberingType::}
3275// ,{"DBCHAR", style::NumberingType::}
3276// ,{"DBNUM1", style::NumberingType::}
3277// ,{"DBNUM2", style::NumberingType::}
3278// ,{"DBNUM3", style::NumberingType::}
3279// ,{"DBNUM4", style::NumberingType::}
3280 ,{"Aiueo", style::NumberingType::AIU_FULLWIDTH_JA}
3281 ,{"Iroha", style::NumberingType::IROHA_FULLWIDTH_JA}
3282// ,{"ZODIAC1", style::NumberingType::}
3283// ,{"ZODIAC2", style::NumberingType::}
3284// ,{"ZODIAC3", style::NumberingType::}
3285// ,{"CHINESENUM1", style::NumberingType::}
3286// ,{"CHINESENUM2", style::NumberingType::}
3287// ,{"CHINESENUM3", style::NumberingType::}
3288 ,{"ArabicAlpha", style::NumberingType::CHARS_ARABIC}
3289 ,{"ArabicAbjad", style::NumberingType::FULLWIDTH_ARABIC}
3290/* possible values:
3291style::NumberingType::
3292
3293 CHARS_UPPER_LETTER_N
3294 CHARS_LOWER_LETTER_N
3295 TRANSLITERATION
3296 NATIVE_NUMBERING
3297 CIRCLE_NUMBER
3298 NUMBER_LOWER_ZH
3299 NUMBER_UPPER_ZH
3300 NUMBER_UPPER_ZH_TW
3301 TIAN_GAN_ZH
3302 DI_ZI_ZH
3303 NUMBER_TRADITIONAL_JA
3304 AIU_HALFWIDTH_JA
3305 IROHA_HALFWIDTH_JA
3306 NUMBER_UPPER_KO
3307 NUMBER_HANGUL_KO
3308 HANGUL_JAMO_KO
3309 HANGUL_SYLLABLE_KO
3310 HANGUL_CIRCLED_JAMO_KO
3311 HANGUL_CIRCLED_SYLLABLE_KO
3312 CHARS_HEBREW
3313 CHARS_NEPALI
3314 CHARS_KHMER
3315 CHARS_LAO
3316 CHARS_TIBETAN
3317 CHARS_CYRILLIC_UPPER_LETTER_BG
3318 CHARS_CYRILLIC_LOWER_LETTER_BG
3319 CHARS_CYRILLIC_UPPER_LETTER_N_BG
3320 CHARS_CYRILLIC_LOWER_LETTER_N_BG
3321 CHARS_CYRILLIC_UPPER_LETTER_RU
3322 CHARS_CYRILLIC_LOWER_LETTER_RU
3323 CHARS_CYRILLIC_UPPER_LETTER_N_RU
3324 CHARS_CYRILLIC_LOWER_LETTER_N_RU
3325 CHARS_CYRILLIC_UPPER_LETTER_SR
3326 CHARS_CYRILLIC_LOWER_LETTER_SR
3327 CHARS_CYRILLIC_UPPER_LETTER_N_SR
3328 CHARS_CYRILLIC_LOWER_LETTER_N_SR*/
3329
3330 };
3331 for(const NumberingPairs& rNumberingPair : aNumberingPairs)
3332 {
3333 if( /*sCommand*/sNumber.equalsAscii(rNumberingPair.cWordName ))
3334 {
3335 nRet = rNumberingPair.nType;
3336 break;
3337 }
3338 }
3339
3340 }
3341 return nRet;
3342}
3343
3344
3345static OUString lcl_ParseFormat( const OUString& rCommand )
3346{
3347 // The command looks like: " DATE \@"dd MMMM yyyy" or "09/02/2014"
3348 // Remove whitespace permitted by standard between \@ and "
3349 OUString command;
3350 sal_Int32 delimPos = rCommand.indexOf("\\@");
3351 if (delimPos != -1)
3352 {
3353 sal_Int32 wsChars = rCommand.indexOf('\"') - delimPos - 2;
3354 command = rCommand.replaceAt(delimPos+2, wsChars, "");
3355 }
3356 else
3357 command = rCommand;
3358
3359 return msfilter::util::findQuotedText(command, "\\@\"", '\"');
3360}
3361/*-------------------------------------------------------------------------
3362extract a parameter (with or without quotes) between the command and the following backslash
3363 -----------------------------------------------------------------------*/
3364static OUString lcl_ExtractToken(OUString const& rCommand,
3365 sal_Int32 & rIndex, bool & rHaveToken, bool & rIsSwitch)
3366{
3367 rHaveToken = false;
3368 rIsSwitch = false;
3369
3370 OUStringBuffer token;
3371 bool bQuoted(false);
3372 for (; rIndex < rCommand.getLength(); ++rIndex)
3373 {
3374 sal_Unicode const currentChar(rCommand[rIndex]);
3375 switch (currentChar)
3376 {
3377 case '\\':
3378 {
3379 if (rIndex == rCommand.getLength() - 1)
3380 {
3381 SAL_INFO("writerfilter.dmapper", "field: trailing escape")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "field: trailing escape"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3381" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "field: trailing escape"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"field: trailing escape"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3381" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "field: trailing escape") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3381" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "field: trailing escape"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"field: trailing escape"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3381" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3382 ++rIndex;
3383 return OUString();
3384 }
3385 sal_Unicode const nextChar(rCommand[rIndex+1]);
3386 if (bQuoted || '\\' == nextChar)
3387 {
3388 ++rIndex; // read 2 chars
3389 token.append(nextChar);
3390 }
3391 else // field switch (case insensitive)
3392 {
3393 rHaveToken = true;
3394 if (token.isEmpty())
3395 {
3396 rIsSwitch = true;
3397 rIndex += 2; // read 2 chars
3398 return rCommand.copy(rIndex - 2, 2).toAsciiUpperCase();
3399 }
3400 else
3401 { // leave rIndex, read it again next time
3402 return token.makeStringAndClear();
3403 }
3404 }
3405 }
3406 break;
3407 case '\"':
3408 if (bQuoted || !token.isEmpty())
3409 {
3410 rHaveToken = true;
3411 if (bQuoted)
3412 {
3413 ++rIndex;
3414 }
3415 return token.makeStringAndClear();
3416 }
3417 else
3418 {
3419 bQuoted = true;
3420 }
3421 break;
3422 case ' ':
3423 if (bQuoted)
3424 {
3425 token.append(' ');
3426 }
3427 else
3428 {
3429 if (!token.isEmpty())
3430 {
3431 rHaveToken = true;
3432 ++rIndex;
3433 return token.makeStringAndClear();
3434 }
3435 }
3436 break;
3437 case '=':
3438 if (token.isEmpty())
3439 {
3440 rHaveToken = true;
3441 ++rIndex;
3442 return "FORMULA";
3443 }
3444 break;
3445 default:
3446 token.append(currentChar);
3447 break;
3448 }
3449 }
3450 assert(rIndex == rCommand.getLength())(static_cast <bool> (rIndex == rCommand.getLength()) ? void
(0) : __assert_fail ("rIndex == rCommand.getLength()", "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 3450, __extension__ __PRETTY_FUNCTION__))
;
3451 if (bQuoted)
3452 {
3453 // MS Word allows this, so just emit a debug message
3454 SAL_INFO("writerfilter.dmapper",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "field argument with unterminated quote"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3455" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "field argument with unterminated quote"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "field argument with unterminated quote"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3455" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "field argument with unterminated quote") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3455" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "field argument with unterminated quote"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "field argument with unterminated quote"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3455" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
3455 "field argument with unterminated quote")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "field argument with unterminated quote"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3455" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "field argument with unterminated quote"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "field argument with unterminated quote"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3455" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "field argument with unterminated quote") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3455" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "field argument with unterminated quote"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "field argument with unterminated quote"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3455" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3456 }
3457 rHaveToken = !token.isEmpty();
3458 return token.makeStringAndClear();
3459}
3460
3461std::tuple<OUString, std::vector<OUString>, std::vector<OUString> > splitFieldCommand(const OUString& rCommand)
3462{
3463 OUString sType;
3464 std::vector<OUString> arguments;
3465 std::vector<OUString> switches;
3466 sal_Int32 nStartIndex(0);
3467 // tdf#54584: Field may be prepended by a backslash
3468 // This is not an escapement, but already escaped literal "\"
3469 // MS Word allows this, so just skip it
3470 if ((rCommand.getLength() >= nStartIndex + 2) &&
3471 (rCommand[nStartIndex] == L'\\') &&
3472 (rCommand[nStartIndex + 1] != L'\\') &&
3473 (rCommand[nStartIndex + 1] != L' '))
3474 {
3475 ++nStartIndex;
3476 }
3477
3478 do
3479 {
3480 bool bHaveToken;
3481 bool bIsSwitch;
3482 OUString const token =
3483 lcl_ExtractToken(rCommand, nStartIndex, bHaveToken, bIsSwitch);
3484 assert(nStartIndex <= rCommand.getLength())(static_cast <bool> (nStartIndex <= rCommand.getLength
()) ? void (0) : __assert_fail ("nStartIndex <= rCommand.getLength()"
, "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 3484, __extension__ __PRETTY_FUNCTION__))
;
3485 if (bHaveToken)
3486 {
3487 if (sType.isEmpty())
3488 {
3489 sType = token.toAsciiUpperCase();
3490 }
3491 else if (bIsSwitch || !switches.empty())
3492 {
3493 switches.push_back(token);
3494 }
3495 else
3496 {
3497 arguments.push_back(token);
3498 }
3499 }
3500 } while (nStartIndex < rCommand.getLength());
3501
3502 return std::make_tuple(sType, arguments, switches);
3503}
3504
3505static OUString lcl_ExtractVariableAndHint( const OUString& rCommand, OUString& rHint )
3506{
3507 // the first word after "ASK " is the variable
3508 // the text after the variable and before a '\' is the hint
3509 // if no hint is set the variable is used as hint
3510 // the quotes of the hint have to be removed
3511 sal_Int32 nIndex = rCommand.indexOf( ' ', 2); //find last space after 'ASK'
3512 if (nIndex == -1)
3513 return OUString();
3514 while(rCommand[nIndex] == ' ')
3515 ++nIndex;
3516 OUString sShortCommand( rCommand.copy( nIndex ) ); //cut off the " ASK "
3517
3518 sShortCommand = sShortCommand.getToken(0, '\\');
3519 nIndex = 0;
3520 OUString sRet = sShortCommand.getToken( 0, ' ', nIndex);
3521 if( nIndex > 0)
3522 rHint = sShortCommand.copy( nIndex );
3523 if( rHint.isEmpty() )
3524 rHint = sRet;
3525 return sRet;
3526}
3527
3528
3529static bool lcl_FindInCommand(
3530 const OUString& rCommand,
3531 sal_Unicode cSwitch,
3532 OUString& rValue )
3533{
3534 bool bRet = false;
3535 OUString sSearch = "\\" + OUStringChar( cSwitch );
3536 sal_Int32 nIndex = rCommand.indexOf( sSearch );
3537 if( nIndex >= 0 )
3538 {
3539 bRet = true;
3540 //find next '\' or end of string
3541 sal_Int32 nEndIndex = rCommand.indexOf( '\\', nIndex + 1);
3542 if( nEndIndex < 0 )
3543 nEndIndex = rCommand.getLength() ;
3544 if( nEndIndex - nIndex > 3 )
3545 rValue = rCommand.copy( nIndex + 3, nEndIndex - nIndex - 3);
3546 }
3547 return bRet;
3548}
3549
3550
3551void DomainMapper_Impl::GetCurrentLocale(lang::Locale& rLocale)
3552{
3553 PropertyMapPtr pTopContext = GetTopContext();
3554 std::optional<PropertyMap::Property> pLocale = pTopContext->getProperty(PROP_CHAR_LOCALE);
3555 if( pLocale )
3556 pLocale->second >>= rLocale;
3557 else
3558 {
3559 PropertyMapPtr pParaContext = GetTopContextOfType(CONTEXT_PARAGRAPH);
3560 pLocale = pParaContext->getProperty(PROP_CHAR_LOCALE);
3561 if( pLocale )
3562 {
3563 pLocale->second >>= rLocale;
3564 }
3565 }
3566}
3567
3568/*-------------------------------------------------------------------------
3569 extract the number format from the command and apply the resulting number
3570 format to the XPropertySet
3571 -----------------------------------------------------------------------*/
3572void DomainMapper_Impl::SetNumberFormat( const OUString& rCommand,
3573 uno::Reference< beans::XPropertySet > const& xPropertySet,
3574 bool const bDetectFormat)
3575{
3576 OUString sFormatString = lcl_ParseFormat( rCommand );
3577 // find \h - hijri/luna calendar todo: what about saka/era calendar?
3578 bool bHijri = 0 < rCommand.indexOf("\\h ");
3579 lang::Locale aUSLocale;
3580 aUSLocale.Language = "en";
3581 aUSLocale.Country = "US";
3582
3583 //determine current locale - todo: is it necessary to initialize this locale?
3584 lang::Locale aCurrentLocale = aUSLocale;
3585 GetCurrentLocale( aCurrentLocale );
3586 OUString sFormat = ConversionHelper::ConvertMSFormatStringToSO( sFormatString, aCurrentLocale, bHijri);
3587 //get the number formatter and convert the string to a format value
3588 try
3589 {
3590 sal_Int32 nKey = 0;
3591 uno::Reference< util::XNumberFormatsSupplier > xNumberSupplier( m_xTextDocument, uno::UNO_QUERY_THROW );
3592 if( bDetectFormat )
3593 {
3594 uno::Reference< util::XNumberFormatter> xFormatter(util::NumberFormatter::create(m_xComponentContext), uno::UNO_QUERY_THROW);
3595 xFormatter->attachNumberFormatsSupplier( xNumberSupplier );
3596 nKey = xFormatter->detectNumberFormat( 0, rCommand );
3597 }
3598 else
3599 {
3600 nKey = xNumberSupplier->getNumberFormats()->addNewConverted( sFormat, aUSLocale, aCurrentLocale );
3601 }
3602 xPropertySet->setPropertyValue(
3603 getPropertyName(PROP_NUMBER_FORMAT),
3604 uno::makeAny( nKey ));
3605 }
3606 catch(const uno::Exception&)
3607 {
3608 }
3609}
3610
3611static uno::Any lcl_getGrabBagValue( const uno::Sequence<beans::PropertyValue>& grabBag, OUString const & name )
3612{
3613 auto pProp = std::find_if(grabBag.begin(), grabBag.end(),
3614 [&name](const beans::PropertyValue& rProp) { return rProp.Name == name; });
3615 if (pProp != grabBag.end())
3616 return pProp->Value;
3617 return uno::Any();
3618}
3619
3620//Link the text frames.
3621void DomainMapper_Impl::ChainTextFrames()
3622{
3623 //can't link textboxes if there are not even two of them...
3624 if( 2 > m_vTextFramesForChaining.size() )
3625 return ;
3626
3627 struct TextFramesForChaining {
3628 css::uno::Reference< css::drawing::XShape > xShape;
3629 sal_Int32 nId;
3630 sal_Int32 nSeq;
3631 OUString s_mso_next_textbox;
3632 bool bShapeNameSet;
3633 TextFramesForChaining(): nId(0), nSeq(0), bShapeNameSet(false) {}
3634 } ;
3635 typedef std::map <OUString, TextFramesForChaining> ChainMap;
3636
3637 try
3638 {
3639 ChainMap aTextFramesForChainingHelper;
3640 OUString sChainNextName("ChainNextName");
3641
3642 //learn about ALL of the textboxes and their chaining values first - because frames are processed in no specific order.
3643 for( const auto& rTextFrame : m_vTextFramesForChaining )
3644 {
3645 uno::Reference<text::XTextContent> xTextContent(rTextFrame, uno::UNO_QUERY_THROW);
3646 uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
3647 uno::Reference<beans::XPropertySetInfo> xPropertySetInfo;
3648 if( xPropertySet.is() )
3649 xPropertySetInfo = xPropertySet->getPropertySetInfo();
3650 uno::Sequence<beans::PropertyValue> aGrabBag;
3651 uno::Reference<lang::XServiceInfo> xServiceInfo(xPropertySet, uno::UNO_QUERY);
3652
3653 TextFramesForChaining aChainStruct;
3654 OUString sShapeName;
3655 OUString sLinkChainName;
3656
3657 //The chaining name and the shape name CAN be different in .docx.
3658 //MUST use LinkDisplayName/ChainName as the shape name for establishing links.
3659 if ( xServiceInfo->supportsService("com.sun.star.text.TextFrame") )
3660 {
3661 xPropertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
3662 xPropertySet->getPropertyValue("LinkDisplayName") >>= sShapeName;
3663 }
3664 else
3665 {
3666 xPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
3667 xPropertySet->getPropertyValue("ChainName") >>= sShapeName;
3668 }
3669
3670 lcl_getGrabBagValue( aGrabBag, "Txbx-Id") >>= aChainStruct.nId;
3671 lcl_getGrabBagValue( aGrabBag, "Txbx-Seq") >>= aChainStruct.nSeq;
3672 lcl_getGrabBagValue( aGrabBag, "LinkChainName") >>= sLinkChainName;
3673 lcl_getGrabBagValue( aGrabBag, "mso-next-textbox") >>= aChainStruct.s_mso_next_textbox;
3674
3675 //Sometimes the shape names have not been imported. If not, we may have a fallback name.
3676 //Set name later, only if required for linking.
3677 if( sShapeName.isEmpty() )
3678 aChainStruct.bShapeNameSet = false;
3679 else
3680 {
3681 aChainStruct.bShapeNameSet = true;
3682 sLinkChainName = sShapeName;
3683 }
3684
3685 if( !sLinkChainName.isEmpty() )
3686 {
3687 aChainStruct.xShape = rTextFrame;
3688 aTextFramesForChainingHelper[sLinkChainName] = aChainStruct;
3689 }
3690 }
3691
3692 //if mso-next-textbox tags are provided, create those vml-style links first. Afterwards we will make dml-style id/seq links.
3693 for (auto& msoItem : aTextFramesForChainingHelper)
3694 {
3695 //if no mso-next-textbox, we are done.
3696 //if it points to itself, we are done.
3697 if( !msoItem.second.s_mso_next_textbox.isEmpty()
3698 && msoItem.second.s_mso_next_textbox != msoItem.first )
3699 {
3700 ChainMap::iterator nextFinder=aTextFramesForChainingHelper.find(msoItem.second.s_mso_next_textbox);
3701 if( nextFinder != aTextFramesForChainingHelper.end() )
3702 {
3703 //if the frames have no name yet, then set them. LinkDisplayName / ChainName are read-only.
3704 if( !msoItem.second.bShapeNameSet )
3705 {
3706 uno::Reference< container::XNamed > xNamed( msoItem.second.xShape, uno::UNO_QUERY );
3707 if ( xNamed.is() )
3708 {
3709 xNamed->setName( msoItem.first );
3710 msoItem.second.bShapeNameSet = true;
3711 }
3712 }
3713 if( !nextFinder->second.bShapeNameSet )
3714 {
3715 uno::Reference< container::XNamed > xNamed( nextFinder->second.xShape, uno::UNO_QUERY );
3716 if ( xNamed.is() )
3717 {
3718 xNamed->setName( nextFinder->first );
3719 nextFinder->second.bShapeNameSet = true;
3720 }
3721 }
3722
3723 uno::Reference<text::XTextContent> xTextContent(msoItem.second.xShape, uno::UNO_QUERY_THROW);
3724 uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
3725
3726 //The reverse chaining happens automatically, so only one direction needs to be set
3727 xPropertySet->setPropertyValue(sChainNextName, uno::makeAny(nextFinder->first));
3728
3729 //the last item in an mso-next-textbox chain is indistinguishable from id/seq items. Now that it is handled, remove it.
3730 if( nextFinder->second.s_mso_next_textbox.isEmpty() )
3731 aTextFramesForChainingHelper.erase(nextFinder->first);
3732 }
3733 }
3734 }
3735
3736 //TODO: Perhaps allow reverse sequences when mso-layout-flow-alt = "bottom-to-top"
3737 const sal_Int32 nDirection = 1;
3738
3739 //Finally - go through and attach the chains based on matching ID and incremented sequence number (dml-style).
3740 for (const auto& rOuter : aTextFramesForChainingHelper)
3741 {
3742 if( rOuter.second.s_mso_next_textbox.isEmpty() ) //non-empty ones already handled earlier - so skipping them now.
3743 {
3744 for (const auto& rInner : aTextFramesForChainingHelper)
3745 {
3746 if ( rInner.second.nId == rOuter.second.nId )
3747 {
3748 if ( rInner.second.nSeq == ( rOuter.second.nSeq + nDirection ) )
3749 {
3750 uno::Reference<text::XTextContent> xTextContent(rOuter.second.xShape, uno::UNO_QUERY_THROW);
3751 uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
3752
3753 //The reverse chaining happens automatically, so only one direction needs to be set
3754 xPropertySet->setPropertyValue(sChainNextName, uno::makeAny(rInner.first));
3755 break ; //there cannot be more than one next frame
3756 }
3757 }
3758 }
3759 }
3760 }
3761 m_vTextFramesForChaining.clear(); //clear the vector
3762 }
3763 catch (const uno::Exception&)
3764 {
3765 DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper")DbgUnhandledException( DbgGetCaughtException(), __func__, "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3765" ": ", "writerfilter.dmapper" );
;
3766 }
3767}
3768
3769uno::Reference<beans::XPropertySet> DomainMapper_Impl::FindOrCreateFieldMaster(const char* pFieldMasterService, const OUString& rFieldMasterName)
3770{
3771 // query master, create if not available
3772 uno::Reference< text::XTextFieldsSupplier > xFieldsSupplier( GetTextDocument(), uno::UNO_QUERY_THROW );
3773 uno::Reference< container::XNameAccess > xFieldMasterAccess = xFieldsSupplier->getTextFieldMasters();
3774 uno::Reference< beans::XPropertySet > xMaster;
3775 OUString sFieldMasterService( OUString::createFromAscii(pFieldMasterService) );
3776 OUStringBuffer aFieldMasterName;
3777 OUString sDatabaseDataSourceName = GetSettingsTable()->GetCurrentDatabaseDataSource();
3778 bool bIsMergeField = sFieldMasterService.endsWith("Database");
3779 aFieldMasterName.appendAscii( pFieldMasterService );
3780 aFieldMasterName.append('.');
3781 if ( bIsMergeField && !sDatabaseDataSourceName.isEmpty() )
3782 {
3783 aFieldMasterName.append(sDatabaseDataSourceName);
3784 aFieldMasterName.append('.');
3785 }
3786 aFieldMasterName.append(rFieldMasterName);
3787 OUString sFieldMasterName = aFieldMasterName.makeStringAndClear();
3788 if(xFieldMasterAccess->hasByName(sFieldMasterName))
3789 {
3790 //get the master
3791 xMaster.set(xFieldMasterAccess->getByName(sFieldMasterName), uno::UNO_QUERY_THROW);
3792 }
3793 else if( m_xTextFactory.is() )
3794 {
3795 //create the master
3796 xMaster.set( m_xTextFactory->createInstance(sFieldMasterService), uno::UNO_QUERY_THROW);
3797 if ( !bIsMergeField || sDatabaseDataSourceName.isEmpty() )
3798 {
3799 //set the master's name
3800 xMaster->setPropertyValue(
3801 getPropertyName(PROP_NAME),
3802 uno::makeAny(rFieldMasterName));
3803 } else {
3804 // set database data, based on the "databasename.tablename" of sDatabaseDataSourceName
3805 xMaster->setPropertyValue(
3806 getPropertyName(PROP_DATABASE_NAME),
3807 uno::makeAny(sDatabaseDataSourceName.copy(0, sDatabaseDataSourceName.indexOf('.'))));
3808 xMaster->setPropertyValue(
3809 getPropertyName(PROP_COMMAND_TYPE),
3810 uno::makeAny(sal_Int32(0)));
3811 xMaster->setPropertyValue(
3812 getPropertyName(PROP_DATATABLE_NAME),
3813 uno::makeAny(sDatabaseDataSourceName.copy(sDatabaseDataSourceName.indexOf('.') + 1)));
3814 xMaster->setPropertyValue(
3815 getPropertyName(PROP_DATACOLUMN_NAME),
3816 uno::makeAny(rFieldMasterName));
3817 }
3818 }
3819 return xMaster;
3820}
3821
3822void DomainMapper_Impl::PushFieldContext()
3823{
3824 m_bParaHadField = true;
3825 if(m_bDiscardHeaderFooter)
3826 return;
3827#ifdef DBG_UTIL
3828 TagLogger::getInstance().element("pushFieldContext");
3829#endif
3830
3831 uno::Reference<text::XTextCursor> xCrsr;
3832 if (!m_aTextAppendStack.empty())
3833 {
3834 uno::Reference<text::XTextAppend> xTextAppend = m_aTextAppendStack.top().xTextAppend;
3835 if (xTextAppend.is())
3836 xCrsr = xTextAppend->createTextCursorByRange(
3837 m_aTextAppendStack.top().xInsertPosition.is()
3838 ? m_aTextAppendStack.top().xInsertPosition
3839 : xTextAppend->getEnd());
3840 }
3841
3842 uno::Reference< text::XTextRange > xStart;
3843 if (xCrsr.is())
3844 xStart = xCrsr->getStart();
3845 m_aFieldStack.push_back(new FieldContext(xStart));
3846}
3847/*-------------------------------------------------------------------------
3848//the current field context waits for the completion of the command
3849 -----------------------------------------------------------------------*/
3850bool DomainMapper_Impl::IsOpenFieldCommand() const
3851{
3852 return !m_aFieldStack.empty() && !m_aFieldStack.back()->IsCommandCompleted();
3853}
3854/*-------------------------------------------------------------------------
3855//the current field context waits for the completion of the command
3856 -----------------------------------------------------------------------*/
3857bool DomainMapper_Impl::IsOpenField() const
3858{
3859 return !m_aFieldStack.empty();
3860}
3861
3862// Mark top field context as containing a fixed field
3863void DomainMapper_Impl::SetFieldLocked()
3864{
3865 if (IsOpenField())
3866 m_aFieldStack.back()->SetFieldLocked();
3867}
3868
3869HeaderFooterContext::HeaderFooterContext(bool bTextInserted, sal_Int32 nTableDepth)
3870 : m_bTextInserted(bTextInserted)
3871 , m_nTableDepth(nTableDepth)
3872{
3873}
3874
3875bool HeaderFooterContext::getTextInserted() const
3876{
3877 return m_bTextInserted;
3878}
3879
3880sal_Int32 HeaderFooterContext::getTableDepth() const { return m_nTableDepth; }
3881
3882FieldContext::FieldContext(uno::Reference< text::XTextRange > const& xStart)
3883 : m_bFieldCommandCompleted(false)
3884 , m_xStartRange( xStart )
3885 , m_bFieldLocked( false )
3886{
3887 m_pProperties = new PropertyMap();
3888}
3889
3890
3891FieldContext::~FieldContext()
3892{
3893}
3894
3895
3896void FieldContext::AppendCommand(const OUString& rPart)
3897{
3898 m_sCommand += rPart;
3899}
3900
3901::std::vector<OUString> FieldContext::GetCommandParts() const
3902{
3903 ::std::vector<OUString> aResult;
3904 sal_Int32 nIndex = 0;
3905 bool bInString = false;
3906 OUString sPart;
3907 while (nIndex != -1)
3908 {
3909 OUString sToken = GetCommand().getToken(0, ' ', nIndex);
3910 bool bInStringNext = bInString;
3911
3912 if (sToken.isEmpty())
3913 continue;
3914
3915 if (sToken[0] == '"')
3916 {
3917 bInStringNext = true;
3918 sToken = sToken.copy(1);
3919 }
3920 if (sToken.endsWith("\""))
3921 {
3922 bInStringNext = false;
3923 sToken = sToken.copy(0, sToken.getLength() - 1);
3924 }
3925
3926 if (bInString)
3927 {
3928 sPart += " " + sToken;
3929 if (!bInStringNext)
3930 {
3931 aResult.push_back(sPart);
3932 }
3933 }
3934 else
3935 {
3936 if (bInStringNext)
3937 {
3938 sPart = sToken;
3939 }
3940 else
3941 {
3942 aResult.push_back(sToken);
3943 }
3944 }
3945
3946 bInString = bInStringNext;
3947 }
3948
3949 return aResult;
3950}
3951
3952/*-------------------------------------------------------------------------
3953//collect the pieces of the command
3954 -----------------------------------------------------------------------*/
3955void DomainMapper_Impl::AppendFieldCommand(OUString const & rPartOfCommand)
3956{
3957#ifdef DBG_UTIL
3958 TagLogger::getInstance().startElement("appendFieldCommand");
3959 TagLogger::getInstance().chars(rPartOfCommand);
3960 TagLogger::getInstance().endElement();
3961#endif
3962
3963 FieldContextPtr pContext = m_aFieldStack.back();
3964 OSL_ENSURE( pContext, "no field context available")do { if (true && (!(pContext))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "3964" ": "), "%s", "no field context available"); } } while
(false)
;
3965 if( pContext )
3966 {
3967 pContext->AppendCommand( rPartOfCommand );
3968 }
3969}
3970
3971
3972typedef std::multimap < sal_Int32, OUString > TOCStyleMap;
3973
3974
3975static ww::eField GetWW8FieldId(OUString const& rType)
3976{
3977 std::unordered_map<OUString, ww::eField> mapID
3978 {
3979 {"ADDRESSBLOCK", ww::eADDRESSBLOCK},
3980 {"ADVANCE", ww::eADVANCE},
3981 {"ASK", ww::eASK},
3982 {"AUTONUM", ww::eAUTONUM},
3983 {"AUTONUMLGL", ww::eAUTONUMLGL},
3984 {"AUTONUMOUT", ww::eAUTONUMOUT},
3985 {"AUTOTEXT", ww::eAUTOTEXT},
3986 {"AUTOTEXTLIST", ww::eAUTOTEXTLIST},
3987 {"AUTHOR", ww::eAUTHOR},
3988 {"BARCODE", ww::eBARCODE},
3989 {"BIDIOUTLINE", ww::eBIDIOUTLINE},
3990 {"DATE", ww::eDATE},
3991 {"COMMENTS", ww::eCOMMENTS},
3992 {"COMPARE", ww::eCOMPARE},
3993 {"CONTROL", ww::eCONTROL},
3994 {"CREATEDATE", ww::eCREATEDATE},
3995 {"DATABASE", ww::eDATABASE},
3996 {"DDEAUTOREF", ww::eDDEAUTOREF},
3997 {"DDEREF", ww::eDDEREF},
3998 {"DOCPROPERTY", ww::eDOCPROPERTY},
3999 {"DOCVARIABLE", ww::eDOCVARIABLE},
4000 {"EDITTIME", ww::eEDITTIME},
4001 {"EMBED", ww::eEMBED},
4002 {"EQ", ww::eEQ},
4003 {"FILLIN", ww::eFILLIN},
4004 {"FILENAME", ww::eFILENAME},
4005 {"FILESIZE", ww::eFILESIZE},
4006 {"FOOTREF", ww::eFOOTREF},
4007// {"FORMULA", ww::},
4008 {"FORMCHECKBOX", ww::eFORMCHECKBOX},
4009 {"FORMDROPDOWN", ww::eFORMDROPDOWN},
4010 {"FORMTEXT", ww::eFORMTEXT},
4011 {"GLOSSREF", ww::eGLOSSREF},
4012 {"GOTOBUTTON", ww::eGOTOBUTTON},
4013 {"GREETINGLINE", ww::eGREETINGLINE},
4014 {"HTMLCONTROL", ww::eHTMLCONTROL},
4015 {"HYPERLINK", ww::eHYPERLINK},
4016 {"IF", ww::eIF},
4017 {"INFO", ww::eINFO},
4018 {"INCLUDEPICTURE", ww::eINCLUDEPICTURE},
4019 {"INCLUDETEXT", ww::eINCLUDETEXT},
4020 {"INCLUDETIFF", ww::eINCLUDETIFF},
4021 {"KEYWORDS", ww::eKEYWORDS},
4022 {"LASTSAVEDBY", ww::eLASTSAVEDBY},
4023 {"LINK", ww::eLINK},
4024 {"LISTNUM", ww::eLISTNUM},
4025 {"MACRO", ww::eMACRO},
4026 {"MACROBUTTON", ww::eMACROBUTTON},
4027 {"MERGEDATA", ww::eMERGEDATA},
4028 {"MERGEFIELD", ww::eMERGEFIELD},
4029 {"MERGEINC", ww::eMERGEINC},
4030 {"MERGEREC", ww::eMERGEREC},
4031 {"MERGESEQ", ww::eMERGESEQ},
4032 {"NEXT", ww::eNEXT},
4033 {"NEXTIF", ww::eNEXTIF},
4034 {"NOTEREF", ww::eNOTEREF},
4035 {"PAGE", ww::ePAGE},
4036 {"PAGEREF", ww::ePAGEREF},
4037 {"PLUGIN", ww::ePLUGIN},
4038 {"PRINT", ww::ePRINT},
4039 {"PRINTDATE", ww::ePRINTDATE},
4040 {"PRIVATE", ww::ePRIVATE},
4041 {"QUOTE", ww::eQUOTE},
4042 {"RD", ww::eRD},
4043 {"REF", ww::eREF},
4044 {"REVNUM", ww::eREVNUM},
4045 {"SAVEDATE", ww::eSAVEDATE},
4046 {"SECTION", ww::eSECTION},
4047 {"SECTIONPAGES", ww::eSECTIONPAGES},
4048 {"SEQ", ww::eSEQ},
4049 {"SET", ww::eSET},
4050 {"SKIPIF", ww::eSKIPIF},
4051 {"STYLEREF", ww::eSTYLEREF},
4052 {"SUBSCRIBER", ww::eSUBSCRIBER},
4053 {"SUBJECT", ww::eSUBJECT},
4054 {"SYMBOL", ww::eSYMBOL},
4055 {"TA", ww::eTA},
4056 {"TEMPLATE", ww::eTEMPLATE},
4057 {"TIME", ww::eTIME},
4058 {"TITLE", ww::eTITLE},
4059 {"TOA", ww::eTOA},
4060 {"USERINITIALS", ww::eUSERINITIALS},
4061 {"USERADDRESS", ww::eUSERADDRESS},
4062 {"USERNAME", ww::eUSERNAME},
4063
4064 {"TOC", ww::eTOC},
4065 {"TC", ww::eTC},
4066 {"NUMCHARS", ww::eNUMCHARS},
4067 {"NUMWORDS", ww::eNUMWORDS},
4068 {"NUMPAGES", ww::eNUMPAGES},
4069 {"INDEX", ww::eINDEX},
4070 {"XE", ww::eXE},
4071 {"BIBLIOGRAPHY", ww::eBIBLIOGRAPHY},
4072 {"CITATION", ww::eCITATION},
4073 };
4074 auto const it = mapID.find(rType);
4075 return (it == mapID.end()) ? ww::eNONE : it->second;
4076}
4077
4078static const FieldConversionMap_t & lcl_GetFieldConversion()
4079{
4080 static const FieldConversionMap_t aFieldConversionMap
4081 {
4082// {"ADDRESSBLOCK", {"", FIELD_ADDRESSBLOCK }},
4083// {"ADVANCE", {"", FIELD_ADVANCE }},
4084 {"ASK", {"SetExpression", FIELD_ASK }},
4085 {"AUTONUM", {"SetExpression", FIELD_AUTONUM }},
4086 {"AUTONUMLGL", {"SetExpression", FIELD_AUTONUMLGL }},
4087 {"AUTONUMOUT", {"SetExpression", FIELD_AUTONUMOUT }},
4088 {"AUTHOR", {"DocInfo.CreateAuthor", FIELD_AUTHOR }},
4089 {"DATE", {"DateTime", FIELD_DATE }},
4090 {"COMMENTS", {"DocInfo.Description", FIELD_COMMENTS }},
4091 {"CREATEDATE", {"DocInfo.CreateDateTime", FIELD_CREATEDATE }},
4092 {"DOCPROPERTY", {"", FIELD_DOCPROPERTY }},
4093 {"DOCVARIABLE", {"User", FIELD_DOCVARIABLE }},
4094 {"EDITTIME", {"DocInfo.EditTime", FIELD_EDITTIME }},
4095 {"EQ", {"", FIELD_EQ }},
4096 {"FILLIN", {"Input", FIELD_FILLIN }},
4097 {"FILENAME", {"FileName", FIELD_FILENAME }},
4098// {"FILESIZE", {"", FIELD_FILESIZE }},
4099 {"FORMULA", {"TableFormula", FIELD_FORMULA }},
4100 {"FORMCHECKBOX", {"", FIELD_FORMCHECKBOX }},
4101 {"FORMDROPDOWN", {"DropDown", FIELD_FORMDROPDOWN }},
4102 {"FORMTEXT", {"Input", FIELD_FORMTEXT }},
4103 {"GOTOBUTTON", {"", FIELD_GOTOBUTTON }},
4104 {"HYPERLINK", {"", FIELD_HYPERLINK }},
4105 {"IF", {"ConditionalText", FIELD_IF }},
4106// {"INFO", {"", FIELD_INFO }},
4107 {"INCLUDEPICTURE", {"", FIELD_INCLUDEPICTURE}},
4108 {"KEYWORDS", {"DocInfo.KeyWords", FIELD_KEYWORDS }},
4109 {"LASTSAVEDBY", {"DocInfo.ChangeAuthor", FIELD_LASTSAVEDBY }},
4110 {"MACROBUTTON", {"Macro", FIELD_MACROBUTTON }},
4111 {"MERGEFIELD", {"Database", FIELD_MERGEFIELD }},
4112 {"MERGEREC", {"DatabaseNumberOfSet", FIELD_MERGEREC }},
4113// {"MERGESEQ", {"", FIELD_MERGESEQ }},
4114 {"NEXT", {"DatabaseNextSet", FIELD_NEXT }},
4115 {"NEXTIF", {"DatabaseNextSet", FIELD_NEXTIF }},
4116 {"PAGE", {"PageNumber", FIELD_PAGE }},
4117 {"PAGEREF", {"GetReference", FIELD_PAGEREF }},
4118 {"REF", {"GetReference", FIELD_REF }},
4119 {"REVNUM", {"DocInfo.Revision", FIELD_REVNUM }},
4120 {"SAVEDATE", {"DocInfo.Change", FIELD_SAVEDATE }},
4121// {"SECTION", {"", FIELD_SECTION }},
4122// {"SECTIONPAGES", {"", FIELD_SECTIONPAGES }},
4123 {"SEQ", {"SetExpression", FIELD_SEQ }},
4124 {"SET", {"SetExpression", FIELD_SET }},
4125// {"SKIPIF", {"", FIELD_SKIPIF }},
4126// {"STYLEREF", {"", FIELD_STYLEREF }},
4127 {"SUBJECT", {"DocInfo.Subject", FIELD_SUBJECT }},
4128 {"SYMBOL", {"", FIELD_SYMBOL }},
4129 {"TEMPLATE", {"TemplateName", FIELD_TEMPLATE }},
4130 {"TIME", {"DateTime", FIELD_TIME }},
4131 {"TITLE", {"DocInfo.Title", FIELD_TITLE }},
4132 {"USERINITIALS", {"Author", FIELD_USERINITIALS }},
4133// {"USERADDRESS", {"", FIELD_USERADDRESS }},
4134 {"USERNAME", {"Author", FIELD_USERNAME }},
4135
4136
4137 {"TOC", {"com.sun.star.text.ContentIndex", FIELD_TOC }},
4138 {"TC", {"com.sun.star.text.ContentIndexMark", FIELD_TC }},
4139 {"NUMCHARS", {"CharacterCount", FIELD_NUMCHARS }},
4140 {"NUMWORDS", {"WordCount", FIELD_NUMWORDS }},
4141 {"NUMPAGES", {"PageCount", FIELD_NUMPAGES }},
4142 {"INDEX", {"com.sun.star.text.DocumentIndex", FIELD_INDEX }},
4143 {"XE", {"com.sun.star.text.DocumentIndexMark", FIELD_XE }},
4144 {"BIBLIOGRAPHY",{"com.sun.star.text.Bibliography", FIELD_BIBLIOGRAPHY }},
4145 {"CITATION", {"com.sun.star.text.TextField.Bibliography",FIELD_CITATION }},
4146 };
4147
4148 return aFieldConversionMap;
4149}
4150
4151static const FieldConversionMap_t & lcl_GetEnhancedFieldConversion()
4152{
4153 static const FieldConversionMap_t aEnhancedFieldConversionMap =
4154 {
4155 {"FORMCHECKBOX", {"FormFieldmark", FIELD_FORMCHECKBOX}},
4156 {"FORMDROPDOWN", {"FormFieldmark", FIELD_FORMDROPDOWN}},
4157 {"FORMTEXT", {"Fieldmark", FIELD_FORMTEXT}},
4158 };
4159
4160 return aEnhancedFieldConversionMap;
4161}
4162
4163void DomainMapper_Impl::handleFieldSet
4164 (const FieldContextPtr& pContext,
4165 uno::Reference< uno::XInterface > const & xFieldInterface,
4166 uno::Reference< beans::XPropertySet > const& xFieldProperties)
4167{
4168 OUString sVariable, sHint;
4169
4170 sVariable = lcl_ExtractVariableAndHint(pContext->GetCommand(), sHint);
4171
4172 // remove surrounding "" if exists
4173 if(sHint.getLength() >= 2)
4174 {
4175 OUString sTmp = sHint.trim();
4176 if (sTmp.startsWith("\"") && sTmp.endsWith("\""))
4177 {
4178 sHint = sTmp.copy(1, sTmp.getLength() - 2);
4179 }
4180 }
4181
4182 // determine field master name
4183 uno::Reference< beans::XPropertySet > xMaster =
4184 FindOrCreateFieldMaster
4185 ("com.sun.star.text.FieldMaster.SetExpression", sVariable );
4186
4187 // a set field is a string
4188 xMaster->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::makeAny(text::SetVariableType::STRING));
4189
4190 // attach the master to the field
4191 uno::Reference< text::XDependentTextField > xDependentField
4192 ( xFieldInterface, uno::UNO_QUERY_THROW );
4193 xDependentField->attachTextFieldMaster( xMaster );
4194
4195 xFieldProperties->setPropertyValue(getPropertyName(PROP_HINT), uno::makeAny( sHint ));
4196 xFieldProperties->setPropertyValue(getPropertyName(PROP_CONTENT), uno::makeAny( sHint ));
4197 xFieldProperties->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::makeAny(text::SetVariableType::STRING));
4198
4199 // Mimic MS Word behavior (hide the SET)
4200 xFieldProperties->setPropertyValue(getPropertyName(PROP_IS_VISIBLE), uno::makeAny(false));
4201}
4202
4203void DomainMapper_Impl::handleFieldAsk
4204 (const FieldContextPtr& pContext,
4205 uno::Reference< uno::XInterface > & xFieldInterface,
4206 uno::Reference< beans::XPropertySet > const& xFieldProperties)
4207{
4208 //doesn the command contain a variable name?
4209 OUString sVariable, sHint;
4210
4211 sVariable = lcl_ExtractVariableAndHint( pContext->GetCommand(),
4212 sHint );
4213 if(!sVariable.isEmpty())
4214 {
4215 // determine field master name
4216 uno::Reference< beans::XPropertySet > xMaster =
4217 FindOrCreateFieldMaster
4218 ("com.sun.star.text.FieldMaster.SetExpression", sVariable );
4219 // An ASK field is always a string of characters
4220 xMaster->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::makeAny(text::SetVariableType::STRING));
4221
4222 // attach the master to the field
4223 uno::Reference< text::XDependentTextField > xDependentField
4224 ( xFieldInterface, uno::UNO_QUERY_THROW );
4225 xDependentField->attachTextFieldMaster( xMaster );
4226
4227 // set input flag at the field
4228 xFieldProperties->setPropertyValue(
4229 getPropertyName(PROP_IS_INPUT), uno::makeAny( true ));
4230 // set the prompt
4231 xFieldProperties->setPropertyValue(
4232 getPropertyName(PROP_HINT),
4233 uno::makeAny( sHint ));
4234 xFieldProperties->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::makeAny(text::SetVariableType::STRING));
4235 // The ASK has no field value to display
4236 xFieldProperties->setPropertyValue(getPropertyName(PROP_IS_VISIBLE), uno::makeAny(false));
4237 }
4238 else
4239 {
4240 //don't insert the field
4241 //todo: maybe import a 'normal' input field here?
4242 xFieldInterface = nullptr;
4243 }
4244}
4245
4246/**
4247 * Converts a Microsoft Word field formula into LibreOffice syntax
4248 * @param input The Microsoft Word field formula, with no leading '=' sign
4249 * @return An equivalent LibreOffice field formula
4250 */
4251OUString DomainMapper_Impl::convertFieldFormula(const OUString& input) {
4252
4253 OUString listSeparator = m_pSettingsTable->GetListSeparator();
4254
4255 /* Replace logical condition functions with LO equivalent operators */
4256 OUString changed = input.replaceAll(" <> ", " NEQ ");
4257 changed = changed.replaceAll(" <= ", " LEQ ");
4258 changed = changed.replaceAll(" >= ", " GEQ ");
4259 changed = changed.replaceAll(" = " , " EQ ");
4260 changed = changed.replaceAll(" < " , " L ");
4261 changed = changed.replaceAll(" > " , " G ");
4262
4263 changed = changed.replaceAll("<>", " NEQ ");
4264 changed = changed.replaceAll("<=", " LEQ ");
4265 changed = changed.replaceAll(">=", " GEQ ");
4266 changed = changed.replaceAll("=" , " EQ ");
4267 changed = changed.replaceAll("<" , " L ");
4268 changed = changed.replaceAll(">" , " G ");
4269
4270 /* Replace function calls with infix keywords for AND(), OR(), and ROUND(). Nothing needs to be
4271 * done for NOT(). This simple regex will work properly with most common cases. However, it may
4272 * not work correctly when the arguments are nested subcalls to other functions, like
4273 * ROUND(MIN(1,2),MAX(3,4)). See TDF#134765. */
4274 icu::ErrorCode status;
4275 icu::UnicodeString usInput(changed.getStr());
4276 const uint32_t rMatcherFlags = UREGEX_CASE_INSENSITIVE;
4277 OUString regex = "\\b(AND|OR|ROUND)\\s*\\(\\s*([^" + listSeparator + "]+)\\s*" + listSeparator + "\\s*([^)]+)\\s*\\)";
4278 icu::UnicodeString usRegex(regex.getStr());
4279 icu::RegexMatcher rmatch1(usRegex, usInput, rMatcherFlags, status);
4280 usInput = rmatch1.replaceAll(icu::UnicodeString("(($2) $1 ($3))"), status);
4281
4282 /* Assumes any remaining list separators separate arguments to functions that accept lists
4283 * (SUM, MIN, MAX, MEAN, etc.) */
4284 usInput.findAndReplace(icu::UnicodeString(listSeparator.getStr()), "|");
4285
4286 /* Surround single cell references with angle brackets.
4287 * If there is ever added a function name that ends with a digit, this regex will need to be revisited. */
4288 icu::RegexMatcher rmatch2("\\b([A-Z]{1,3}[0-9]+)\\b(?![(])", usInput, rMatcherFlags, status);
4289 usInput = rmatch2.replaceAll(icu::UnicodeString("<$1>"), status);
4290
4291 /* Cell references must be upper case
4292 * TODO: convert reference to other tables, e.g. SUM(Table1 A1:B2), where "Table1" is a bookmark of the table,
4293 * TODO: also column range A:A */
4294 icu::RegexMatcher rmatch3("(<[a-z]{1,3}[0-9]+>|\\b(above|below|left|right)\\b)", usInput, rMatcherFlags, status);
4295 icu::UnicodeString replacedCellRefs;
4296 while (rmatch3.find(status) && status.isSuccess()) {
4297 rmatch3.appendReplacement(replacedCellRefs, rmatch3.group(status).toUpper(), status);
4298 }
4299 rmatch3.appendTail(replacedCellRefs);
4300
4301 /* Fix up cell ranges */
4302 icu::RegexMatcher rmatch4("<([A-Z]{1,3}[0-9]+)>:<([A-Z]{1,3}[0-9]+)>", replacedCellRefs, rMatcherFlags, status);
4303 usInput = rmatch4.replaceAll(icu::UnicodeString("<$1:$2>"), status);
4304
4305 /* Fix up user defined names */
4306 icu::RegexMatcher rmatch5("\\bDEFINED\\s*\\(<([A-Z]+[0-9]+)>\\)", usInput, rMatcherFlags, status);
4307 usInput = rmatch5.replaceAll(icu::UnicodeString("DEFINED($1)"), status);
4308
4309 /* Prepare replace of ABOVE/BELOW/LEFT/RIGHT by adding spaces around them */
4310 icu::RegexMatcher rmatch6("\\b(ABOVE|BELOW|LEFT|RIGHT)\\b", usInput, rMatcherFlags, status);
4311 usInput = rmatch6.replaceAll(icu::UnicodeString(" $1 "), status);
4312
4313 return OUString(usInput.getTerminatedBuffer());
4314}
4315
4316void DomainMapper_Impl::handleFieldFormula
4317 (const FieldContextPtr& pContext,
4318 uno::Reference< beans::XPropertySet > const& xFieldProperties)
4319{
4320 OUString command = pContext->GetCommand().trim();
4321
4322 // Remove number formatting from \# to end of command
4323 // TODO: handle custom number formatting
4324 sal_Int32 delimPos = command.indexOf("\\#");
4325 if (delimPos != -1)
4326 {
4327 command = command.replaceAt(delimPos, command.getLength() - delimPos, "").trim();
4328 }
4329
4330 // command must contains = and at least another char
4331 if (command.getLength() < 2)
4332 return;
4333
4334 // we don't copy the = symbol from the command
4335 OUString formula = convertFieldFormula(command.copy(1));
4336
4337 xFieldProperties->setPropertyValue(getPropertyName(PROP_CONTENT), uno::makeAny(formula));
4338 xFieldProperties->setPropertyValue(getPropertyName(PROP_NUMBER_FORMAT), uno::makeAny(sal_Int32(0)));
4339 xFieldProperties->setPropertyValue("IsShowFormula", uno::makeAny(false));
4340
4341 // grab-bag the original and converted formula
4342 if (hasTableManager())
4343 {
4344 TablePropertyMapPtr pPropMap(new TablePropertyMap());
4345 pPropMap->Insert(PROP_CELL_FORMULA, uno::makeAny(command.copy(1)), true, CELL_GRAB_BAG);
4346 pPropMap->Insert(PROP_CELL_FORMULA_CONVERTED, uno::makeAny(formula), true, CELL_GRAB_BAG);
4347 getTableManager().cellProps(pPropMap);
4348 }
4349}
4350
4351void DomainMapper_Impl::handleRubyEQField( const FieldContextPtr& pContext)
4352{
4353 const OUString & rCommand(pContext->GetCommand());
4354 sal_Int32 nIndex = 0, nEnd = 0;
4355 RubyInfo aInfo ;
4356 nIndex = rCommand.indexOf("\\* jc" );
4357 if (nIndex != -1)
4358 {
4359 nIndex += 5;
4360 sal_uInt32 nJc = rCommand.getToken(0, ' ',nIndex).toInt32();
4361 const sal_Int32 aRubyAlignValues[] =
4362 {
4363 NS_ooxml::LN_Value_ST_RubyAlign_center,
4364 NS_ooxml::LN_Value_ST_RubyAlign_distributeLetter,
4365 NS_ooxml::LN_Value_ST_RubyAlign_distributeSpace,
4366 NS_ooxml::LN_Value_ST_RubyAlign_left,
4367 NS_ooxml::LN_Value_ST_RubyAlign_right,
4368 NS_ooxml::LN_Value_ST_RubyAlign_rightVertical,
4369 };
4370 aInfo.nRubyAlign = aRubyAlignValues[(nJc<SAL_N_ELEMENTS(aRubyAlignValues)(sizeof(sal_n_array_size(aRubyAlignValues))))?nJc:0];
4371 }
4372
4373 // we don't parse or use the font field in rCommand
4374
4375 nIndex = rCommand.indexOf("\\* hps" );
4376 if (nIndex != -1)
4377 {
4378 nIndex += 6;
4379 aInfo.nHps = rCommand.getToken(0, ' ',nIndex).toInt32();
4380 }
4381
4382 nIndex = rCommand.indexOf("\\o");
4383 if (nIndex == -1)
4384 return;
4385 nIndex = rCommand.indexOf('(', nIndex);
4386 if (nIndex == -1)
4387 return;
4388 nEnd = rCommand.lastIndexOf(')');
4389 if (nEnd == -1)
4390 return;
4391 if (nEnd <= nIndex)
4392 return;
4393
4394 OUString sRubyParts = rCommand.copy(nIndex+1,nEnd-nIndex-1);
4395 nIndex = 0;
4396 OUString sPart1 = sRubyParts.getToken(0, ',', nIndex);
4397 OUString sPart2 = sRubyParts.getToken(0, ',', nIndex);
4398 if ((nIndex = sPart1.indexOf('(')) != -1 && (nEnd = sPart1.lastIndexOf(')'))!=-1 && nEnd > nIndex)
4399 {
4400 aInfo.sRubyText = sPart1.copy(nIndex+1,nEnd-nIndex-1);
4401 }
4402
4403 PropertyMapPtr pRubyContext(new PropertyMap());
4404 pRubyContext->InsertProps(GetTopContext());
4405 if (aInfo.nHps > 0)
4406 {
4407 double fVal = double(aInfo.nHps) / 2.;
4408 uno::Any aVal = uno::makeAny( fVal );
4409
4410 pRubyContext->Insert(PROP_CHAR_HEIGHT, aVal);
4411 pRubyContext->Insert(PROP_CHAR_HEIGHT_ASIAN, aVal);
4412 }
4413 PropertyValueVector_t aProps = comphelper::sequenceToContainer< PropertyValueVector_t >(pRubyContext->GetPropertyValues());
4414 aInfo.sRubyStyle = m_rDMapper.getOrCreateCharStyle(aProps, /*bAlwaysCreate=*/false);
4415 PropertyMapPtr pCharContext(new PropertyMap());
4416 if (m_pLastCharacterContext)
4417 pCharContext->InsertProps(m_pLastCharacterContext);
4418 pCharContext->InsertProps(pContext->getProperties());
4419 pCharContext->Insert(PROP_RUBY_TEXT, uno::makeAny( aInfo.sRubyText ) );
4420 pCharContext->Insert(PROP_RUBY_ADJUST, uno::makeAny(static_cast<sal_Int16>(ConversionHelper::convertRubyAlign(aInfo.nRubyAlign))));
4421 if ( aInfo.nRubyAlign == NS_ooxml::LN_Value_ST_RubyAlign_rightVertical )
4422 pCharContext->Insert(PROP_RUBY_POSITION, uno::makeAny(css::text::RubyPosition::INTER_CHARACTER));
4423 pCharContext->Insert(PROP_RUBY_STYLE, uno::makeAny(aInfo.sRubyStyle));
4424 appendTextPortion(sPart2, pCharContext);
4425
4426}
4427
4428void DomainMapper_Impl::handleAutoNum
4429 (const FieldContextPtr& pContext,
4430 uno::Reference< uno::XInterface > const & xFieldInterface,
4431 uno::Reference< beans::XPropertySet > const& xFieldProperties)
4432{
4433 //create a sequence field master "AutoNr"
4434 uno::Reference< beans::XPropertySet > xMaster =
4435 FindOrCreateFieldMaster
4436 ("com.sun.star.text.FieldMaster.SetExpression",
4437 "AutoNr");
4438
4439 xMaster->setPropertyValue( getPropertyName(PROP_SUB_TYPE),
4440 uno::makeAny(text::SetVariableType::SEQUENCE));
4441
4442 //apply the numbering type
4443 xFieldProperties->setPropertyValue(
4444 getPropertyName(PROP_NUMBERING_TYPE),
4445 uno::makeAny( lcl_ParseNumberingType(pContext->GetCommand()) ));
4446 // attach the master to the field
4447 uno::Reference< text::XDependentTextField > xDependentField
4448 ( xFieldInterface, uno::UNO_QUERY_THROW );
4449 xDependentField->attachTextFieldMaster( xMaster );
4450}
4451
4452void DomainMapper_Impl::handleAuthor
4453 (OUString const& rFirstParam,
4454 uno::Reference< beans::XPropertySet > const& xFieldProperties,
4455 FieldId eFieldId )
4456{
4457 if ( eFieldId != FIELD_USERINITIALS )
4458 xFieldProperties->setPropertyValue
4459 ( getPropertyName(PROP_FULL_NAME), uno::makeAny( true ));
4460
4461 if (!rFirstParam.isEmpty())
4462 {
4463 xFieldProperties->setPropertyValue(
4464 getPropertyName( PROP_IS_FIXED ),
4465 uno::makeAny( true ));
4466 //PROP_CURRENT_PRESENTATION is set later anyway
4467 }
4468}
4469
4470 void DomainMapper_Impl::handleDocProperty
4471 (const FieldContextPtr& pContext,
4472 OUString const& rFirstParam,
4473 uno::Reference< uno::XInterface > & xFieldInterface)
4474{
4475 //some docproperties should be imported as document statistic fields, some as DocInfo fields
4476 //others should be user fields
4477 if (rFirstParam.isEmpty())
4478 return;
4479
4480 constexpr sal_uInt8 SET_ARABIC = 0x01;
4481 constexpr sal_uInt8 SET_DATE = 0x04;
4482 struct DocPropertyMap
4483 {
4484 const char* pDocPropertyName;
4485 const char* pServiceName;
4486 sal_uInt8 nFlags;
4487 };
4488 static const DocPropertyMap aDocProperties[] =
4489 {
4490 {"CreateTime", "DocInfo.CreateDateTime", SET_DATE},
4491 {"Characters", "CharacterCount", SET_ARABIC},
4492 {"Comments", "DocInfo.Description", 0},
4493 {"Keywords", "DocInfo.KeyWords", 0},
4494 {"LastPrinted", "DocInfo.PrintDateTime", 0},
4495 {"LastSavedBy", "DocInfo.ChangeAuthor", 0},
4496 {"LastSavedTime", "DocInfo.ChangeDateTime", SET_DATE},
4497 {"Paragraphs", "ParagraphCount", SET_ARABIC},
4498 {"RevisionNumber", "DocInfo.Revision", 0},
4499 {"Subject", "DocInfo.Subject", 0},
4500 {"Template", "TemplateName", 0},
4501 {"Title", "DocInfo.Title", 0},
4502 {"TotalEditingTime", "DocInfo.EditTime", 0},
4503 {"Words", "WordCount", SET_ARABIC}
4504
4505 //other available DocProperties:
4506 //Bytes, Category, CharactersWithSpaces, Company
4507 //HyperlinkBase,
4508 //Lines, Manager, NameofApplication, ODMADocId, Pages,
4509 //Security,
4510 };
4511 uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(m_xTextDocument, uno::UNO_QUERY);
4512 uno::Reference<document::XDocumentProperties> xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
4513 uno::Reference<beans::XPropertySet> xUserDefinedProps(xDocumentProperties->getUserDefinedProperties(), uno::UNO_QUERY_THROW);
4514 uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xUserDefinedProps->getPropertySetInfo();
4515 //search for a field mapping
4516 OUString sFieldServiceName;
4517 size_t nMap = 0;
4518 for( ; nMap < SAL_N_ELEMENTS(aDocProperties)(sizeof(sal_n_array_size(aDocProperties))); ++nMap )
4519 {
4520 if ((rFirstParam.equalsAscii(aDocProperties[nMap].pDocPropertyName)) && (!xPropertySetInfo->hasPropertyByName(rFirstParam)))
4521 {
4522 sFieldServiceName =
4523 OUString::createFromAscii
4524 (aDocProperties[nMap].pServiceName);
4525 break;
4526 }
4527 }
4528 OUString sServiceName("com.sun.star.text.TextField.");
4529 bool bIsCustomField = false;
4530 if(sFieldServiceName.isEmpty())
4531 {
4532 //create a custom property field
4533 sServiceName += "DocInfo.Custom";
4534 bIsCustomField = true;
4535 }
4536 else
4537 {
4538 sServiceName += sFieldServiceName;
4539 }
4540 if (m_xTextFactory.is())
4541 xFieldInterface = m_xTextFactory->createInstance(sServiceName);
4542 uno::Reference<beans::XPropertySet> xFieldProperties( xFieldInterface, uno::UNO_QUERY_THROW);
4543 if( bIsCustomField )
4544 {
4545 xFieldProperties->setPropertyValue(
4546 getPropertyName(PROP_NAME), uno::makeAny(rFirstParam));
4547 pContext->SetCustomField( xFieldProperties );
4548 }
4549 else
4550 {
4551 if(0 != (aDocProperties[nMap].nFlags & SET_ARABIC))
4552 xFieldProperties->setPropertyValue(
4553 getPropertyName(PROP_NUMBERING_TYPE),
4554 uno::makeAny( style::NumberingType::ARABIC ));
4555 else if(0 != (aDocProperties[nMap].nFlags & SET_DATE))
4556 {
4557 xFieldProperties->setPropertyValue(
4558 getPropertyName(PROP_IS_DATE),
4559 uno::makeAny( true ));
4560 SetNumberFormat( pContext->GetCommand(), xFieldProperties );
4561 }
4562 }
4563}
4564
4565static uno::Sequence< beans::PropertyValues > lcl_createTOXLevelHyperlinks( bool bHyperlinks, const OUString& sChapterNoSeparator,
4566 const uno::Sequence< beans::PropertyValues >& aLevel )
4567{
4568 //create a copy of the level and add two new entries - hyperlink start and end
4569 bool bChapterNoSeparator = !sChapterNoSeparator.isEmpty();
4570 sal_Int32 nAdd = (bHyperlinks && bChapterNoSeparator) ? 4 : 2;
4571 uno::Sequence< beans::PropertyValues > aNewLevel( aLevel.getLength() + nAdd);
4572 beans::PropertyValues* pNewLevel = aNewLevel.getArray();
4573 if( bHyperlinks )
4574 {
4575 beans::PropertyValues aHyperlink(1);
4576 aHyperlink[0].Name = getPropertyName( PROP_TOKEN_TYPE );
4577 aHyperlink[0].Value <<= getPropertyName( PROP_TOKEN_HYPERLINK_START );
4578 pNewLevel[0] = aHyperlink;
4579 aHyperlink[0].Value <<= getPropertyName( PROP_TOKEN_HYPERLINK_END );
4580 pNewLevel[aNewLevel.getLength() -1] = aHyperlink;
4581 }
4582 if( bChapterNoSeparator )
4583 {
4584 beans::PropertyValues aChapterNo(2);
4585 aChapterNo[0].Name = getPropertyName( PROP_TOKEN_TYPE );
4586 aChapterNo[0].Value <<= getPropertyName( PROP_TOKEN_CHAPTER_INFO );
4587 aChapterNo[1].Name = getPropertyName( PROP_CHAPTER_FORMAT );
4588 //todo: is ChapterFormat::Number correct?
4589 aChapterNo[1].Value <<= sal_Int16(text::ChapterFormat::NUMBER);
4590 pNewLevel[aNewLevel.getLength() - (bHyperlinks ? 4 : 2) ] = aChapterNo;
4591
4592 beans::PropertyValues aChapterSeparator(2);
4593 aChapterSeparator[0].Name = getPropertyName( PROP_TOKEN_TYPE );
4594 aChapterSeparator[0].Value <<= getPropertyName( PROP_TOKEN_TEXT );
4595 aChapterSeparator[1].Name = getPropertyName( PROP_TEXT );
4596 aChapterSeparator[1].Value <<= sChapterNoSeparator;
4597 pNewLevel[aNewLevel.getLength() - (bHyperlinks ? 3 : 1)] = aChapterSeparator;
4598 }
4599 //copy the 'old' entries except the last (page no)
4600 std::copy(aLevel.begin(), std::prev(aLevel.end()), std::next(aNewLevel.begin()));
4601 //copy page no entry (last or last but one depending on bHyperlinks
4602 sal_Int32 nPageNo = aNewLevel.getLength() - (bHyperlinks ? 2 : 3);
4603 pNewLevel[nPageNo] = aLevel[aLevel.getLength() - 1];
4604
4605 return aNewLevel;
4606}
4607
4608/// Returns title of the TOC placed in paragraph(s) before TOC field inside STD-frame
4609OUString DomainMapper_Impl::extractTocTitle()
4610{
4611 if (!m_xSdtEntryStart.is())
4612 return OUString();
4613
4614 uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
4615 if(!xTextAppend.is())
4616 return OUString();
4617
4618 // try-catch was added in the same way as inside appendTextSectionAfter()
4619 try
4620 {
4621 uno::Reference<text::XParagraphCursor> xCursor(xTextAppend->createTextCursorByRange(m_xSdtEntryStart), uno::UNO_QUERY_THROW);
4622 if (!xCursor.is())
4623 return OUString();
4624
4625 //the cursor has been moved to the end of the paragraph because of the appendTextPortion() calls
4626 xCursor->gotoStartOfParagraph( false );
4627 if (m_aTextAppendStack.top().xInsertPosition.is())
4628 xCursor->gotoRange( m_aTextAppendStack.top().xInsertPosition, true );
4629 else
4630 xCursor->gotoEnd( true );
4631
4632 // the paragraph after this new section might have been already inserted
4633 OUString sResult = xCursor->getString();
4634 if (sResult.endsWith(SAL_NEWLINE_STRING"\n"))
4635 sResult = sResult.copy(0, sResult.getLength() - SAL_N_ELEMENTS(SAL_NEWLINE_STRING)(sizeof(sal_n_array_size("\n"))) + 1);
4636
4637 return sResult;
4638 }
4639 catch(const uno::Exception&)
4640 {
4641 }
4642
4643 return OUString();
4644}
4645
4646css::uno::Reference<css::beans::XPropertySet>
4647DomainMapper_Impl::StartIndexSectionChecked(const OUString& sServiceName)
4648{
4649 if (m_bParaChanged)
4650 {
4651 finishParagraph(GetTopContextOfType(CONTEXT_PARAGRAPH), false); // resets m_bParaChanged
4652 PopProperties(CONTEXT_PARAGRAPH);
4653 PushProperties(CONTEXT_PARAGRAPH);
4654 SetIsFirstRun(true);
4655 // The first paragraph of the index that is continuation of just finished one needs to be
4656 // removed when finished (unless more content will arrive, which will set m_bParaChanged)
4657 m_bRemoveThisParagraph = true;
4658 }
4659 const auto& xTextAppend = GetTopTextAppend();
4660 const auto xTextRange = xTextAppend->getEnd();
4661 const auto xRet = createSectionForRange(xTextRange, xTextRange, sServiceName, false);
4662 if (!m_aTextAppendStack.top().xInsertPosition)
4663 {
4664 try
4665 {
4666 m_bStartedTOC = true;
4667 uno::Reference<text::XTextCursor> xTOCTextCursor
4668 = xTextRange->getText()->createTextCursor();
4669 assert(xTOCTextCursor.is())(static_cast <bool> (xTOCTextCursor.is()) ? void (0) : __assert_fail
("xTOCTextCursor.is()", "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 4669, __extension__ __PRETTY_FUNCTION__))
;
4670 xTOCTextCursor->gotoEnd(false);
4671 m_aTextAppendStack.push(TextAppendContext(xTextAppend, xTOCTextCursor));
4672 }
4673 catch (const uno::Exception&)
4674 {
4675 TOOLS_WARN_EXCEPTION("writerfilter.dmapper",do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "DomainMapper_Impl::StartIndexSectionChecked:"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "4676" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "DomainMapper_Impl::StartIndexSectionChecked:"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "DomainMapper_Impl::StartIndexSectionChecked:" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "4676" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "DomainMapper_Impl::StartIndexSectionChecked:" <<
" " << exceptionToString(tools_warn_exception)) == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "4676" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "DomainMapper_Impl::StartIndexSectionChecked:"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "DomainMapper_Impl::StartIndexSectionChecked:" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "4676" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
4676 "DomainMapper_Impl::StartIndexSectionChecked:")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "DomainMapper_Impl::StartIndexSectionChecked:"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "4676" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "DomainMapper_Impl::StartIndexSectionChecked:"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "DomainMapper_Impl::StartIndexSectionChecked:" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "4676" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "DomainMapper_Impl::StartIndexSectionChecked:" <<
" " << exceptionToString(tools_warn_exception)) == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "4676" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "DomainMapper_Impl::StartIndexSectionChecked:"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "DomainMapper_Impl::StartIndexSectionChecked:" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "4676" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
4677 }
4678 }
4679 return xRet;
4680}
4681
4682void DomainMapper_Impl::handleToc
4683 (const FieldContextPtr& pContext,
4684 const OUString & sTOCServiceName)
4685{
4686 OUString sValue;
4687 if (IsInHeaderFooter())
4688 m_bStartTOCHeaderFooter = true;
4689 bool bTableOfFigures = false;
4690 bool bHyperlinks = false;
4691 bool bFromOutline = false;
4692 bool bFromEntries = false;
4693 bool bHideTabLeaderPageNumbers = false ;
4694 bool bIsTabEntry = false ;
4695 bool bNewLine = false ;
4696 bool bParagraphOutlineLevel = false;
4697
4698 sal_Int16 nMaxLevel = 10;
4699 OUString sTemplate;
4700 OUString sChapterNoSeparator;
4701 OUString sFigureSequence;
4702 uno::Reference< beans::XPropertySet > xTOC;
4703 OUString aBookmarkName;
4704
4705// \a Builds a table of figures but does not include the captions's label and number
4706 if( lcl_FindInCommand( pContext->GetCommand(), 'a', sValue ))
4707 { //make it a table of figures
4708 bTableOfFigures = true;
4709 }
4710// \b Uses a bookmark to specify area of document from which to build table of contents
4711 if( lcl_FindInCommand( pContext->GetCommand(), 'b', sValue ))
4712 {
4713 aBookmarkName = sValue.trim().replaceAll("\"","");
4714 }
4715 if( lcl_FindInCommand( pContext->GetCommand(), 'c', sValue ))
4716// \c Builds a table of figures of the given label
4717 {
4718 //todo: sValue contains the label's name
4719 bTableOfFigures = true;
4720 sFigureSequence = sValue.trim();
4721 sFigureSequence = sFigureSequence.replaceAll("\"", "").replaceAll("'","");
4722 }
4723// \d Defines the separator between sequence and page numbers
4724 if( lcl_FindInCommand( pContext->GetCommand(), 'd', sValue ))
4725 {
4726 //todo: insert the chapter number into each level and insert the separator additionally
4727 sChapterNoSeparator = sValue;
4728 }
4729// \f Builds a table of contents using TC entries instead of outline levels
4730 if( lcl_FindInCommand( pContext->GetCommand(), 'f', sValue ))
4731 {
4732 //todo: sValue can contain a TOC entry identifier - use unclear
4733 bFromEntries = true;
4734 }
4735// \h Hyperlinks the entries and page numbers within the table of contents
4736 if( lcl_FindInCommand( pContext->GetCommand(), 'h', sValue ))
4737 {
4738 //todo: make all entries to hyperlinks
4739 bHyperlinks = true;
4740 }
4741// \l Defines the TC entries field level used to build a table of contents
4742// if( lcl_FindInCommand( pContext->GetCommand(), 'l', sValue ))
4743// {
4744 //todo: entries can only be included completely
4745// }
4746// \n Builds a table of contents or a range of entries, such as 1-9 in a table of contents without page numbers
4747// if( lcl_FindInCommand( pContext->GetCommand(), 'n', sValue ))
4748// {
4749 //todo: what does the description mean?
4750// }
4751// \o Builds a table of contents by using outline levels instead of TC entries
4752 if( lcl_FindInCommand( pContext->GetCommand(), 'o', sValue ))
4753 {
4754 bFromOutline = true;
4755 if (sValue.isEmpty())
4756 nMaxLevel = WW_OUTLINE_MAXsal_Int16( 9 );
4757 else
4758 {
4759 sal_Int32 nIndex = 0;
4760 sValue.getToken( 0, '-', nIndex );
4761 nMaxLevel = static_cast<sal_Int16>(nIndex != -1 ? sValue.copy(nIndex).toInt32() : 0);
4762 }
4763 }
4764// \p Defines the separator between the table entry and its page number
4765// \s Builds a table of contents by using a sequence type
4766// \t Builds a table of contents by using style names other than the standard outline styles
4767 if( lcl_FindInCommand( pContext->GetCommand(), 't', sValue ))
4768 {
4769 OUString sToken = sValue.getToken(1, '"');
4770 sTemplate = sToken.isEmpty() ? sValue : sToken;
4771 }
4772// \u Builds a table of contents by using the applied paragraph outline level
4773 if( lcl_FindInCommand( pContext->GetCommand(), 'u', sValue ))
4774 {
4775 bFromOutline = true;
4776 bParagraphOutlineLevel = true;
4777 //todo: what doesn 'the applied paragraph outline level' refer to?
4778 }
4779// \w Preserve tab characters within table entries
4780 if( lcl_FindInCommand( pContext->GetCommand(), 'w', sValue ))
4781 {
4782 bIsTabEntry = true ;
4783 }
4784// \x Preserve newline characters within table entries
4785 if( lcl_FindInCommand( pContext->GetCommand(), 'x', sValue ))
4786 {
4787 bNewLine = true ;
4788 }
4789// \z Hides page numbers within the table of contents when shown in Web Layout View
4790 if( lcl_FindInCommand( pContext->GetCommand(), 'z', sValue ))
4791 {
4792 bHideTabLeaderPageNumbers = true ;
4793 }
4794
4795 //if there's no option then it should be created from outline
4796 if( !bFromOutline && !bFromEntries && sTemplate.isEmpty() )
4797 bFromOutline = true;
4798
4799 const OUString aTocTitle = extractTocTitle();
4800
4801 if (m_xTextFactory.is() && ! m_aTextAppendStack.empty())
4802 {
4803 const auto& xTextAppend = GetTopTextAppend();
4804 if (aTocTitle.isEmpty() || bTableOfFigures)
4805 {
4806 // reset marker of the TOC title
4807 m_xSdtEntryStart.clear();
4808
4809 // Create section before setting m_bStartTOC: finishing paragraph
4810 // inside StartIndexSectionChecked could do the wrong thing otherwise
4811 xTOC = StartIndexSectionChecked(bTableOfFigures ? "com.sun.star.text.IllustrationsIndex"
4812 : sTOCServiceName);
4813
4814 const auto xTextCursor = xTextAppend->getText()->createTextCursor();
4815 if (xTextCursor)
4816 xTextCursor->gotoEnd(false);
4817 xTOCMarkerCursor = xTextCursor;
4818 }
4819 else
4820 {
4821 // create TOC section
4822 css::uno::Reference<css::text::XTextRange> xTextRangeEndOfTocHeader = GetTopTextAppend()->getEnd();
4823 xTOC = createSectionForRange(m_xSdtEntryStart, xTextRangeEndOfTocHeader, sTOCServiceName, false);
4824
4825 // init [xTOCMarkerCursor]
4826 uno::Reference< text::XText > xText = xTextAppend->getText();
4827 uno::Reference< text::XTextCursor > xCrsr = xText->createTextCursor();
4828 xTOCMarkerCursor = xCrsr;
4829
4830 // create header of the TOC with the TOC title inside
4831 createSectionForRange(m_xSdtEntryStart, xTextRangeEndOfTocHeader, "com.sun.star.text.IndexHeaderSection", true);
4832 }
4833 }
4834
4835 m_bStartTOC = true;
4836
4837 if (xTOC.is())
4838 xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::makeAny(aTocTitle));
4839
4840 if (!aBookmarkName.isEmpty())
4841 xTOC->setPropertyValue(getPropertyName(PROP_TOC_BOOKMARK), uno::makeAny(aBookmarkName));
4842 if( !bTableOfFigures && xTOC.is() )
4843 {
4844 xTOC->setPropertyValue( getPropertyName( PROP_LEVEL ), uno::makeAny( nMaxLevel ) );
4845 xTOC->setPropertyValue( getPropertyName( PROP_CREATE_FROM_OUTLINE ), uno::makeAny( bFromOutline ));
4846 xTOC->setPropertyValue( getPropertyName( PROP_CREATE_FROM_MARKS ), uno::makeAny( bFromEntries ));
4847 xTOC->setPropertyValue( getPropertyName( PROP_HIDE_TAB_LEADER_AND_PAGE_NUMBERS ), uno::makeAny( bHideTabLeaderPageNumbers ));
4848 xTOC->setPropertyValue( getPropertyName( PROP_TAB_IN_TOC ), uno::makeAny( bIsTabEntry ));
4849 xTOC->setPropertyValue( getPropertyName( PROP_TOC_NEW_LINE ), uno::makeAny( bNewLine ));
4850 xTOC->setPropertyValue( getPropertyName( PROP_TOC_PARAGRAPH_OUTLINE_LEVEL ), uno::makeAny( bParagraphOutlineLevel ));
4851 if( !sTemplate.isEmpty() )
4852 {
4853 //the string contains comma separated the names and related levels
4854 //like: "Heading 1,1,Heading 2,2"
4855 TOCStyleMap aMap;
4856 sal_Int32 nLevel;
4857 sal_Int32 nPosition = 0;
4858 while( nPosition >= 0)
4859 {
4860 OUString sStyleName = sTemplate.getToken( 0, ',', nPosition );
4861 //empty tokens should be skipped
4862 while( sStyleName.isEmpty() && nPosition > 0 )
4863 sStyleName = sTemplate.getToken( 0, ',', nPosition );
4864 nLevel = sTemplate.getToken( 0, ',', nPosition ).toInt32();
4865 if( !nLevel )
4866 nLevel = 1;
4867 if( !sStyleName.isEmpty() )
4868 aMap.emplace(nLevel, sStyleName);
4869 }
4870 uno::Reference< container::XIndexReplace> xParaStyles;
4871 xTOC->getPropertyValue(getPropertyName(PROP_LEVEL_PARAGRAPH_STYLES)) >>= xParaStyles;
4872 for( nLevel = 1; nLevel < 10; ++nLevel)
4873 {
4874 sal_Int32 nLevelCount = aMap.count( nLevel );
4875 if( nLevelCount )
4876 {
4877 TOCStyleMap::iterator aTOCStyleIter = aMap.find( nLevel );
4878
4879 uno::Sequence< OUString> aStyles( nLevelCount );
4880 for ( sal_Int32 nStyle = 0; nStyle < nLevelCount; ++nStyle, ++aTOCStyleIter )
4881 {
4882 aStyles[nStyle] = aTOCStyleIter->second;
4883 }
4884 xParaStyles->replaceByIndex(nLevel - 1, uno::makeAny(aStyles));
4885 }
4886 }
4887 xTOC->setPropertyValue(getPropertyName(PROP_CREATE_FROM_LEVEL_PARAGRAPH_STYLES), uno::makeAny( true ));
4888
4889 }
4890 if(bHyperlinks || !sChapterNoSeparator.isEmpty())
4891 {
4892 uno::Reference< container::XIndexReplace> xLevelFormats;
4893 xTOC->getPropertyValue(getPropertyName(PROP_LEVEL_FORMAT)) >>= xLevelFormats;
4894 sal_Int32 nLevelCount = xLevelFormats->getCount();
4895 //start with level 1, 0 is the header level
4896 for( sal_Int32 nLevel = 1; nLevel < nLevelCount; ++nLevel)
4897 {
4898 uno::Sequence< beans::PropertyValues > aLevel;
4899 xLevelFormats->getByIndex( nLevel ) >>= aLevel;
4900
4901 uno::Sequence< beans::PropertyValues > aNewLevel = lcl_createTOXLevelHyperlinks(
4902 bHyperlinks, sChapterNoSeparator,
4903 aLevel );
4904 xLevelFormats->replaceByIndex( nLevel, uno::makeAny( aNewLevel ) );
4905 }
4906 }
4907 }
4908 else if (bTableOfFigures && xTOC.is())
4909 {
4910 if (!sFigureSequence.isEmpty())
4911 xTOC->setPropertyValue(getPropertyName(PROP_LABEL_CATEGORY),
4912 uno::makeAny(sFigureSequence));
4913
4914 if ( bHyperlinks )
4915 {
4916 uno::Reference< container::XIndexReplace> xLevelFormats;
4917 xTOC->getPropertyValue(getPropertyName(PROP_LEVEL_FORMAT)) >>= xLevelFormats;
4918 uno::Sequence< beans::PropertyValues > aLevel;
4919 xLevelFormats->getByIndex( 1 ) >>= aLevel;
4920
4921 uno::Sequence< beans::PropertyValues > aNewLevel = lcl_createTOXLevelHyperlinks(
4922 bHyperlinks, sChapterNoSeparator,
4923 aLevel );
4924 xLevelFormats->replaceByIndex( 1, uno::makeAny( aNewLevel ) );
4925 }
4926 }
4927 pContext->SetTOC( xTOC );
4928 m_bParaHadField = false;
4929}
4930
4931uno::Reference<beans::XPropertySet> DomainMapper_Impl::createSectionForRange(
4932 uno::Reference< css::text::XTextRange > xStart,
4933 uno::Reference< css::text::XTextRange > xEnd,
4934 const OUString & sObjectType,
4935 bool stepLeft)
4936{
4937 if (!xStart.is())
4938 return uno::Reference<beans::XPropertySet>();
4939 if (!xEnd.is())
4940 return uno::Reference<beans::XPropertySet>();
4941
4942 uno::Reference< beans::XPropertySet > xRet;
4943 if (m_aTextAppendStack.empty())
4944 return xRet;
4945 uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
4946 if(xTextAppend.is())
4947 {
4948 try
4949 {
4950 uno::Reference< text::XParagraphCursor > xCursor(
4951 xTextAppend->createTextCursorByRange( xStart ), uno::UNO_QUERY_THROW);
4952 //the cursor has been moved to the end of the paragraph because of the appendTextPortion() calls
4953 xCursor->gotoStartOfParagraph( false );
4954 xCursor->gotoRange( xEnd, true );
4955 //the paragraph after this new section is already inserted
4956 if (stepLeft)
4957 xCursor->goLeft(1, true);
4958 uno::Reference< text::XTextContent > xSection( m_xTextFactory->createInstance(sObjectType), uno::UNO_QUERY_THROW );
4959 xSection->attach( uno::Reference< text::XTextRange >( xCursor, uno::UNO_QUERY_THROW) );
4960 xRet.set(xSection, uno::UNO_QUERY );
4961 }
4962 catch(const uno::Exception&)
4963 {
4964 }
4965 }
4966
4967 return xRet;
4968}
4969
4970void DomainMapper_Impl::handleBibliography
4971 (const FieldContextPtr& pContext,
4972 const OUString & sTOCServiceName)
4973{
4974 if (m_aTextAppendStack.empty())
4975 {
4976 // tdf#130214: a workaround to avoid crash on import errors
4977 SAL_WARN("writerfilter.dmapper", "no text append stack")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "no text append stack"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "4977" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no text append stack"), 0); } else {
::std::ostringstream sal_detail_stream; sal_detail_stream <<
"no text append stack"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "4977" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "no text append stack") == 1) { ::sal_detail_log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "4977" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no text append stack"), 0); } else {
::std::ostringstream sal_detail_stream; sal_detail_stream <<
"no text append stack"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "4977" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
4978 return;
4979 }
4980 // Create section before setting m_bStartTOC and m_bStartBibliography: finishing paragraph
4981 // inside StartIndexSectionChecked could do the wrong thing otherwise
4982 const auto xTOC = StartIndexSectionChecked(sTOCServiceName);
4983 m_bStartTOC = true;
4984 m_bStartBibliography = true;
4985
4986 if (xTOC.is())
4987 xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::makeAny(OUString()));
4988
4989 pContext->SetTOC( xTOC );
4990 m_bParaHadField = false;
4991
4992 uno::Reference< text::XTextContent > xToInsert( xTOC, uno::UNO_QUERY );
4993 appendTextContent(xToInsert, uno::Sequence< beans::PropertyValue >() );
4994}
4995
4996void DomainMapper_Impl::handleIndex
4997 (const FieldContextPtr& pContext,
4998 const OUString & sTOCServiceName)
4999{
5000 // Create section before setting m_bStartTOC and m_bStartIndex: finishing paragraph
5001 // inside StartIndexSectionChecked could do the wrong thing otherwise
5002 const auto xTOC = StartIndexSectionChecked(sTOCServiceName);
5003
5004 m_bStartTOC = true;
5005 m_bStartIndex = true;
5006 OUString sValue;
5007 OUString sIndexEntryType = "I"; // Default value for field flag '\f' is 'I'.
5008
5009 if (xTOC.is())
5010 {
5011 xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::makeAny(OUString()));
5012
5013 if( lcl_FindInCommand( pContext->GetCommand(), 'r', sValue ))
5014 {
5015 xTOC->setPropertyValue("IsCommaSeparated", uno::makeAny(true));
5016 }
5017 if( lcl_FindInCommand( pContext->GetCommand(), 'h', sValue ))
5018 {
5019 xTOC->setPropertyValue("UseAlphabeticalSeparators", uno::makeAny(true));
5020 }
5021 if( lcl_FindInCommand( pContext->GetCommand(), 'f', sValue ))
5022 {
5023 if(!sValue.isEmpty())
5024 sIndexEntryType = sValue ;
5025 xTOC->setPropertyValue(getPropertyName( PROP_INDEX_ENTRY_TYPE ), uno::makeAny(sIndexEntryType));
5026 }
5027 }
5028 pContext->SetTOC( xTOC );
5029 m_bParaHadField = false;
5030
5031 uno::Reference< text::XTextContent > xToInsert( xTOC, uno::UNO_QUERY );
5032 appendTextContent(xToInsert, uno::Sequence< beans::PropertyValue >() );
5033
5034 if( lcl_FindInCommand( pContext->GetCommand(), 'c', sValue ))
5035 {
5036 sValue = sValue.replaceAll("\"", "");
5037 uno::Reference<text::XTextColumns> xTextColumns;
5038 xTOC->getPropertyValue(getPropertyName( PROP_TEXT_COLUMNS )) >>= xTextColumns;
5039 if (xTextColumns.is())
5040 {
5041 xTextColumns->setColumnCount( sValue.toInt32() );
5042 xTOC->setPropertyValue( getPropertyName( PROP_TEXT_COLUMNS ), uno::makeAny( xTextColumns ) );
5043 }
5044 }
5045}
5046
5047static auto InsertFieldmark(std::stack<TextAppendContext> & rTextAppendStack,
5048 uno::Reference<text::XFormField> const& xFormField,
5049 uno::Reference<text::XTextRange> const& xStartRange,
5050 std::optional<FieldId> const oFieldId) -> void
5051{
5052 uno::Reference<text::XTextContent> const xTextContent(xFormField, uno::UNO_QUERY_THROW);
5053 uno::Reference<text::XTextAppend> const& xTextAppend(rTextAppendStack.top().xTextAppend);
5054 uno::Reference<text::XTextCursor> const xCursor =
5055 xTextAppend->createTextCursorByRange(xStartRange);
5056 if (rTextAppendStack.top().xInsertPosition.is())
5057 {
5058 uno::Reference<text::XTextRangeCompare> const xCompare(
5059 rTextAppendStack.top().xTextAppend,
5060 uno::UNO_QUERY);
5061 if (xCompare->compareRegionStarts(xStartRange, rTextAppendStack.top().xInsertPosition) < 0)
5062 {
5063 SAL_WARN("writerfilter.dmapper", "invalid field mark positions")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "invalid field mark positions"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5063" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid field mark positions"), 0);
} else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "invalid field mark positions"; ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5063" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "invalid field mark positions") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5063" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid field mark positions"), 0);
} else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "invalid field mark positions"; ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5063" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
5064 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 5064, __extension__ __PRETTY_FUNCTION__))
;
5065 }
5066 xCursor->gotoRange(rTextAppendStack.top().xInsertPosition, true);
5067 }
5068 else
5069 {
5070 xCursor->gotoEnd(true);
5071 }
5072 xTextAppend->insertTextContent(xCursor, xTextContent, true);
5073 if (oFieldId
5074 && (oFieldId == FIELD_FORMCHECKBOX || oFieldId == FIELD_FORMDROPDOWN))
5075 {
5076 return; // only a single CH_TXT_ATR_FORMELEMENT!
5077 }
5078 // problem: the fieldmark must be inserted in CloseFieldCommand(), because
5079 // attach() takes 2 positions, not 3!
5080 // FAIL: AppendTextNode() ignores the content index!
5081 // plan B: insert a spurious paragraph break now and join
5082 // it in PopFieldContext()!
5083 xCursor->gotoRange(xTextContent->getAnchor()->getEnd(), false);
5084 xCursor->goLeft(1, false); // skip CH_TXT_ATR_FIELDEND
5085 xTextAppend->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
5086 xCursor->goLeft(1, false); // back to previous paragraph
5087 rTextAppendStack.push(TextAppendContext(xTextAppend, xCursor));
5088}
5089
5090static auto PopFieldmark(std::stack<TextAppendContext> & rTextAppendStack,
5091 uno::Reference<text::XTextCursor> const& xCursor,
5092 std::optional<FieldId> const oFieldId) -> void
5093{
5094 if (oFieldId
5095 && (oFieldId == FIELD_FORMCHECKBOX || oFieldId == FIELD_FORMDROPDOWN))
5096 {
5097 return; // only a single CH_TXT_ATR_FORMELEMENT!
5098 }
5099 xCursor->gotoRange(rTextAppendStack.top().xInsertPosition, false);
5100 xCursor->goRight(1, true);
5101 xCursor->setString(OUString()); // undo SplitNode from CloseFieldCommand()
5102 // note: paragraph properties will be overwritten
5103 // by finishParagraph() anyway so ignore here
5104 rTextAppendStack.pop();
5105}
5106
5107void DomainMapper_Impl::CloseFieldCommand()
5108{
5109 if(m_bDiscardHeaderFooter)
5110 return;
5111#ifdef DBG_UTIL
5112 TagLogger::getInstance().element("closeFieldCommand");
5113#endif
5114
5115 FieldContextPtr pContext;
5116 if(!m_aFieldStack.empty())
5117 pContext = m_aFieldStack.back();
5118 OSL_ENSURE( pContext, "no field context available")do { if (true && (!(pContext))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5118" ": "), "%s", "no field context available"); } } while
(false)
;
5119 if( !pContext )
5120 return;
5121
5122 m_bSetUserFieldContent = false;
5123 m_bSetCitation = false;
5124 m_bSetDateValue = false;
5125 const FieldConversionMap_t& aFieldConversionMap = lcl_GetFieldConversion();
5126
5127 try
5128 {
5129 uno::Reference< uno::XInterface > xFieldInterface;
5130
5131 const auto& [sType, vArguments, vSwitches]{ splitFieldCommand(pContext->GetCommand()) };
5132 (void)vSwitches;
5133 OUString const sFirstParam(vArguments.empty() ? OUString() : vArguments.front());
5134
5135 // apply font size to the form control
5136 if (!m_aTextAppendStack.empty() && m_pLastCharacterContext && ( m_pLastCharacterContext->isSet(PROP_CHAR_HEIGHT) || m_pLastCharacterContext->isSet(PROP_CHAR_FONT_NAME )))
5137 {
5138 uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
5139 if (xTextAppend.is())
5140 {
5141 uno::Reference< text::XTextCursor > xCrsr = xTextAppend->getText()->createTextCursor();
5142 if (xCrsr.is())
5143 {
5144 xCrsr->gotoEnd(false);
5145 uno::Reference< beans::XPropertySet > xProp( xCrsr, uno::UNO_QUERY );
5146 if (m_pLastCharacterContext->isSet(PROP_CHAR_HEIGHT))
5147 {
5148 xProp->setPropertyValue(getPropertyName(PROP_CHAR_HEIGHT), m_pLastCharacterContext->getProperty(PROP_CHAR_HEIGHT)->second);
5149 if (m_pLastCharacterContext->isSet(PROP_CHAR_HEIGHT_COMPLEX))
5150 xProp->setPropertyValue(getPropertyName(PROP_CHAR_HEIGHT_COMPLEX), m_pLastCharacterContext->getProperty(PROP_CHAR_HEIGHT_COMPLEX)->second);
5151 }
5152 if (m_pLastCharacterContext->isSet(PROP_CHAR_FONT_NAME))
5153 xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME), m_pLastCharacterContext->getProperty(PROP_CHAR_FONT_NAME)->second);
5154 }
5155 }
5156 }
5157
5158 FieldConversionMap_t::const_iterator const aIt = aFieldConversionMap.find(sType);
5159 if (aIt != aFieldConversionMap.end()
5160 && (!m_bForceGenericFields
5161 // these need to convert ffData to properties...
5162 || (aIt->second.eFieldId == FIELD_FORMCHECKBOX)
5163 || (aIt->second.eFieldId == FIELD_FORMDROPDOWN)
5164 || (aIt->second.eFieldId == FIELD_FORMTEXT)))
5165 {
5166 pContext->SetFieldId(aIt->second.eFieldId);
5167 bool bCreateEnhancedField = false;
5168 uno::Reference< beans::XPropertySet > xFieldProperties;
5169 bool bCreateField = true;
5170 switch (aIt->second.eFieldId)
5171 {
5172 case FIELD_HYPERLINK:
5173 case FIELD_DOCPROPERTY:
5174 case FIELD_TOC:
5175 case FIELD_INDEX:
5176 case FIELD_XE:
5177 case FIELD_BIBLIOGRAPHY:
5178 case FIELD_CITATION:
5179 case FIELD_TC:
5180 case FIELD_EQ:
5181 case FIELD_INCLUDEPICTURE:
5182 case FIELD_SYMBOL:
5183 case FIELD_GOTOBUTTON:
5184 bCreateField = false;
5185 break;
5186 case FIELD_FORMCHECKBOX :
5187 case FIELD_FORMTEXT :
5188 case FIELD_FORMDROPDOWN :
5189 {
5190 // If we use 'enhanced' fields then FIELD_FORMCHECKBOX,
5191 // FIELD_FORMTEXT & FIELD_FORMDROPDOWN are treated specially
5192 if ( m_bUsingEnhancedFields )
5193 {
5194 bCreateField = false;
5195 bCreateEnhancedField = true;
5196 }
5197 // for non enhanced fields checkboxes are displayed
5198 // as an awt control not a field
5199 else if ( aIt->second.eFieldId == FIELD_FORMCHECKBOX )
5200 bCreateField = false;
5201 break;
5202 }
5203 default:
5204 {
5205 FieldContextPtr pOuter = GetParentFieldContext(m_aFieldStack);
5206 if (pOuter)
5207 {
5208 if (!IsFieldNestingAllowed(pOuter, m_aFieldStack.back()))
5209 {
5210 // Parent field can't host this child field: don't create a child field
5211 // in this case.
5212 bCreateField = false;
5213 }
5214 }
5215 break;
5216 }
5217 }
5218 if (m_bStartTOC && (aIt->second.eFieldId == FIELD_PAGEREF) )
5219 {
5220 bCreateField = false;
5221 }
5222
5223 if( bCreateField || bCreateEnhancedField )
5224 {
5225 //add the service prefix
5226 OUString sServiceName("com.sun.star.text.");
5227 if ( bCreateEnhancedField )
5228 {
5229 const FieldConversionMap_t& aEnhancedFieldConversionMap = lcl_GetEnhancedFieldConversion();
5230 FieldConversionMap_t::const_iterator aEnhancedIt =
5231 aEnhancedFieldConversionMap.find(sType);
5232 if ( aEnhancedIt != aEnhancedFieldConversionMap.end())
5233 sServiceName += OUString::createFromAscii(aEnhancedIt->second.cFieldServiceName );
5234 }
5235 else
5236 {
5237 sServiceName += "TextField." + OUString::createFromAscii(aIt->second.cFieldServiceName );
5238 }
5239
5240#ifdef DBG_UTIL
5241 TagLogger::getInstance().startElement("fieldService");
5242 TagLogger::getInstance().chars(sServiceName);
5243 TagLogger::getInstance().endElement();
5244#endif
5245
5246 if (m_xTextFactory.is())
5247 {
5248 xFieldInterface = m_xTextFactory->createInstance(sServiceName);
5249 xFieldProperties.set( xFieldInterface, uno::UNO_QUERY_THROW);
5250 }
5251 }
5252 switch( aIt->second.eFieldId )
5253 {
5254 case FIELD_ADDRESSBLOCK: break;
5255 case FIELD_ADVANCE : break;
5256 case FIELD_ASK :
5257 handleFieldAsk(pContext, xFieldInterface, xFieldProperties);
5258 break;
5259 case FIELD_AUTONUM :
5260 case FIELD_AUTONUMLGL :
5261 case FIELD_AUTONUMOUT :
5262 handleAutoNum(pContext, xFieldInterface, xFieldProperties);
5263 break;
5264 case FIELD_AUTHOR :
5265 case FIELD_USERNAME :
5266 case FIELD_USERINITIALS :
5267 handleAuthor(sFirstParam,
5268 xFieldProperties,
5269 aIt->second.eFieldId);
5270 break;
5271 case FIELD_DATE:
5272 if (xFieldProperties.is())
5273 {
5274 // Get field fixed property from the context handler
5275 if (pContext->IsFieldLocked())
5276 {
5277 xFieldProperties->setPropertyValue(
5278 getPropertyName(PROP_IS_FIXED),
5279 uno::makeAny( true ));
5280 m_bSetDateValue = true;
5281 }
5282 else
5283 xFieldProperties->setPropertyValue(
5284 getPropertyName(PROP_IS_FIXED),
5285 uno::makeAny( false ));
5286
5287 xFieldProperties->setPropertyValue(
5288 getPropertyName(PROP_IS_DATE),
5289 uno::makeAny( true ));
5290 SetNumberFormat( pContext->GetCommand(), xFieldProperties );
5291 }
5292 break;
5293 case FIELD_COMMENTS :
5294 {
5295 // OUString sParam = lcl_ExtractParameter(pContext->GetCommand(), sizeof(" COMMENTS") );
5296 // A parameter with COMMENTS shouldn't set fixed
5297 // ( or at least the binary filter doesn't )
5298 // If we set fixed then we won't export a field cmd.
5299 // Additionally the para in COMMENTS is more like an
5300 // instruction to set the document property comments
5301 // with the param ( e.g. each COMMENT with a param will
5302 // overwrite the Comments document property
5303 // #TODO implement the above too
5304 xFieldProperties->setPropertyValue(
5305 getPropertyName( PROP_IS_FIXED ), uno::makeAny( false ));
5306 //PROP_CURRENT_PRESENTATION is set later anyway
5307 }
5308 break;
5309 case FIELD_CREATEDATE :
5310 {
5311 xFieldProperties->setPropertyValue(
5312 getPropertyName( PROP_IS_DATE ), uno::makeAny( true ));
5313 SetNumberFormat( pContext->GetCommand(), xFieldProperties );
5314 }
5315 break;
5316 case FIELD_DOCPROPERTY :
5317 handleDocProperty(pContext, sFirstParam,
5318 xFieldInterface);
5319 break;
5320 case FIELD_DOCVARIABLE :
5321 {
5322 //create a user field and type
5323 uno::Reference< beans::XPropertySet > xMaster =
5324 FindOrCreateFieldMaster("com.sun.star.text.FieldMaster.User", sFirstParam);
5325 uno::Reference< text::XDependentTextField > xDependentField( xFieldInterface, uno::UNO_QUERY_THROW );
5326 xDependentField->attachTextFieldMaster( xMaster );
5327 m_bSetUserFieldContent = true;
5328 }
5329 break;
5330 case FIELD_EDITTIME :
5331 //it's a numbering type, no number format! SetNumberFormat( pContext->GetCommand(), xFieldProperties );
5332 break;
5333 case FIELD_EQ:
5334 {
5335 OUString aCommand = pContext->GetCommand().trim();
5336
5337 msfilter::util::EquationResult aResult(msfilter::util::ParseCombinedChars(aCommand));
5338 if (!aResult.sType.isEmpty() && m_xTextFactory.is())
5339 {
5340 xFieldInterface = m_xTextFactory->createInstance("com.sun.star.text.TextField." + aResult.sType);
5341 xFieldProperties =
5342 uno::Reference< beans::XPropertySet >( xFieldInterface,
5343 uno::UNO_QUERY_THROW);
5344 xFieldProperties->setPropertyValue(getPropertyName(PROP_CONTENT), uno::makeAny(aResult.sResult));
5345 }
5346 else
5347 {
5348 //merge Read_SubF_Ruby into filter/.../util.cxx and reuse that ?
5349 sal_Int32 nSpaceIndex = aCommand.indexOf(' ');
5350 if(nSpaceIndex > 0)
5351 aCommand = aCommand.copy(nSpaceIndex).trim();
5352 if (aCommand.startsWith("\\s"))
5353 {
5354 aCommand = aCommand.copy(2);
5355 if (aCommand.startsWith("\\do"))
5356 {
5357 aCommand = aCommand.copy(3);
5358 sal_Int32 nStartIndex = aCommand.indexOf('(');
5359 sal_Int32 nEndIndex = aCommand.indexOf(')');
5360 if (nStartIndex > 0 && nEndIndex > 0)
5361 {
5362 // nDown is the requested "lower by" value in points.
5363 sal_Int32 nDown = aCommand.copy(0, nStartIndex).toInt32();
5364 OUString aContent = aCommand.copy(nStartIndex + 1, nEndIndex - nStartIndex - 1);
5365 PropertyMapPtr pCharContext = GetTopContext();
5366 // dHeight is the font size of the current style.
5367 double dHeight = 0;
5368 if ((GetPropertyFromParaStyleSheet(PROP_CHAR_HEIGHT) >>= dHeight) && dHeight != 0)
5369 // Character escapement should be given in negative percents for subscripts.
5370 pCharContext->Insert(PROP_CHAR_ESCAPEMENT, uno::makeAny( sal_Int16(- 100 * nDown / dHeight) ) );
5371 appendTextPortion(aContent, pCharContext);
5372 }
5373 }
5374 }
5375 else if (aCommand.startsWith("\\* jc"))
5376 {
5377 handleRubyEQField(pContext);
5378 }
5379 }
5380 }
5381 break;
5382 case FIELD_FILLIN :
5383 if (xFieldProperties.is())
5384 xFieldProperties->setPropertyValue(
5385 getPropertyName(PROP_HINT), uno::makeAny( pContext->GetCommand().getToken(1, '\"')));
5386 break;
5387 case FIELD_FILENAME:
5388 {
5389 sal_Int32 nNumberingTypeIndex = pContext->GetCommand().indexOf("\\p");
5390 if (xFieldProperties.is())
5391 xFieldProperties->setPropertyValue(
5392 getPropertyName(PROP_FILE_FORMAT),
5393 uno::makeAny( nNumberingTypeIndex > 0 ? text::FilenameDisplayFormat::FULL : text::FilenameDisplayFormat::NAME_AND_EXT ));
5394 }
5395 break;
5396 case FIELD_FILESIZE : break;
5397 case FIELD_FORMULA :
5398 handleFieldFormula(pContext, xFieldProperties);
5399 break;
5400 case FIELD_FORMCHECKBOX :
5401 case FIELD_FORMDROPDOWN :
5402 case FIELD_FORMTEXT :
5403 {
5404 uno::Reference< text::XTextField > xTextField( xFieldInterface, uno::UNO_QUERY );
5405 if ( !xTextField.is() )
5406 {
5407 FFDataHandler::Pointer_t
5408 pFFDataHandler(pContext->getFFDataHandler());
5409 FormControlHelper::Pointer_t
5410 pFormControlHelper(new FormControlHelper
5411 (m_bUsingEnhancedFields ? aIt->second.eFieldId : FIELD_FORMCHECKBOX,
5412
5413 m_xTextDocument, pFFDataHandler));
5414 pContext->setFormControlHelper(pFormControlHelper);
5415 uno::Reference< text::XFormField > xFormField( xFieldInterface, uno::UNO_QUERY );
5416 uno::Reference< container::XNamed > xNamed( xFormField, uno::UNO_QUERY );
5417 if ( xNamed.is() )
5418 {
5419 if ( pFFDataHandler && !pFFDataHandler->getName().isEmpty() )
5420 xNamed->setName( pFFDataHandler->getName() );
5421 pContext->SetFormField( xFormField );
5422 }
5423 InsertFieldmark(m_aTextAppendStack,
5424 xFormField, pContext->GetStartRange(),
5425 pContext->GetFieldId());
5426 }
5427 else
5428 {
5429 if ( aIt->second.eFieldId == FIELD_FORMDROPDOWN )
5430 lcl_handleDropdownField( xFieldProperties, pContext->getFFDataHandler() );
5431 else
5432 lcl_handleTextField( xFieldProperties, pContext->getFFDataHandler() );
5433 }
5434 }
5435 break;
5436 case FIELD_GOTOBUTTON : break;
5437 case FIELD_HYPERLINK:
5438 {
5439 ::std::vector<OUString> aParts = pContext->GetCommandParts();
5440
5441 // Syntax is either:
5442 // HYPERLINK "" \l "link"
5443 // or
5444 // HYPERLINK \l "link"
5445 // Make sure "HYPERLINK" doesn't end up as part of link in the second case.
5446 if (!aParts.empty() && aParts[0] == "HYPERLINK")
5447 aParts.erase(aParts.begin());
5448
5449 ::std::vector<OUString>::const_iterator aItEnd = aParts.end();
5450 ::std::vector<OUString>::const_iterator aPartIt = aParts.begin();
5451
5452 OUString sURL;
5453 OUString sTarget;
5454
5455 while (aPartIt != aItEnd)
5456 {
5457 if ( *aPartIt == "\\l" )
5458 {
5459 ++aPartIt;
5460
5461 if (aPartIt == aItEnd)
5462 break;
5463
5464 sURL += "#" + *aPartIt;
5465 }
5466 else if (*aPartIt == "\\m" || *aPartIt == "\\n" || *aPartIt == "\\h")
5467 {
5468 }
5469 else if ( *aPartIt == "\\o" || *aPartIt == "\\t" )
5470 {
5471 ++aPartIt;
5472
5473 if (aPartIt == aItEnd)
5474 break;
5475
5476 sTarget = *aPartIt;
5477 }
5478 else
5479 {
5480 sURL = *aPartIt;
5481 }
5482
5483 ++aPartIt;
5484 }
5485
5486 if (!sURL.isEmpty())
5487 {
5488 if (sURL.startsWith("file:///"))
5489 {
5490 // file:///absolute\\path\\to\\file => invalid file URI (Writer cannot open)
5491 // convert all double backslashes to slashes:
5492 sURL = sURL.replaceAll("\\\\", "/");
5493
5494 // file:///absolute\path\to\file => invalid file URI (Writer cannot open)
5495 // convert all backslashes to slashes:
5496 sURL = sURL.replace('\\', '/');
5497 }
5498 // Try to make absolute any relative URLs, except
5499 // for relative same-document URLs that only contain
5500 // a fragment part:
5501 else if (!sURL.startsWith("#")) {
5502 try {
5503 sURL = rtl::Uri::convertRelToAbs(
5504 m_aBaseUrl, sURL);
5505 } catch (rtl::MalformedUriException & e) {
5506 SAL_WARN(do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "MalformedUriException "
<< e.getMessage()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "MalformedUriException " << e.
getMessage()), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "MalformedUriException " <<
e.getMessage(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "MalformedUriException " << e.getMessage())
== 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "MalformedUriException " << e.
getMessage()), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "MalformedUriException " <<
e.getMessage(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
5507 "writerfilter.dmapper",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "MalformedUriException "
<< e.getMessage()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "MalformedUriException " << e.
getMessage()), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "MalformedUriException " <<
e.getMessage(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "MalformedUriException " << e.getMessage())
== 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "MalformedUriException " << e.
getMessage()), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "MalformedUriException " <<
e.getMessage(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
5508 "MalformedUriException "do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "MalformedUriException "
<< e.getMessage()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "MalformedUriException " << e.
getMessage()), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "MalformedUriException " <<
e.getMessage(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "MalformedUriException " << e.getMessage())
== 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "MalformedUriException " << e.
getMessage()), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "MalformedUriException " <<
e.getMessage(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
5509 << e.getMessage())do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "MalformedUriException "
<< e.getMessage()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "MalformedUriException " << e.
getMessage()), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "MalformedUriException " <<
e.getMessage(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "MalformedUriException " << e.getMessage())
== 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "MalformedUriException " << e.
getMessage()), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "MalformedUriException " <<
e.getMessage(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5509" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
5510 }
5511 }
5512 pContext->SetHyperlinkURL(sURL);
5513 }
5514
5515 if (!sTarget.isEmpty())
5516 pContext->SetHyperlinkTarget(sTarget);
5517 }
5518 break;
5519 case FIELD_IF : break;
5520 case FIELD_INFO : break;
5521 case FIELD_INCLUDEPICTURE: break;
5522 case FIELD_KEYWORDS :
5523 {
5524 if (!sFirstParam.isEmpty())
5525 {
5526 xFieldProperties->setPropertyValue(
5527 getPropertyName( PROP_IS_FIXED ), uno::makeAny( true ));
5528 //PROP_CURRENT_PRESENTATION is set later anyway
5529 }
5530 }
5531 break;
5532 case FIELD_LASTSAVEDBY : break;
5533 case FIELD_MACROBUTTON:
5534 {
5535 //extract macro name
5536 sal_Int32 nIndex = sizeof(" MACROBUTTON ");
5537 OUString sMacro = pContext->GetCommand().getToken( 0, ' ', nIndex);
5538 if (xFieldProperties.is())
5539 xFieldProperties->setPropertyValue(
5540 getPropertyName(PROP_MACRO_NAME), uno::makeAny( sMacro ));
5541
5542 //extract quick help text
5543 if(xFieldProperties.is() && pContext->GetCommand().getLength() > nIndex + 1)
5544 {
5545 xFieldProperties->setPropertyValue(
5546 getPropertyName(PROP_HINT),
5547 uno::makeAny( pContext->GetCommand().copy( nIndex )));
5548 }
5549 }
5550 break;
5551 case FIELD_MERGEFIELD :
5552 {
5553 //todo: create a database field and fieldmaster pointing to a column, only
5554 //create a user field and type
5555 uno::Reference< beans::XPropertySet > xMaster =
5556 FindOrCreateFieldMaster("com.sun.star.text.FieldMaster.Database", sFirstParam);
5557
5558// xFieldProperties->setPropertyValue(
5559// "FieldCode",
5560// uno::makeAny( pContext->GetCommand().copy( nIndex + 1 )));
5561 uno::Reference< text::XDependentTextField > xDependentField( xFieldInterface, uno::UNO_QUERY_THROW );
5562 xDependentField->attachTextFieldMaster( xMaster );
5563 }
5564 break;
5565 case FIELD_MERGEREC : break;
5566 case FIELD_MERGESEQ : break;
5567 case FIELD_NEXT : break;
5568 case FIELD_NEXTIF : break;
5569 case FIELD_PAGE :
5570 if (xFieldProperties.is())
5571 {
5572 xFieldProperties->setPropertyValue(
5573 getPropertyName(PROP_NUMBERING_TYPE),
5574 uno::makeAny( lcl_ParseNumberingType(pContext->GetCommand()) ));
5575 xFieldProperties->setPropertyValue(
5576 getPropertyName(PROP_SUB_TYPE),
5577 uno::makeAny( text::PageNumberType_CURRENT ));
5578 }
5579
5580 break;
5581 case FIELD_PAGEREF:
5582 case FIELD_REF:
5583 if (xFieldProperties.is() && !m_bStartTOC)
5584 {
5585 bool bPageRef = aIt->second.eFieldId == FIELD_PAGEREF;
5586
5587 // Do we need a GetReference (default) or a GetExpression field?
5588 uno::Reference< text::XTextFieldsSupplier > xFieldsSupplier( GetTextDocument(), uno::UNO_QUERY );
5589 uno::Reference< container::XNameAccess > xFieldMasterAccess = xFieldsSupplier->getTextFieldMasters();
5590
5591 if (!xFieldMasterAccess->hasByName(
5592 "com.sun.star.text.FieldMaster.SetExpression."
5593 + sFirstParam))
5594 {
5595 xFieldProperties->setPropertyValue(
5596 getPropertyName(PROP_REFERENCE_FIELD_SOURCE),
5597 uno::makeAny( sal_Int16(text::ReferenceFieldSource::BOOKMARK)) );
5598 xFieldProperties->setPropertyValue(
5599 getPropertyName(PROP_SOURCE_NAME),
5600 uno::makeAny(sFirstParam) );
5601 sal_Int16 nFieldPart = (bPageRef ? text::ReferenceFieldPart::PAGE : text::ReferenceFieldPart::TEXT);
5602 OUString sValue;
5603 if( lcl_FindInCommand( pContext->GetCommand(), 'p', sValue ))
5604 {
5605 //above-below
5606 nFieldPart = text::ReferenceFieldPart::UP_DOWN;
5607 }
5608 else if( lcl_FindInCommand( pContext->GetCommand(), 'r', sValue ))
5609 {
5610 //number
5611 nFieldPart = text::ReferenceFieldPart::NUMBER;
5612 }
5613 else if( lcl_FindInCommand( pContext->GetCommand(), 'n', sValue ))
5614 {
5615 //number-no-context
5616 nFieldPart = text::ReferenceFieldPart::NUMBER_NO_CONTEXT;
5617 }
5618 else if( lcl_FindInCommand( pContext->GetCommand(), 'w', sValue ))
5619 {
5620 //number-full-context
5621 nFieldPart = text::ReferenceFieldPart::NUMBER_FULL_CONTEXT;
5622 }
5623 xFieldProperties->setPropertyValue(
5624 getPropertyName( PROP_REFERENCE_FIELD_PART ), uno::makeAny( nFieldPart ));
5625 }
5626 else if( m_xTextFactory.is() )
5627 {
5628 xFieldInterface = m_xTextFactory->createInstance("com.sun.star.text.TextField.GetExpression");
5629 xFieldProperties.set(xFieldInterface, uno::UNO_QUERY);
5630 xFieldProperties->setPropertyValue(
5631 getPropertyName(PROP_CONTENT),
5632 uno::makeAny(sFirstParam));
5633 xFieldProperties->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::makeAny(text::SetVariableType::STRING));
5634 }
5635 }
5636 break;
5637 case FIELD_REVNUM : break;
5638 case FIELD_SAVEDATE :
5639 SetNumberFormat( pContext->GetCommand(), xFieldProperties );
5640 break;
5641 case FIELD_SECTION : break;
5642 case FIELD_SECTIONPAGES : break;
5643 case FIELD_SEQ :
5644 {
5645 // command looks like: " SEQ Table \* ARABIC "
5646 OUString sCmd(pContext->GetCommand());
5647 // find the sequence name, e.g. "SEQ"
5648 OUString sSeqName = msfilter::util::findQuotedText(sCmd, "SEQ ", '\\');
5649 sSeqName = sSeqName.trim();
5650
5651 // create a sequence field master using the sequence name
5652 uno::Reference< beans::XPropertySet > xMaster = FindOrCreateFieldMaster(
5653 "com.sun.star.text.FieldMaster.SetExpression",
5654 sSeqName);
5655
5656 xMaster->setPropertyValue(
5657 getPropertyName(PROP_SUB_TYPE),
5658 uno::makeAny(text::SetVariableType::SEQUENCE));
5659
5660 // apply the numbering type
5661 xFieldProperties->setPropertyValue(
5662 getPropertyName(PROP_NUMBERING_TYPE),
5663 uno::makeAny( lcl_ParseNumberingType(pContext->GetCommand()) ));
5664
5665 // attach the master to the field
5666 uno::Reference< text::XDependentTextField > xDependentField( xFieldInterface, uno::UNO_QUERY_THROW );
5667 xDependentField->attachTextFieldMaster( xMaster );
5668
5669 OUString sFormula = sSeqName + "+1";
5670 OUString sValue;
5671 if( lcl_FindInCommand( pContext->GetCommand(), 'c', sValue ))
5672 {
5673 sFormula = sSeqName;
5674 }
5675 else if( lcl_FindInCommand( pContext->GetCommand(), 'r', sValue ))
5676 {
5677 sFormula = sValue;
5678 }
5679 // TODO \s isn't handled, but the spec isn't easy to understand without
5680 // an example for this one.
5681 xFieldProperties->setPropertyValue(
5682 getPropertyName(PROP_CONTENT),
5683 uno::makeAny(sFormula));
5684
5685 // Take care of the numeric formatting definition, default is Arabic
5686 sal_Int16 nNumberingType = lcl_ParseNumberingType(pContext->GetCommand());
5687 if (nNumberingType == style::NumberingType::PAGE_DESCRIPTOR)
5688 nNumberingType = style::NumberingType::ARABIC;
5689 xFieldProperties->setPropertyValue(
5690 getPropertyName(PROP_NUMBERING_TYPE),
5691 uno::makeAny(nNumberingType));
5692 }
5693 break;
5694 case FIELD_SET :
5695 handleFieldSet(pContext, xFieldInterface, xFieldProperties);
5696 break;
5697 case FIELD_SKIPIF : break;
5698 case FIELD_STYLEREF : break;
5699 case FIELD_SUBJECT :
5700 {
5701 if (!sFirstParam.isEmpty())
5702 {
5703 xFieldProperties->setPropertyValue(
5704 getPropertyName( PROP_IS_FIXED ), uno::makeAny( true ));
5705 //PROP_CURRENT_PRESENTATION is set later anyway
5706 }
5707 }
5708 break;
5709 case FIELD_SYMBOL:
5710 {
5711 uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
5712 OUString sSymbol( sal_Unicode( sFirstParam.startsWithIgnoreAsciiCase("0x") ? sFirstParam.copy(2).toUInt32(16) : sFirstParam.toUInt32() ) );
5713 OUString sFont;
5714 bool bHasFont = lcl_FindInCommand( pContext->GetCommand(), 'f', sFont);
5715 if ( bHasFont )
5716 {
5717 sFont = sFont.trim();
5718 if (sFont.startsWith("\""))
5719 sFont = sFont.copy(1);
5720 if (sFont.endsWith("\""))
5721 sFont = sFont.copy(0,sFont.getLength()-1);
5722 }
5723
5724
5725
5726 if (xTextAppend.is())
5727 {
5728 uno::Reference< text::XText > xText = xTextAppend->getText();
5729 uno::Reference< text::XTextCursor > xCrsr = xText->createTextCursor();
5730 if (xCrsr.is())
5731 {
5732 xCrsr->gotoEnd(false);
5733 xText->insertString(xCrsr, sSymbol, true);
5734 uno::Reference< beans::XPropertySet > xProp( xCrsr, uno::UNO_QUERY );
5735 xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_CHAR_SET), uno::makeAny(awt::CharSet::SYMBOL));
5736 if(bHasFont)
5737 {
5738 uno::Any aVal = uno::makeAny( sFont );
5739 xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME), aVal);
5740 xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME_ASIAN), aVal);
5741 xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME_COMPLEX), aVal);
5742
5743 }
5744 }
5745 }
5746 }
5747 break;
5748 case FIELD_TEMPLATE: break;
5749 case FIELD_TIME :
5750 {
5751 if (pContext->IsFieldLocked())
5752 {
5753 xFieldProperties->setPropertyValue(
5754 getPropertyName(PROP_IS_FIXED),
5755 uno::makeAny( true ));
5756 m_bSetDateValue = true;
5757 }
5758 SetNumberFormat( pContext->GetCommand(), xFieldProperties );
5759 }
5760 break;
5761 case FIELD_TITLE :
5762 {
5763 if (!sFirstParam.isEmpty())
5764 {
5765 xFieldProperties->setPropertyValue(
5766 getPropertyName( PROP_IS_FIXED ), uno::makeAny( true ));
5767 //PROP_CURRENT_PRESENTATION is set later anyway
5768 }
5769 }
5770 break;
5771 case FIELD_USERADDRESS : //todo: user address collects street, city ...
5772 break;
5773 case FIELD_INDEX:
5774 handleIndex(pContext,
5775 OUString::createFromAscii(aIt->second.cFieldServiceName));
5776 break;
5777 case FIELD_BIBLIOGRAPHY:
5778 handleBibliography(pContext,
5779 OUString::createFromAscii(aIt->second.cFieldServiceName));
5780 break;
5781 case FIELD_TOC:
5782 handleToc(pContext,
5783 OUString::createFromAscii(aIt->second.cFieldServiceName));
5784 break;
5785 case FIELD_XE:
5786 {
5787 if( !m_xTextFactory.is() )
5788 break;
5789
5790 uno::Reference< beans::XPropertySet > xTC(
5791 m_xTextFactory->createInstance(
5792 OUString::createFromAscii(aIt->second.cFieldServiceName)),
5793 uno::UNO_QUERY_THROW);
5794 if (!sFirstParam.isEmpty())
5795 {
5796 xTC->setPropertyValue("PrimaryKey",
5797 uno::makeAny(sFirstParam));
5798 }
5799 uno::Reference< text::XTextContent > xToInsert( xTC, uno::UNO_QUERY );
5800 uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
5801 if (xTextAppend.is())
5802 {
5803 uno::Reference< text::XText > xText = xTextAppend->getText();
5804 uno::Reference< text::XTextCursor > xCrsr = xText->createTextCursor();
5805 if (xCrsr.is())
5806 {
5807 xCrsr->gotoEnd(false);
5808 xText->insertTextContent(uno::Reference< text::XTextRange >( xCrsr, uno::UNO_QUERY_THROW ), xToInsert, false);
5809 }
5810 }
5811 }
5812 break;
5813 case FIELD_CITATION:
5814 {
5815 if( !m_xTextFactory.is() )
5816 break;
5817
5818 xFieldInterface = m_xTextFactory->createInstance(
5819 OUString::createFromAscii(aIt->second.cFieldServiceName));
5820 uno::Reference< beans::XPropertySet > xTC(xFieldInterface,
5821 uno::UNO_QUERY_THROW);
5822 OUString sCmd(pContext->GetCommand());//sCmd is the entire instrText including the index e.g. CITATION Kra06 \l 1033
5823 if( !sCmd.isEmpty()){
5824 uno::Sequence<beans::PropertyValue> aValues( comphelper::InitPropertySequence({
5825 { "Identifier", uno::Any(sCmd) }
5826 }));
5827 xTC->setPropertyValue("Fields", uno::makeAny(aValues));
5828 }
5829 uno::Reference< text::XTextContent > xToInsert( xTC, uno::UNO_QUERY );
5830
5831 uno::Sequence<beans::PropertyValue> aValues
5832 = m_aFieldStack.back()->getProperties()->GetPropertyValues();
5833 appendTextContent(xToInsert, aValues);
5834 m_bSetCitation = true;
5835 }
5836 break;
5837
5838 case FIELD_TC :
5839 {
5840 if( !m_xTextFactory.is() )
5841 break;
5842
5843 uno::Reference< beans::XPropertySet > xTC(
5844 m_xTextFactory->createInstance(
5845 OUString::createFromAscii(aIt->second.cFieldServiceName)),
5846 uno::UNO_QUERY_THROW);
5847 if (!sFirstParam.isEmpty())
5848 {
5849 xTC->setPropertyValue(getPropertyName(PROP_ALTERNATIVE_TEXT),
5850 uno::makeAny(sFirstParam));
5851 }
5852 OUString sValue;
5853 // \f TC entry in doc with multiple tables
5854// if( lcl_FindInCommand( pContext->GetCommand(), 'f', sValue ))
5855// {
5856 // todo: unsupported
5857// }
5858 if( lcl_FindInCommand( pContext->GetCommand(), 'l', sValue ))
5859 // \l Outline Level
5860 {
5861 sal_Int32 nLevel = sValue.toInt32();
5862 if( !sValue.isEmpty() && nLevel >= 0 && nLevel <= 10 )
5863 xTC->setPropertyValue(getPropertyName(PROP_LEVEL), uno::makeAny( static_cast<sal_Int16>(nLevel) ));
5864 }
5865// if( lcl_FindInCommand( pContext->GetCommand(), 'n', sValue ))
5866// \n Suppress page numbers
5867// {
5868 //todo: unsupported feature
5869// }
5870 pContext->SetTC( xTC );
5871 }
5872 break;
5873 case FIELD_NUMCHARS:
5874 case FIELD_NUMWORDS:
5875 case FIELD_NUMPAGES:
5876 if (xFieldProperties.is())
5877 xFieldProperties->setPropertyValue(
5878 getPropertyName(PROP_NUMBERING_TYPE),
5879 uno::makeAny( lcl_ParseNumberingType(pContext->GetCommand()) ));
5880 break;
5881 }
5882 }
5883 else
5884 {
5885 /* Unsupported fields will be handled here for docx file.
5886 * To handle unsupported fields used fieldmark API.
5887 */
5888 OUString aCode( pContext->GetCommand().trim() );
5889 // Don't waste resources on wrapping shapes inside a fieldmark.
5890 if (sType != "SHAPE" && m_xTextFactory.is() && !m_aTextAppendStack.empty())
5891 {
5892 xFieldInterface = m_xTextFactory->createInstance("com.sun.star.text.Fieldmark");
5893
5894 uno::Reference<text::XFormField> const xFormField(xFieldInterface, uno::UNO_QUERY);
5895 InsertFieldmark(m_aTextAppendStack, xFormField, pContext->GetStartRange(),
5896 pContext->GetFieldId());
5897 xFormField->setFieldType(ODF_UNHANDLED"vnd.oasis.opendocument.field.UNHANDLED");
5898 ++m_nStartGenericField;
5899 pContext->SetFormField( xFormField );
5900 uno::Reference<container::XNameContainer> const xNameCont(xFormField->getParameters());
5901 // note: setting the code to empty string is *required* in
5902 // m_bForceGenericFields mode, or the export will write
5903 // the ODF_UNHANDLED string!
5904 assert(!m_bForceGenericFields || aCode.isEmpty())(static_cast <bool> (!m_bForceGenericFields || aCode.isEmpty
()) ? void (0) : __assert_fail ("!m_bForceGenericFields || aCode.isEmpty()"
, "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 5904, __extension__ __PRETTY_FUNCTION__))
;
5905 xNameCont->insertByName(ODF_CODE_PARAM"vnd.oasis.opendocument.field.code", uno::makeAny(aCode));
5906 ww::eField const id(GetWW8FieldId(sType));
5907 if (id != ww::eNONE)
5908 { // tdf#129247 tdf#134264 set WW8 id for WW8 export
5909 xNameCont->insertByName(ODF_ID_PARAM"vnd.oasis.opendocument.field.id", uno::makeAny(OUString::number(id)));
5910 }
5911 }
5912 else
5913 m_bParaHadField = false;
5914 }
5915 //set the text field if there is any
5916 pContext->SetTextField( uno::Reference< text::XTextField >( xFieldInterface, uno::UNO_QUERY ) );
5917 }
5918 catch( const uno::Exception& )
5919 {
5920 TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "Exception in CloseFieldCommand()" )do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Exception in CloseFieldCommand()"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5920" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Exception in CloseFieldCommand()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Exception in CloseFieldCommand()" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5920" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Exception in CloseFieldCommand()" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5920" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Exception in CloseFieldCommand()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Exception in CloseFieldCommand()" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5920" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
5921 }
5922 pContext->SetCommandCompleted();
5923}
5924/*-------------------------------------------------------------------------
5925//the _current_ fields require a string type result while TOCs accept richt results
5926 -----------------------------------------------------------------------*/
5927bool DomainMapper_Impl::IsFieldResultAsString()
5928{
5929 bool bRet = false;
5930 OSL_ENSURE( !m_aFieldStack.empty(), "field stack empty?")do { if (true && (!(!m_aFieldStack.empty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5930" ": "), "%s", "field stack empty?"); } } while (false
)
;
5931 FieldContextPtr pContext = m_aFieldStack.back();
5932 OSL_ENSURE( pContext, "no field context available")do { if (true && (!(pContext))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5932" ": "), "%s", "no field context available"); } } while
(false)
;
5933 if( pContext )
5934 {
5935 bRet = pContext->GetTextField().is()
5936 || pContext->GetFieldId() == FIELD_FORMDROPDOWN
5937 || pContext->GetFieldId() == FIELD_FILLIN;
5938 }
5939
5940 if (!bRet)
5941 {
5942 FieldContextPtr pOuter = GetParentFieldContext(m_aFieldStack);
5943 if (pOuter)
5944 {
5945 if (!IsFieldNestingAllowed(pOuter, m_aFieldStack.back()))
5946 {
5947 // Child field has no backing SwField, but the parent has: append is still possible.
5948 bRet = pOuter->GetTextField().is();
5949 }
5950 }
5951 }
5952 return bRet;
5953}
5954
5955void DomainMapper_Impl::AppendFieldResult(OUString const& rString)
5956{
5957 assert(!m_aFieldStack.empty())(static_cast <bool> (!m_aFieldStack.empty()) ? void (0)
: __assert_fail ("!m_aFieldStack.empty()", "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 5957, __extension__ __PRETTY_FUNCTION__))
;
5958 FieldContextPtr pContext = m_aFieldStack.back();
5959 SAL_WARN_IF(!pContext, "writerfilter.dmapper", "no field context")do { if (true && (!pContext)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "writerfilter.dmapper")) { case
SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "no field context") == 1) { ::sal_detail_log( (::
SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5959" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no field context"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"no field context"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5959" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "no field context") == 1) { ::sal_detail_log( (::
SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5959" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no field context"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"no field context"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "5959" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
5960 if (!pContext)
5961 return;
5962
5963 FieldContextPtr pOuter = GetParentFieldContext(m_aFieldStack);
5964 if (pOuter)
5965 {
5966 if (!IsFieldNestingAllowed(pOuter, pContext))
5967 {
5968 // Child can't host the field result, forward to parent.
5969 pOuter->AppendResult(rString);
5970 return;
5971 }
5972 }
5973
5974 pContext->AppendResult(rString);
5975}
5976
5977// Calculates css::DateTime based on ddddd.sssss since 1900-1-0
5978static util::DateTime lcl_dateTimeFromSerial(const double& dSerial)
5979{
5980 const sal_uInt32 secondsPerDay = 86400;
5981 const sal_uInt16 secondsPerHour = 3600;
5982
5983 DateTime d(Date(30, 12, 1899));
5984 d.AddDays( static_cast<sal_Int32>(dSerial) );
5985
5986 double frac = std::modf(dSerial, &o3tl::temporary(double()));
5987 sal_uInt32 seconds = frac * secondsPerDay;
5988
5989 util::DateTime date;
5990 date.Year = d.GetYear();
5991 date.Month = d.GetMonth();
5992 date.Day = d.GetDay();
5993 date.Hours = seconds / secondsPerHour;
5994 date.Minutes = (seconds % secondsPerHour) / 60;
5995 date.Seconds = seconds % 60;
5996
5997 return date;
5998}
5999
6000void DomainMapper_Impl::SetFieldResult(OUString const& rResult)
6001{
6002#ifdef DBG_UTIL
6003 TagLogger::getInstance().startElement("setFieldResult");
6004 TagLogger::getInstance().chars(rResult);
6005#endif
6006
6007 FieldContextPtr pContext = m_aFieldStack.back();
6008 OSL_ENSURE( pContext, "no field context available")do { if (true && (!(pContext))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6008" ": "), "%s", "no field context available"); } } while
(false)
;
6009
6010 if (m_aFieldStack.size() > 1)
6011 {
6012 // This is a nested field. See if the parent supports nesting on the Writer side.
6013 FieldContextPtr pParentContext = m_aFieldStack[m_aFieldStack.size() - 2];
6014 if (pParentContext)
6015 {
6016 std::vector<OUString> aParentParts = pParentContext->GetCommandParts();
6017 // Conditional text fields don't support nesting in Writer.
6018 if (!aParentParts.empty() && aParentParts[0] == "IF")
6019 {
6020 return;
6021 }
6022 }
6023 }
6024
6025 if( !pContext )
6026 return;
6027
6028 uno::Reference<text::XTextField> xTextField = pContext->GetTextField();
6029 try
6030 {
6031 OSL_ENSURE( xTextField.is()do { if (true && (!(xTextField.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6034" ": "), "%s", "DomainMapper_Impl::SetFieldResult: field not created"
); } } while (false)
6032 //||m_xTOC.is() ||m_xTC.is()do { if (true && (!(xTextField.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6034" ": "), "%s", "DomainMapper_Impl::SetFieldResult: field not created"
); } } while (false)
6033 //||m_sHyperlinkURL.getLength()do { if (true && (!(xTextField.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6034" ": "), "%s", "DomainMapper_Impl::SetFieldResult: field not created"
); } } while (false)
6034 , "DomainMapper_Impl::SetFieldResult: field not created" )do { if (true && (!(xTextField.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6034" ": "), "%s", "DomainMapper_Impl::SetFieldResult: field not created"
); } } while (false)
;
6035 if(xTextField.is())
6036 {
6037 try
6038 {
6039 if( m_bSetUserFieldContent )
6040 {
6041 // user field content has to be set at the field master
6042 uno::Reference< text::XDependentTextField > xDependentField( xTextField, uno::UNO_QUERY_THROW );
6043 xDependentField->getTextFieldMaster()->setPropertyValue(
6044 getPropertyName(PROP_CONTENT),
6045 uno::makeAny( rResult ));
6046 }
6047 else if ( m_bSetCitation )
6048 {
6049
6050 uno::Reference< beans::XPropertySet > xFieldProperties( xTextField, uno::UNO_QUERY_THROW);
6051 // In case of SetExpression, the field result contains the content of the variable.
6052 uno::Reference<lang::XServiceInfo> xServiceInfo(xTextField, uno::UNO_QUERY);
6053
6054 bool bIsSetbiblio = xServiceInfo->supportsService("com.sun.star.text.TextField.Bibliography");
6055 if( bIsSetbiblio )
6056 {
6057 uno::Any aProperty = xFieldProperties->getPropertyValue("Fields");
6058 uno::Sequence<beans::PropertyValue> aValues ;
6059 aProperty >>= aValues;
6060 beans::PropertyValue propertyVal;
6061 sal_Int32 nTitleFoundIndex = -1;
6062 for (sal_Int32 i = 0; i < aValues.getLength(); ++i)
6063 {
6064 propertyVal = aValues[i];
6065 if (propertyVal.Name == "Title")
6066 {
6067 nTitleFoundIndex = i;
6068 break;
6069 }
6070 }
6071 if (nTitleFoundIndex != -1)
6072 {
6073 OUString titleStr;
6074 uno::Any aValue(propertyVal.Value);
6075 aValue >>= titleStr;
6076 titleStr += rResult;
6077 propertyVal.Value <<= titleStr;
6078 aValues[nTitleFoundIndex] = propertyVal;
6079 }
6080 else
6081 {
6082 aValues.realloc(aValues.getLength() + 1);
6083 propertyVal.Name = "Title";
6084 propertyVal.Value <<= rResult;
6085 aValues[aValues.getLength() - 1] = propertyVal;
6086 }
6087 xFieldProperties->setPropertyValue("Fields",
6088 uno::makeAny(aValues));
6089 }
6090 }
6091 else if ( m_bSetDateValue )
6092 {
6093 uno::Reference< util::XNumberFormatsSupplier > xNumberSupplier( m_xTextDocument, uno::UNO_QUERY_THROW );
6094
6095 uno::Reference<util::XNumberFormatter> xFormatter(util::NumberFormatter::create(m_xComponentContext), uno::UNO_QUERY_THROW);
6096 xFormatter->attachNumberFormatsSupplier( xNumberSupplier );
6097 sal_Int32 nKey = 0;
6098
6099 uno::Reference< beans::XPropertySet > xFieldProperties( xTextField, uno::UNO_QUERY_THROW);
6100
6101 xFieldProperties->getPropertyValue( "NumberFormat" ) >>= nKey;
6102 xFieldProperties->setPropertyValue(
6103 "DateTimeValue",
6104 uno::makeAny( lcl_dateTimeFromSerial( xFormatter->convertStringToNumber( nKey, rResult ) ) ) );
6105 }
6106 else
6107 {
6108 uno::Reference< beans::XPropertySet > xFieldProperties( xTextField, uno::UNO_QUERY_THROW);
6109 // In case of SetExpression, and Input fields the field result contains the content of the variable.
6110 uno::Reference<lang::XServiceInfo> xServiceInfo(xTextField, uno::UNO_QUERY);
6111 // there are fields with a content property, which aren't working correctly with
6112 // a generalized try catch of the content, property, so just restrict content
6113 // handling to these explicit services.
6114 const bool bHasContent = xServiceInfo->supportsService("com.sun.star.text.TextField.SetExpression") ||
6115 xServiceInfo->supportsService("com.sun.star.text.TextField.Input");
6116 // If we already have content set, then use the current presentation
6117 OUString sValue;
6118 if (bHasContent)
6119 {
6120 // this will throw for field types without Content
6121 uno::Any aValue(xFieldProperties->getPropertyValue(
6122 getPropertyName(PROP_CONTENT)));
6123 aValue >>= sValue;
6124 }
6125 xFieldProperties->setPropertyValue(
6126 getPropertyName(bHasContent && sValue.isEmpty()? PROP_CONTENT : PROP_CURRENT_PRESENTATION),
6127 uno::makeAny( rResult ));
6128 }
6129 }
6130 catch( const beans::UnknownPropertyException& )
6131 {
6132 //some fields don't have a CurrentPresentation (DateTime)
6133 }
6134 }
6135 }
6136 catch (const uno::Exception&)
6137 {
6138 TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "DomainMapper_Impl::SetFieldResult")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "DomainMapper_Impl::SetFieldResult"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6138" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "DomainMapper_Impl::SetFieldResult" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "DomainMapper_Impl::SetFieldResult" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6138" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "DomainMapper_Impl::SetFieldResult" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6138" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "DomainMapper_Impl::SetFieldResult" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "DomainMapper_Impl::SetFieldResult" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6138" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
6139 }
6140}
6141
6142void DomainMapper_Impl::SetFieldFFData(const FFDataHandler::Pointer_t& pFFDataHandler)
6143{
6144#ifdef DBG_UTIL
6145 TagLogger::getInstance().startElement("setFieldFFData");
6146#endif
6147
6148 if (!m_aFieldStack.empty())
6149 {
6150 FieldContextPtr pContext = m_aFieldStack.back();
6151 if (pContext)
6152 {
6153 pContext->setFFDataHandler(pFFDataHandler);
6154 }
6155 }
6156
6157#ifdef DBG_UTIL
6158 TagLogger::getInstance().endElement();
6159#endif
6160}
6161
6162void DomainMapper_Impl::PopFieldContext()
6163{
6164 if(m_bDiscardHeaderFooter)
6165 return;
6166#ifdef DBG_UTIL
6167 TagLogger::getInstance().element("popFieldContext");
6168#endif
6169
6170 if (m_aFieldStack.empty())
6171 return;
6172
6173 FieldContextPtr pContext = m_aFieldStack.back();
6174 OSL_ENSURE( pContext, "no field context available")do { if (true && (!(pContext))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6174" ": "), "%s", "no field context available"); } } while
(false)
;
6175 if( pContext )
6176 {
6177 if( !pContext->IsCommandCompleted() )
6178 CloseFieldCommand();
6179
6180 if (!pContext->GetResult().isEmpty())
6181 {
6182 uno::Reference< beans::XPropertySet > xFieldProperties = pContext->GetCustomField();
6183 if(xFieldProperties.is())
6184 SetNumberFormat( pContext->GetResult(), xFieldProperties, true );
6185 SetFieldResult( pContext->GetResult() );
6186 }
6187
6188 //insert the field, TC or TOC
6189 uno::Reference< text::XTextAppend > xTextAppend;
6190 if (!m_aTextAppendStack.empty())
6191 xTextAppend = m_aTextAppendStack.top().xTextAppend;
6192 if(xTextAppend.is())
6193 {
6194 try
6195 {
6196 uno::Reference< text::XTextCursor > xCrsr = xTextAppend->createTextCursorByRange(pContext->GetStartRange());
6197 uno::Reference< text::XTextContent > xToInsert( pContext->GetTOC(), uno::UNO_QUERY );
6198 if( xToInsert.is() )
6199 {
6200 if (m_bStartedTOC || m_bStartIndex || m_bStartBibliography)
6201 {
6202 // inside SDT, last empty paragraph is also part of index
6203 if (!m_bParaChanged && !m_xSdtEntryStart)
6204 {
6205 // End of index is the first item on a new paragraph - this paragraph
6206 // should not be part of index
6207 auto xCursor
6208 = xTextAppend->createTextCursorByRange(xTextAppend->getEnd());
6209 xCursor->gotoEnd(false);
6210 xCursor->goLeft(1, true);
6211 // delete
6212 xCursor->setString(OUString());
6213 // But a new paragraph should be started after the index instead
6214 xTextAppend->finishParagraph(css::beans::PropertyValues());
6215 }
6216 m_bStartedTOC = false;
6217 m_aTextAppendStack.pop();
6218 m_bTextInserted = false;
6219 m_bParaChanged = true; // the paragraph must stay anyway
6220 }
6221 m_bStartTOC = false;
6222 m_bStartIndex = false;
6223 m_bStartBibliography = false;
6224 if (IsInHeaderFooter() && m_bStartTOCHeaderFooter)
6225 m_bStartTOCHeaderFooter = false;
6226 }
6227 else
6228 {
6229 xToInsert.set(pContext->GetTC(), uno::UNO_QUERY);
6230 if( !xToInsert.is() && !m_bStartTOC && !m_bStartIndex && !m_bStartBibliography )
6231 xToInsert = pContext->GetTextField();
6232 if( xToInsert.is() && !m_bStartTOC && !m_bStartIndex && !m_bStartBibliography)
6233 {
6234 PropertyMap aMap;
6235 // Character properties of the field show up here the
6236 // last (always empty) run. Inherit character
6237 // properties from there.
6238 // Also merge in the properties from the field context,
6239 // e.g. SdtEndBefore.
6240 if (m_pLastCharacterContext)
6241 aMap.InsertProps(m_pLastCharacterContext);
6242 aMap.InsertProps(m_aFieldStack.back()->getProperties());
6243 appendTextContent(xToInsert, aMap.GetPropertyValues());
6244 CheckRedline( xToInsert->getAnchor( ) );
6245 }
6246 else
6247 {
6248 FormControlHelper::Pointer_t pFormControlHelper(pContext->getFormControlHelper());
6249 if (pFormControlHelper)
6250 {
6251 uno::Reference< text::XFormField > xFormField( pContext->GetFormField() );
6252 assert(xCrsr.is())(static_cast <bool> (xCrsr.is()) ? void (0) : __assert_fail
("xCrsr.is()", "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 6252, __extension__ __PRETTY_FUNCTION__))
;
6253 if (pFormControlHelper->hasFFDataHandler())
6254 {
6255 xToInsert.set(xFormField, uno::UNO_QUERY);
6256 if (xFormField.is() && xToInsert.is())
6257 {
6258 PopFieldmark(m_aTextAppendStack, xCrsr,
6259 pContext->GetFieldId());
6260 pFormControlHelper->processField( xFormField );
6261 }
6262 else
6263 {
6264 pFormControlHelper->insertControl(xCrsr);
6265 }
6266 }
6267 else
6268 {
6269 PopFieldmark(m_aTextAppendStack, xCrsr,
6270 pContext->GetFieldId());
6271 uno::Reference<lang::XComponent>(xFormField, uno::UNO_QUERY_THROW)->dispose(); // presumably invalid?
6272 }
6273 }
6274 else if (!pContext->GetHyperlinkURL().isEmpty() && xCrsr.is())
6275 {
6276 xCrsr->gotoEnd( true );
6277
6278 // Draw components (like comments) need hyperlinks set differently
6279 SvxUnoTextRangeBase* pDrawText = dynamic_cast<SvxUnoTextRangeBase*>(xCrsr.get());
6280 if ( pDrawText )
6281 pDrawText->attachField( std::make_unique<SvxURLField>(pContext->GetHyperlinkURL(), xCrsr->getString(), SvxURLFormat::AppDefault) );
6282 else
6283 {
6284 uno::Reference< beans::XPropertySet > xCrsrProperties( xCrsr, uno::UNO_QUERY_THROW );
6285 xCrsrProperties->setPropertyValue(getPropertyName(PROP_HYPER_LINK_U_R_L), uno::
6286 makeAny(pContext->GetHyperlinkURL()));
6287
6288 if (!pContext->GetHyperlinkTarget().isEmpty())
6289 xCrsrProperties->setPropertyValue("HyperLinkTarget", uno::makeAny(pContext->GetHyperlinkTarget()));
6290
6291 if (m_bStartTOC) {
6292 OUString sDisplayName("Index Link");
6293 xCrsrProperties->setPropertyValue("VisitedCharStyleName",uno::makeAny(sDisplayName));
6294 xCrsrProperties->setPropertyValue("UnvisitedCharStyleName",uno::makeAny(sDisplayName));
6295 }
6296 else
6297 {
6298 uno::Any aAny = xCrsrProperties->getPropertyValue("CharStyleName");
6299 OUString charStyle;
6300 if (css::uno::fromAny(aAny, &charStyle))
6301 {
6302 if (charStyle.isEmpty())
6303 {
6304 xCrsrProperties->setPropertyValue("VisitedCharStyleName", uno::makeAny(OUString("Default Style")));
6305 xCrsrProperties->setPropertyValue("UnvisitedCharStyleName", uno::makeAny(OUString("Default Style")));
6306 }
6307 else if (charStyle.equalsIgnoreAsciiCase("Internet Link"))
6308 {
6309 xCrsrProperties->setPropertyValue("CharStyleName", uno::makeAny(OUString("Default Style")));
6310 }
6311 else
6312 {
6313 xCrsrProperties->setPropertyValue("VisitedCharStyleName", aAny);
6314 xCrsrProperties->setPropertyValue("UnvisitedCharStyleName", aAny);
6315 }
6316 }
6317 }
6318 }
6319 }
6320 else if (m_nStartGenericField != 0)
6321 {
6322 --m_nStartGenericField;
6323 PopFieldmark(m_aTextAppendStack, xCrsr, pContext->GetFieldId());
6324 if(m_bTextInserted)
6325 {
6326 m_bTextInserted = false;
6327 }
6328 }
6329 }
6330 }
6331 }
6332 catch(const lang::IllegalArgumentException&)
6333 {
6334 OSL_FAIL( "IllegalArgumentException in PopFieldContext()" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6334" ": "), "%s", "IllegalArgumentException in PopFieldContext()"
); } } while (false)
;
6335 }
6336 catch(const uno::Exception&)
6337 {
6338 OSL_FAIL( "exception in PopFieldContext()" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6338" ": "), "%s", "exception in PopFieldContext()"); }
} while (false)
;
6339 }
6340 }
6341
6342 //TOCs have to include all the imported content
6343 }
6344
6345 std::vector<FieldParagraph> aParagraphsToFinish;
6346 if (pContext)
6347 {
6348 aParagraphsToFinish = pContext->GetParagraphsToFinish();
6349 }
6350
6351 //remove the field context
6352 m_aFieldStack.pop_back();
6353
6354 // Finish the paragraph(s) now that the field is closed.
6355 for (const auto& rFinish : aParagraphsToFinish)
6356 {
6357 finishParagraph(rFinish.m_pPropertyMap, rFinish.m_bRemove);
6358 }
6359}
6360
6361
6362void DomainMapper_Impl::SetBookmarkName( const OUString& rBookmarkName )
6363{
6364 BookmarkMap_t::iterator aBookmarkIter = m_aBookmarkMap.find( m_sCurrentBkmkId );
6365 if( aBookmarkIter != m_aBookmarkMap.end() )
6366 {
6367 // fields are internal bookmarks: consume redundant "normal" bookmark
6368 if ( IsOpenField() )
6369 {
6370 FFDataHandler::Pointer_t pFFDataHandler(GetTopFieldContext()->getFFDataHandler());
6371 if (pFFDataHandler && pFFDataHandler->getName() == rBookmarkName)
6372 {
6373 // HACK: At the END marker, StartOrEndBookmark will START
6374 // a bookmark which will eventually be abandoned, not created.
6375 m_aBookmarkMap.erase(aBookmarkIter);
6376 return;
6377 }
6378 }
6379
6380 aBookmarkIter->second.m_sBookmarkName = rBookmarkName;
6381 }
6382 else
6383 m_sCurrentBkmkName = rBookmarkName;
6384}
6385
6386// This method was used as-is for DomainMapper_Impl::startOrEndPermissionRange() implementation.
6387void DomainMapper_Impl::StartOrEndBookmark( const OUString& rId )
6388{
6389 /*
6390 * Add the dummy paragraph to handle section properties
6391 * iff the first element in the section is a table. If the dummy para is not added yet, then add it;
6392 * So bookmark is not attached to the wrong paragraph.
6393 */
6394 if(hasTableManager() && getTableManager().isInCell() && m_nTableDepth == 0 && GetIsFirstParagraphInSection()
6395 && !GetIsDummyParaAddedForTableInSection() &&!GetIsTextFrameInserted())
6396 {
6397 AddDummyParaForTableInSection();
6398 }
6399
6400 bool bIsAfterDummyPara = GetIsDummyParaAddedForTableInSection() && GetIsFirstParagraphInSection();
6401 if (m_aTextAppendStack.empty())
6402 return;
6403 uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
6404 BookmarkMap_t::iterator aBookmarkIter = m_aBookmarkMap.find( rId );
6405 //is the bookmark name already registered?
6406 try
6407 {
6408 if( aBookmarkIter != m_aBookmarkMap.end() )
6409 {
6410 if (m_xTextFactory.is())
6411 {
6412 uno::Reference< text::XTextContent > xBookmark( m_xTextFactory->createInstance( "com.sun.star.text.Bookmark" ), uno::UNO_QUERY_THROW );
6413 uno::Reference< text::XTextCursor > xCursor;
6414 uno::Reference< text::XText > xText = aBookmarkIter->second.m_xTextRange->getText();
6415 if( aBookmarkIter->second.m_bIsStartOfText && !bIsAfterDummyPara)
6416 {
6417 xCursor = xText->createTextCursorByRange( xText->getStart() );
6418 }
6419 else
6420 {
6421 xCursor = xText->createTextCursorByRange( aBookmarkIter->second.m_xTextRange );
6422 xCursor->goRight( 1, false );
6423 }
6424
6425 xCursor->gotoRange( xTextAppend->getEnd(), true );
6426 // A Paragraph was recently finished, and a new Paragraph has not been started as yet
6427 // then move the bookmark-End to the earlier paragraph
6428 if (IsOutsideAParagraph())
6429 {
6430 xCursor->goLeft( 1, false );
6431 }
6432 uno::Reference< container::XNamed > xBkmNamed( xBookmark, uno::UNO_QUERY_THROW );
6433 assert(!aBookmarkIter->second.m_sBookmarkName.isEmpty())(static_cast <bool> (!aBookmarkIter->second.m_sBookmarkName
.isEmpty()) ? void (0) : __assert_fail ("!aBookmarkIter->second.m_sBookmarkName.isEmpty()"
, "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 6433, __extension__ __PRETTY_FUNCTION__))
;
6434 //todo: make sure the name is not used already!
6435 xBkmNamed->setName( aBookmarkIter->second.m_sBookmarkName );
6436 xTextAppend->insertTextContent( uno::Reference< text::XTextRange >( xCursor, uno::UNO_QUERY_THROW), xBookmark, !xCursor->isCollapsed() );
6437 }
6438 m_aBookmarkMap.erase( aBookmarkIter );
6439 m_sCurrentBkmkId.clear();
6440 }
6441 else
6442 {
6443 //otherwise insert a text range as marker
6444 bool bIsStart = true;
6445 uno::Reference< text::XTextRange > xCurrent;
6446 if (xTextAppend.is())
6447 {
6448 uno::Reference<text::XTextCursor> const xCursor =
6449 xTextAppend->createTextCursorByRange(
6450 m_aTextAppendStack.top().xInsertPosition.is()
6451 ? m_aTextAppendStack.top().xInsertPosition
6452 : xTextAppend->getEnd() );
6453
6454 if (!xCursor)
6455 return;
6456
6457 if (!bIsAfterDummyPara)
6458 bIsStart = !xCursor->goLeft(1, false);
6459 xCurrent = xCursor->getStart();
6460 }
6461 m_sCurrentBkmkId = rId;
6462 m_aBookmarkMap.emplace( rId, BookmarkInsertPosition( bIsStart, m_sCurrentBkmkName, xCurrent ) );
6463 m_sCurrentBkmkName.clear();
6464 }
6465 }
6466 catch( const uno::Exception& )
6467 {
6468 //TODO: What happens to bookmarks where start and end are at different XText objects?
6469 }
6470}
6471
6472void DomainMapper_Impl::setPermissionRangeEd(const OUString& user)
6473{
6474 PermMap_t::iterator aPremIter = m_aPermMap.find(m_sCurrentPermId);
6475 if (aPremIter != m_aPermMap.end())
6476 aPremIter->second.m_Ed = user;
6477 else
6478 m_sCurrentPermEd = user;
6479}
6480
6481void DomainMapper_Impl::setPermissionRangeEdGrp(const OUString& group)
6482{
6483 PermMap_t::iterator aPremIter = m_aPermMap.find(m_sCurrentPermId);
6484 if (aPremIter != m_aPermMap.end())
6485 aPremIter->second.m_EdGrp = group;
6486 else
6487 m_sCurrentPermEdGrp = group;
6488}
6489
6490// This method is based on implementation from DomainMapper_Impl::StartOrEndBookmark()
6491void DomainMapper_Impl::startOrEndPermissionRange(sal_Int32 permissinId)
6492{
6493 /*
6494 * Add the dummy paragraph to handle section properties
6495 * if the first element in the section is a table. If the dummy para is not added yet, then add it;
6496 * So permission is not attached to the wrong paragraph.
6497 */
6498 if (getTableManager().isInCell() && m_nTableDepth == 0 && GetIsFirstParagraphInSection()
6499 && !GetIsDummyParaAddedForTableInSection() && !GetIsTextFrameInserted())
6500 {
6501 AddDummyParaForTableInSection();
6502 }
6503
6504 if (m_aTextAppendStack.empty())
6505 return;
6506
6507 const bool bIsAfterDummyPara = GetIsDummyParaAddedForTableInSection() && GetIsFirstParagraphInSection();
6508
6509 uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
6510 PermMap_t::iterator aPermIter = m_aPermMap.find(permissinId);
6511
6512 //is the bookmark name already registered?
6513 try
6514 {
6515 if (aPermIter == m_aPermMap.end())
6516 {
6517 //otherwise insert a text range as marker
6518 bool bIsStart = true;
6519 uno::Reference< text::XTextRange > xCurrent;
6520 if (xTextAppend.is())
6521 {
6522 uno::Reference< text::XTextCursor > xCursor = xTextAppend->createTextCursorByRange(xTextAppend->getEnd());
6523
6524 if (!bIsAfterDummyPara)
6525 bIsStart = !xCursor->goLeft(1, false);
6526 xCurrent = xCursor->getStart();
6527 }
6528
6529 // register the start of the new permission
6530 m_sCurrentPermId = permissinId;
6531 m_aPermMap.emplace(permissinId, PermInsertPosition(bIsStart, permissinId, m_sCurrentPermEd, m_sCurrentPermEdGrp, xCurrent));
6532
6533 // clean up
6534 m_sCurrentPermEd.clear();
6535 m_sCurrentPermEdGrp.clear();
6536 }
6537 else
6538 {
6539 if (m_xTextFactory.is())
6540 {
6541 uno::Reference< text::XTextCursor > xCursor;
6542 uno::Reference< text::XText > xText = aPermIter->second.m_xTextRange->getText();
6543 if (aPermIter->second.m_bIsStartOfText && !bIsAfterDummyPara)
6544 {
6545 xCursor = xText->createTextCursorByRange(xText->getStart());
6546 }
6547 else
6548 {
6549 xCursor = xText->createTextCursorByRange(aPermIter->second.m_xTextRange);
6550 xCursor->goRight(1, false);
6551 }
6552
6553 xCursor->gotoRange(xTextAppend->getEnd(), true);
6554 // A Paragraph was recently finished, and a new Paragraph has not been started as yet
6555 // then move the bookmark-End to the earlier paragraph
6556 if (IsOutsideAParagraph())
6557 {
6558 xCursor->goLeft(1, false);
6559 }
6560
6561 // create a new bookmark using specific bookmark name pattern for permissions
6562 uno::Reference< text::XTextContent > xPerm(m_xTextFactory->createInstance("com.sun.star.text.Bookmark"), uno::UNO_QUERY_THROW);
6563 uno::Reference< container::XNamed > xPermNamed(xPerm, uno::UNO_QUERY_THROW);
6564 xPermNamed->setName(aPermIter->second.createBookmarkName());
6565
6566 // add new bookmark
6567 const bool bAbsorb = !xCursor->isCollapsed();
6568 uno::Reference< text::XTextRange > xCurrent(xCursor, uno::UNO_QUERY_THROW);
6569 xTextAppend->insertTextContent(xCurrent, xPerm, bAbsorb);
6570 }
6571
6572 // remove processed permission
6573 m_aPermMap.erase(aPermIter);
6574
6575 // clean up
6576 m_sCurrentPermId = 0;
6577 m_sCurrentPermEd.clear();
6578 m_sCurrentPermEdGrp.clear();
6579 }
6580 }
6581 catch (const uno::Exception&)
6582 {
6583 //TODO: What happens to bookmarks where start and end are at different XText objects?
6584 }
6585}
6586
6587void DomainMapper_Impl::AddAnnotationPosition(
6588 const bool bStart,
6589 const sal_Int32 nAnnotationId)
6590{
6591 if (m_aTextAppendStack.empty())
6592 return;
6593
6594 // Create a cursor, pointing to the current position.
6595 uno::Reference<text::XTextAppend> xTextAppend = m_aTextAppendStack.top().xTextAppend;
6596 uno::Reference<text::XTextRange> xCurrent;
6597 if (xTextAppend.is())
6598 {
6599 uno::Reference<text::XTextCursor> xCursor;
6600 if (m_bIsNewDoc)
6601 xCursor = xTextAppend->createTextCursorByRange(xTextAppend->getEnd());
6602 else
6603 xCursor = m_aTextAppendStack.top().xCursor;
6604 if (xCursor.is())
6605 xCurrent = xCursor->getStart();
6606 }
6607
6608 // And save it, to be used by PopAnnotation() later.
6609 AnnotationPosition& aAnnotationPosition = m_aAnnotationPositions[ nAnnotationId ];
6610 if (bStart)
6611 {
6612 aAnnotationPosition.m_xStart = xCurrent;
6613 }
6614 else
6615 {
6616 aAnnotationPosition.m_xEnd = xCurrent;
6617 }
6618 m_aAnnotationPositions[ nAnnotationId ] = aAnnotationPosition;
6619}
6620
6621GraphicImportPtr const & DomainMapper_Impl::GetGraphicImport(GraphicImportType eGraphicImportType)
6622{
6623 if(!m_pGraphicImport)
6624 m_pGraphicImport = new GraphicImport( m_xComponentContext, m_xTextFactory, m_rDMapper, eGraphicImportType, m_aPositionOffsets, m_aAligns, m_aPositivePercentages );
6625 return m_pGraphicImport;
6626}
6627/*-------------------------------------------------------------------------
6628 reset graphic import if the last import resulted in a shape, not a graphic
6629 -----------------------------------------------------------------------*/
6630void DomainMapper_Impl::ResetGraphicImport()
6631{
6632 m_pGraphicImport.clear();
6633}
6634
6635
6636void DomainMapper_Impl::ImportGraphic(const writerfilter::Reference< Properties >::Pointer_t& ref, GraphicImportType eGraphicImportType)
6637{
6638 GetGraphicImport(eGraphicImportType);
6639 if( eGraphicImportType != IMPORT_AS_DETECTED_INLINE && eGraphicImportType != IMPORT_AS_DETECTED_ANCHOR )
6640 {
6641 //create the graphic
6642 ref->resolve( *m_pGraphicImport );
6643 }
6644
6645 //insert it into the document at the current cursor position
6646
6647 uno::Reference<text::XTextContent> xTextContent
6648 (m_pGraphicImport->GetGraphicObject());
6649
6650 // In case the SDT starts with the text portion of the graphic, then set the SDT properties here.
6651 bool bHasGrabBag = false;
6652 uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
6653 if (xPropertySet.is())
6654 {
6655 uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
6656 bHasGrabBag = xPropertySetInfo->hasPropertyByName("FrameInteropGrabBag");
6657 // In case we're outside a paragraph, then the SDT properties are stored in the paragraph grab-bag, not the frame one.
6658 if (!m_pSdtHelper->isInteropGrabBagEmpty() && bHasGrabBag && !m_pSdtHelper->isOutsideAParagraph())
6659 {
6660 comphelper::SequenceAsHashMap aFrameGrabBag(xPropertySet->getPropertyValue("FrameInteropGrabBag"));
6661 aFrameGrabBag["SdtPr"] <<= m_pSdtHelper->getInteropGrabBagAndClear();
6662 xPropertySet->setPropertyValue("FrameInteropGrabBag", uno::makeAny(aFrameGrabBag.getAsConstPropertyValueList()));
6663 }
6664 }
6665
6666 /* Set "SdtEndBefore" property on Drawing.
6667 * It is required in a case when Drawing appears immediately after first run i.e.
6668 * there is no text/space/tab in between two runs.
6669 * In this case "SdtEndBefore" property needs to be set on Drawing.
6670 */
6671 if(IsSdtEndBefore())
6672 {
6673 if(xPropertySet.is() && bHasGrabBag)
6674 {
6675 uno::Sequence<beans::PropertyValue> aFrameGrabBag( comphelper::InitPropertySequence({
6676 { "SdtEndBefore", uno::Any(true) }
6677 }));
6678 xPropertySet->setPropertyValue("FrameInteropGrabBag",uno::makeAny(aFrameGrabBag));
6679 }
6680 }
6681
6682
6683 // Update the shape properties if it is embedded object.
6684 if(m_xEmbedded.is()){
6685 if (m_pGraphicImport->GetXShapeObject())
6686 m_pGraphicImport->GetXShapeObject()->setPosition(
6687 m_pGraphicImport->GetGraphicObjectPosition());
6688
6689 uno::Reference<drawing::XShape> xShape = m_pGraphicImport->GetXShapeObject();
6690 UpdateEmbeddedShapeProps(xShape);
6691 if (eGraphicImportType == IMPORT_AS_DETECTED_ANCHOR)
6692 {
6693 uno::Reference<beans::XPropertySet> xEmbeddedProps(m_xEmbedded, uno::UNO_QUERY);
6694 xEmbeddedProps->setPropertyValue("AnchorType", uno::makeAny(text::TextContentAnchorType_AT_CHARACTER));
6695 uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
6696 xEmbeddedProps->setPropertyValue("HoriOrient", xShapeProps->getPropertyValue("HoriOrient"));
6697 xEmbeddedProps->setPropertyValue("HoriOrientPosition", xShapeProps->getPropertyValue("HoriOrientPosition"));
6698 xEmbeddedProps->setPropertyValue("HoriOrientRelation", xShapeProps->getPropertyValue("HoriOrientRelation"));
6699 xEmbeddedProps->setPropertyValue("VertOrient", xShapeProps->getPropertyValue("VertOrient"));
6700 xEmbeddedProps->setPropertyValue("VertOrientPosition", xShapeProps->getPropertyValue("VertOrientPosition"));
6701 xEmbeddedProps->setPropertyValue("VertOrientRelation", xShapeProps->getPropertyValue("VertOrientRelation"));
6702 //tdf123873 fix missing textwrap import
6703 xEmbeddedProps->setPropertyValue("TextWrap", xShapeProps->getPropertyValue("TextWrap"));
6704 }
6705 }
6706 //insert it into the document at the current cursor position
6707 OSL_ENSURE( xTextContent.is(), "DomainMapper_Impl::ImportGraphic")do { if (true && (!(xTextContent.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6707" ": "), "%s", "DomainMapper_Impl::ImportGraphic");
} } while (false)
;
6708 if( xTextContent.is())
6709 {
6710 appendTextContent( xTextContent, uno::Sequence< beans::PropertyValue >() );
6711
6712 if (eGraphicImportType == IMPORT_AS_DETECTED_ANCHOR && !m_aTextAppendStack.empty())
6713 {
6714 // Remember this object is anchored to the current paragraph.
6715 AnchoredObjectInfo aInfo;
6716 aInfo.m_xAnchoredObject = xTextContent;
6717 if (m_pGraphicImport)
6718 {
6719 // We still have the graphic import around, remember the original margin, so later
6720 // SectionPropertyMap::HandleIncreasedAnchoredObjectSpacing() can use it.
6721 aInfo.m_nLeftMargin = m_pGraphicImport->GetLeftMarginOrig();
6722 }
6723 m_aTextAppendStack.top().m_aAnchoredObjects.push_back(aInfo);
6724 }
6725 else if (eGraphicImportType == IMPORT_AS_DETECTED_INLINE)
6726 m_bParaWithInlineObject = true;
6727 }
6728
6729 // Clear the reference, so in case the embedded object is inside a
6730 // TextFrame, we won't try to resize it (to match the size of the
6731 // TextFrame) here.
6732 m_xEmbedded.clear();
6733 m_pGraphicImport.clear();
6734}
6735
6736
6737void DomainMapper_Impl::SetLineNumbering( sal_Int32 nLnnMod, sal_uInt32 nLnc, sal_Int32 ndxaLnn )
6738{
6739 if( !m_bLineNumberingSet )
6740 {
6741 try
6742 {
6743 uno::Reference< text::XLineNumberingProperties > xLineProperties( m_xTextDocument, uno::UNO_QUERY_THROW );
6744 uno::Reference< beans::XPropertySet > xProperties = xLineProperties->getLineNumberingProperties();
6745 uno::Any aTrue( uno::makeAny( true ));
6746 xProperties->setPropertyValue( getPropertyName( PROP_IS_ON ), aTrue);
6747 xProperties->setPropertyValue( getPropertyName( PROP_COUNT_EMPTY_LINES ), aTrue );
6748 xProperties->setPropertyValue( getPropertyName( PROP_COUNT_LINES_IN_FRAMES ), uno::makeAny( false ) );
6749 xProperties->setPropertyValue( getPropertyName( PROP_INTERVAL ), uno::makeAny( static_cast< sal_Int16 >( nLnnMod )));
6750 xProperties->setPropertyValue( getPropertyName( PROP_DISTANCE ), uno::makeAny( ConversionHelper::convertTwipToMM100(ndxaLnn) ));
6751 xProperties->setPropertyValue( getPropertyName( PROP_NUMBER_POSITION ), uno::makeAny( style::LineNumberPosition::LEFT));
6752 xProperties->setPropertyValue( getPropertyName( PROP_NUMBERING_TYPE ), uno::makeAny( style::NumberingType::ARABIC));
6753 xProperties->setPropertyValue( getPropertyName( PROP_RESTART_AT_EACH_PAGE ), uno::makeAny( nLnc == NS_ooxml::LN_Value_ST_LineNumberRestart_newPage ));
6754 }
6755 catch( const uno::Exception& )
6756 {}
6757 }
6758 m_bLineNumberingSet = true;
6759 uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier( GetTextDocument(), uno::UNO_QUERY_THROW );
6760 uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
6761 uno::Reference<container::XNameContainer> xStyles;
6762 xStyleFamilies->getByName(getPropertyName( PROP_PARAGRAPH_STYLES )) >>= xStyles;
6763 lcl_linenumberingHeaderFooter( xStyles, "Header", this );
6764 lcl_linenumberingHeaderFooter( xStyles, "Footer", this );
6765}
6766
6767
6768void DomainMapper_Impl::SetPageMarginTwip( PageMarElement eElement, sal_Int32 nValue )
6769{
6770 nValue = ConversionHelper::convertTwipToMM100(nValue);
6771 switch(eElement)
6772 {
6773 case PAGE_MAR_TOP : m_aPageMargins.top = nValue; break;
6774 case PAGE_MAR_RIGHT : m_aPageMargins.right = nValue; break;
6775 case PAGE_MAR_BOTTOM : m_aPageMargins.bottom = nValue; break;
6776 case PAGE_MAR_LEFT : m_aPageMargins.left = nValue; break;
6777 case PAGE_MAR_HEADER : m_aPageMargins.header = nValue; break;
6778 case PAGE_MAR_FOOTER : m_aPageMargins.footer = nValue; break;
6779 case PAGE_MAR_GUTTER : break;
6780 }
6781}
6782
6783
6784PageMar::PageMar()
6785 : top(ConversionHelper::convertTwipToMM100( sal_Int32(1440)))
6786 // This is strange, the RTF spec says it's 1800, but it's clearly 1440 in Word
6787 // OOXML seems not to specify a default value
6788 , right(ConversionHelper::convertTwipToMM100( sal_Int32(1440)))
6789 , bottom(top)
6790 , left(right)
6791 , header(ConversionHelper::convertTwipToMM100(sal_Int32(720)))
6792 , footer(header)
6793{
6794}
6795
6796
6797void DomainMapper_Impl::RegisterFrameConversion(
6798 uno::Reference< text::XTextRange > const& xFrameStartRange,
6799 uno::Reference< text::XTextRange > const& xFrameEndRange,
6800 const std::vector<beans::PropertyValue>& rFrameProperties
6801 )
6802{
6803 OSL_ENSURE(do { if (true && (!(m_aFrameProperties.empty() &&
!m_xFrameStartRange.is() && !m_xFrameEndRange.is()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6805" ": "), "%s", "frame properties not removed"); } }
while (false)
6804 m_aFrameProperties.empty() && !m_xFrameStartRange.is() && !m_xFrameEndRange.is(),do { if (true && (!(m_aFrameProperties.empty() &&
!m_xFrameStartRange.is() && !m_xFrameEndRange.is()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6805" ": "), "%s", "frame properties not removed"); } }
while (false)
6805 "frame properties not removed")do { if (true && (!(m_aFrameProperties.empty() &&
!m_xFrameStartRange.is() && !m_xFrameEndRange.is()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6805" ": "), "%s", "frame properties not removed"); } }
while (false)
;
6806 m_aFrameProperties = rFrameProperties;
6807 m_xFrameStartRange = xFrameStartRange;
6808 m_xFrameEndRange = xFrameEndRange;
6809}
6810
6811
6812void DomainMapper_Impl::ExecuteFrameConversion()
6813{
6814 if( m_xFrameStartRange.is() && m_xFrameEndRange.is() && !m_bDiscardHeaderFooter )
6815 {
6816 std::vector<sal_Int32> redPos, redLen;
6817 try
6818 {
6819 uno::Reference< text::XTextAppendAndConvert > xTextAppendAndConvert( GetTopTextAppend(), uno::UNO_QUERY_THROW );
6820 // convert redline ranges to cursor movement and character length
6821
6822 for( size_t i = 0; i < aFramedRedlines.size(); i+=3)
6823 {
6824 uno::Reference< text::XTextRange > xRange;
6825 aFramedRedlines[i] >>= xRange;
6826 uno::Reference<text::XTextCursor> xRangeCursor = GetTopTextAppend()->createTextCursorByRange( xRange );
6827 if (xRangeCursor.is())
6828 {
6829 sal_Int32 nLen = xRange->getString().getLength();
6830 redLen.push_back(nLen);
6831 xRangeCursor->gotoRange(m_xFrameStartRange, true);
6832 redPos.push_back(xRangeCursor->getString().getLength() - nLen);
6833 }
6834 else
6835 {
6836 // failed createTextCursorByRange(), for example, table inside the frame
6837 redLen.push_back(-1);
6838 redPos.push_back(-1);
6839 }
6840 }
6841
6842 const uno::Reference< text::XTextContent >& xTextContent = xTextAppendAndConvert->convertToTextFrame(
6843 m_xFrameStartRange,
6844 m_xFrameEndRange,
6845 comphelper::containerToSequence(m_aFrameProperties) );
6846
6847 // create redlines in the previous frame
6848 for( size_t i = 0; i < aFramedRedlines.size(); i+=3)
6849 {
6850 OUString sType;
6851 beans::PropertyValues aRedlineProperties( 3 );
6852 // skip failed createTextCursorByRange()
6853 if (redPos[i/3] == -1)
6854 continue;
6855 aFramedRedlines[i+1] >>= sType;
6856 aFramedRedlines[i+2] >>= aRedlineProperties;
6857 uno::Reference< text::XTextFrame > xFrame( xTextContent, uno::UNO_QUERY_THROW );
6858 uno::Reference< text::XTextCursor > xCrsr = xFrame->getText()->createTextCursor();
6859 xCrsr->goRight(redPos[i/3], false);
6860 xCrsr->goRight(redLen[i/3], true);
6861 uno::Reference < text::XRedline > xRedline( xCrsr, uno::UNO_QUERY_THROW );
6862 xRedline->makeRedline( sType, aRedlineProperties );
6863 }
6864 }
6865 catch( const uno::Exception&)
6866 {
6867 DBG_UNHANDLED_EXCEPTION( "writerfilter.dmapper", "Exception caught when converting to frame")DbgUnhandledException( DbgGetCaughtException(), __func__, "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6867" ": ", "writerfilter.dmapper", "Exception caught when converting to frame"
);
;
6868 }
6869
6870 m_bIsActualParagraphFramed = false;
6871
6872 if (redPos.size() == aFramedRedlines.size()/3)
6873 {
6874 for( sal_Int32 i = aFramedRedlines.size() - 1; i >= 0; --i)
6875 {
6876 // keep redlines of floating tables to process them in CloseSectionGroup()
6877 if ( redPos[i/3] != -1 )
6878 {
6879 aFramedRedlines.erase(aFramedRedlines.begin() + i);
6880 }
6881 }
6882 }
6883 else
6884 aFramedRedlines.clear();
6885 }
6886 m_xFrameStartRange = nullptr;
6887 m_xFrameEndRange = nullptr;
6888 m_aFrameProperties.clear();
6889}
6890
6891void DomainMapper_Impl::AddNewRedline( sal_uInt32 sprmId )
6892{
6893 RedlineParamsPtr pNew( new RedlineParams );
6894 pNew->m_nToken = XML_mod;
6895 if ( !m_bIsParaMarkerChange )
6896 {
6897 // <w:rPrChange> applies to the whole <w:r>, <w:pPrChange> applies to the whole <w:p>,
6898 // so keep those two in CONTEXT_CHARACTERS and CONTEXT_PARAGRAPH, which will take
6899 // care of their scope (i.e. when they should be used and discarded).
6900 // Let's keep the rest the same way they used to be handled (explicitly dropped
6901 // from a global stack by endtrackchange), but quite possibly they should not be handled
6902 // that way either (I don't know).
6903 if( sprmId == NS_ooxml::LN_EG_RPrContent_rPrChange )
6904 GetTopContextOfType( CONTEXT_CHARACTER )->Redlines().push_back( pNew );
6905 else if( sprmId == NS_ooxml::LN_CT_PPr_pPrChange )
6906 GetTopContextOfType( CONTEXT_PARAGRAPH )->Redlines().push_back( pNew );
6907 else if( sprmId != NS_ooxml::LN_CT_ParaRPr_rPrChange )
6908 m_aRedlines.top().push_back( pNew );
6909 }
6910 else
6911 {
6912 m_pParaMarkerRedline = pNew;
6913 }
6914 // Newly read data will go into this redline.
6915 m_currentRedline = pNew;
6916}
6917
6918void DomainMapper_Impl::SetCurrentRedlineIsRead()
6919{
6920 m_currentRedline.clear();
6921}
6922
6923sal_Int32 DomainMapper_Impl::GetCurrentRedlineToken( ) const
6924{
6925 assert(m_currentRedline)(static_cast <bool> (m_currentRedline) ? void (0) : __assert_fail
("m_currentRedline", "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 6925, __extension__ __PRETTY_FUNCTION__))
;
6926 return m_currentRedline->m_nToken;
6927}
6928
6929void DomainMapper_Impl::SetCurrentRedlineAuthor( const OUString& sAuthor )
6930{
6931 if (!m_xAnnotationField.is())
6932 {
6933 if (m_currentRedline)
6934 m_currentRedline->m_sAuthor = sAuthor;
6935 else
6936 SAL_INFO("writerfilter.dmapper", "numberingChange not implemented")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "numberingChange not implemented"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6936" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "numberingChange not implemented"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "numberingChange not implemented"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6936" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "numberingChange not implemented") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6936" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "numberingChange not implemented"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "numberingChange not implemented"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6936" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
6937 }
6938 else
6939 m_xAnnotationField->setPropertyValue("Author", uno::makeAny(sAuthor));
6940}
6941
6942void DomainMapper_Impl::SetCurrentRedlineInitials( const OUString& sInitials )
6943{
6944 if (m_xAnnotationField.is())
6945 m_xAnnotationField->setPropertyValue("Initials", uno::makeAny(sInitials));
6946}
6947
6948void DomainMapper_Impl::SetCurrentRedlineDate( const OUString& sDate )
6949{
6950 if (!m_xAnnotationField.is())
6951 {
6952 if (m_currentRedline)
6953 m_currentRedline->m_sDate = sDate;
6954 else
6955 SAL_INFO("writerfilter.dmapper", "numberingChange not implemented")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "numberingChange not implemented"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6955" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "numberingChange not implemented"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "numberingChange not implemented"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6955" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "numberingChange not implemented") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6955" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "numberingChange not implemented"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "numberingChange not implemented"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6955" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
6956 }
6957 else
6958 m_xAnnotationField->setPropertyValue("DateTimeValue", uno::makeAny(ConversionHelper::ConvertDateStringToDateTime(sDate)));
6959}
6960
6961void DomainMapper_Impl::SetCurrentRedlineId( sal_Int32 sId )
6962{
6963 if (m_xAnnotationField.is())
6964 {
6965 m_nAnnotationId = sId;
6966 }
6967 else
6968 {
6969 // This should be an assert, but somebody had the smart idea to reuse this function also for comments and whatnot,
6970 // and in some cases the id is actually not handled, which may be in fact a bug.
6971 if( !m_currentRedline)
6972 SAL_INFO("writerfilter.dmapper", "no current redline")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "no current redline"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6972" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no current redline"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"no current redline"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6972" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "no current redline") == 1) { ::sal_detail_log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6972" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no current redline"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"no current redline"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6972" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
6973 }
6974}
6975
6976void DomainMapper_Impl::SetCurrentRedlineToken( sal_Int32 nToken )
6977{
6978 assert(m_currentRedline)(static_cast <bool> (m_currentRedline) ? void (0) : __assert_fail
("m_currentRedline", "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 6978, __extension__ __PRETTY_FUNCTION__))
;
6979 m_currentRedline->m_nToken = nToken;
6980}
6981
6982void DomainMapper_Impl::SetCurrentRedlineRevertProperties( const uno::Sequence<beans::PropertyValue>& aProperties )
6983{
6984 assert(m_currentRedline)(static_cast <bool> (m_currentRedline) ? void (0) : __assert_fail
("m_currentRedline", "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 6984, __extension__ __PRETTY_FUNCTION__))
;
6985 m_currentRedline->m_aRevertProperties = aProperties;
6986}
6987
6988
6989// This removes only the last redline stored here, those stored in contexts are automatically removed when
6990// the context is destroyed.
6991void DomainMapper_Impl::RemoveTopRedline( )
6992{
6993 if (m_aRedlines.top().empty())
6994 {
6995 SAL_WARN("writerfilter.dmapper", "RemoveTopRedline called with empty stack")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "RemoveTopRedline called with empty stack"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6995" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RemoveTopRedline called with empty stack"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RemoveTopRedline called with empty stack"; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6995" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RemoveTopRedline called with empty stack") == 1)
{ ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6995" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RemoveTopRedline called with empty stack"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RemoveTopRedline called with empty stack"; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "6995" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
6996 throw uno::Exception("RemoveTopRedline failed", nullptr);
6997 }
6998 m_aRedlines.top().pop_back( );
6999 m_currentRedline.clear();
7000}
7001
7002void DomainMapper_Impl::ApplySettingsTable()
7003{
7004 if (!(m_pSettingsTable && m_xTextFactory.is()))
7005 return;
7006
7007 try
7008 {
7009 uno::Reference< beans::XPropertySet > xTextDefaults(m_xTextFactory->createInstance("com.sun.star.text.Defaults"), uno::UNO_QUERY_THROW );
7010 sal_Int32 nDefTab = m_pSettingsTable->GetDefaultTabStop();
7011 xTextDefaults->setPropertyValue( getPropertyName( PROP_TAB_STOP_DISTANCE ), uno::makeAny(nDefTab) );
7012 if (m_pSettingsTable->GetLinkStyles())
7013 {
7014 // If linked styles are enabled, set paragraph defaults from Word's default template
7015 xTextDefaults->setPropertyValue(getPropertyName(PROP_PARA_BOTTOM_MARGIN), uno::makeAny(ConversionHelper::convertTwipToMM100(200)));
7016 style::LineSpacing aSpacing;
7017 aSpacing.Mode = style::LineSpacingMode::PROP;
7018 aSpacing.Height = sal_Int16(115);
7019 xTextDefaults->setPropertyValue(getPropertyName(PROP_PARA_LINE_SPACING), uno::makeAny(aSpacing));
7020 }
7021
7022 if (m_pSettingsTable->GetZoomFactor() || m_pSettingsTable->GetView())
7023 {
7024 std::vector<beans::PropertyValue> aViewProps;
7025 if (m_pSettingsTable->GetZoomFactor())
7026 {
7027 aViewProps.emplace_back("ZoomFactor", -1, uno::makeAny(m_pSettingsTable->GetZoomFactor()), beans::PropertyState_DIRECT_VALUE);
7028 aViewProps.emplace_back("VisibleBottom", -1, uno::makeAny(sal_Int32(0)), beans::PropertyState_DIRECT_VALUE);
7029 aViewProps.emplace_back("ZoomType", -1,
7030 uno::makeAny(m_pSettingsTable->GetZoomType()),
7031 beans::PropertyState_DIRECT_VALUE);
7032 }
7033 uno::Reference<container::XIndexContainer> xBox = document::IndexedPropertyValues::create(m_xComponentContext);
7034 xBox->insertByIndex(sal_Int32(0), uno::makeAny(comphelper::containerToSequence(aViewProps)));
7035 uno::Reference<document::XViewDataSupplier> xViewDataSupplier(m_xTextDocument, uno::UNO_QUERY);
7036 xViewDataSupplier->setViewData(xBox);
7037 }
7038
7039 uno::Reference< beans::XPropertySet > xSettings(m_xTextFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
7040
7041 if (m_pSettingsTable->GetDoNotExpandShiftReturn())
7042 xSettings->setPropertyValue( "DoNotJustifyLinesWithManualBreak", uno::makeAny(true) );
7043 if (m_pSettingsTable->GetUsePrinterMetrics())
7044 xSettings->setPropertyValue("PrinterIndependentLayout", uno::makeAny(document::PrinterIndependentLayout::DISABLED));
7045 if( m_pSettingsTable->GetEmbedTrueTypeFonts())
7046 xSettings->setPropertyValue( getPropertyName( PROP_EMBED_FONTS ), uno::makeAny(true) );
7047 if( m_pSettingsTable->GetEmbedSystemFonts())
7048 xSettings->setPropertyValue( getPropertyName( PROP_EMBED_SYSTEM_FONTS ), uno::makeAny(true) );
7049 xSettings->setPropertyValue("AddParaTableSpacing", uno::makeAny(m_pSettingsTable->GetDoNotUseHTMLParagraphAutoSpacing()));
7050 if (m_pSettingsTable->GetNoLeading())
7051 {
7052 xSettings->setPropertyValue("AddExternalLeading", uno::makeAny(!m_pSettingsTable->GetNoLeading()));
7053 }
7054 if( m_pSettingsTable->GetProtectForm() )
7055 xSettings->setPropertyValue("ProtectForm", uno::makeAny( true ));
7056 if( m_pSettingsTable->GetReadOnly() )
7057 xSettings->setPropertyValue("LoadReadonly", uno::makeAny( true ));
7058 }
7059 catch(const uno::Exception&)
7060 {
7061 }
7062}
7063
7064uno::Reference<container::XIndexAccess> DomainMapper_Impl::GetCurrentNumberingRules(sal_Int32* pListLevel)
7065{
7066 uno::Reference<container::XIndexAccess> xRet;
7067 try
7068 {
7069 OUString aStyle = GetCurrentParaStyleName();
7070 if (aStyle.isEmpty())
7071 return xRet;
7072 const StyleSheetEntryPtr pEntry = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(aStyle);
7073 if (!pEntry)
7074 return xRet;
7075 const StyleSheetPropertyMap* pStyleSheetProperties = dynamic_cast<const StyleSheetPropertyMap*>(pEntry->pProperties.get());
7076 if (!pStyleSheetProperties)
7077 return xRet;
7078 sal_Int32 nListId = pStyleSheetProperties->GetListId();
7079 if (nListId < 0)
7080 return xRet;
7081 if (pListLevel)
7082 *pListLevel = pStyleSheetProperties->GetListLevel();
7083
7084 // So we are in a paragraph style and it has numbering. Look up the relevant numbering rules.
7085 auto const pList(GetListTable()->GetList(nListId));
7086 OUString aListName;
7087 if (pList)
7088 {
7089 aListName = pList->GetStyleName();
7090 }
7091 uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier(GetTextDocument(), uno::UNO_QUERY_THROW);
7092 uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
7093 uno::Reference<container::XNameAccess> xNumberingStyles;
7094 xStyleFamilies->getByName("NumberingStyles") >>= xNumberingStyles;
7095 uno::Reference<beans::XPropertySet> xStyle(xNumberingStyles->getByName(aListName), uno::UNO_QUERY);
7096 xRet.set(xStyle->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
7097 }
7098 catch (const uno::Exception&)
7099 {
7100 TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "GetCurrentNumberingRules: exception caught")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "GetCurrentNumberingRules: exception caught"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "7100" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetCurrentNumberingRules: exception caught"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetCurrentNumberingRules: exception caught" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "7100" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetCurrentNumberingRules: exception caught" <<
" " << exceptionToString(tools_warn_exception)) == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "7100" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetCurrentNumberingRules: exception caught"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetCurrentNumberingRules: exception caught" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
":" "7100" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
7101 }
7102 return xRet;
7103}
7104
7105uno::Reference<beans::XPropertySet> DomainMapper_Impl::GetCurrentNumberingCharStyle()
7106{
7107 uno::Reference<beans::XPropertySet> xRet;
7108 try
7109 {
7110 sal_Int32 nListLevel = -1;
7111 uno::Reference<container::XIndexAccess> xLevels;
7112 if ( GetTopContextType() == CONTEXT_PARAGRAPH )
7113 xLevels = GetCurrentNumberingRules(&nListLevel);
7114 if (!xLevels.is())
7115 {
7116 if (IsOOXMLImport())
7117 return xRet;
7118
7119 PropertyMapPtr pContext = m_pTopContext;
7120 if (IsRTFImport() && !IsOpenField())
7121 {
7122 // Looking up the paragraph context explicitly (and not just taking
7123 // the top context) is necessary for RTF, where formatting of a run
7124 // and of the paragraph mark is not separated.
7125 // We know that the formatting inside a field won't affect the
7126 // paragraph marker formatting, though.
7127 pContext = GetTopContextOfType(CONTEXT_PARAGRAPH);
7128 if (!pContext)
7129 return xRet;
7130 }
7131
7132 // In case numbering rules is not found via a style, try the direct formatting instead.
7133 std::optional<PropertyMap::Property> oProp = pContext->getProperty(PROP_NUMBERING_RULES);
7134 if (oProp)
7135 {
7136 xLevels.set(oProp->second, uno::UNO_QUERY);
7137 // Found the rules, then also try to look up our numbering level.
7138 oProp = pContext->getProperty(PROP_NUMBERING_LEVEL);
7139 if (oProp)
7140 oProp->second >>= nListLevel;
7141 else
7142 nListLevel = 0;
7143 }
7144
7145 if (!xLevels.is())
7146 return xRet;
7147 }
7148 uno::Sequence<beans::PropertyValue> aProps;
7149 xLevels->getByIndex(nListLevel) >>= aProps;
7150 auto pProp = std::find_if(aProps.begin(), aProps.end(),
7151 [](const beans::PropertyValue& rProp) { return rProp.Name == "CharStyleName"; });
7152 if (pProp != aProps.end())
7153 {
7154 OUString aCharStyle;
7155 pProp->Value >>= aCharStyle;
7156 uno::Reference<container::XNameAccess> xCharacterStyles;
7157 uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier(GetTextDocument(), uno::UNO_QUERY);
7158 uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
7159 xStyleFamilies->getByName("CharacterStyles") >>= xCharacterStyles;
7160 xRet.set(xCharacterStyles->getByName(aCharStyle), uno::UNO_QUERY_THROW);
7161 }
7162 }
7163 catch( const uno::Exception& )
7164 {
7165 }
7166 return xRet;
7167}
7168
7169SectionPropertyMap * DomainMapper_Impl::GetSectionContext()
7170{
7171 SectionPropertyMap* pSectionContext = nullptr;
7172 //the section context is not available before the first call of startSectionGroup()
7173 if( !IsAnyTableImport() )
7174 {
7175 PropertyMapPtr pContext = GetTopContextOfType(CONTEXT_SECTION);
7176 pSectionContext = dynamic_cast< SectionPropertyMap* >( pContext.get() );
7177 }
7178
7179 return pSectionContext;
7180}
7181
7182void DomainMapper_Impl::deferCharacterProperty(sal_Int32 id, const css::uno::Any& value)
7183{
7184 deferredCharacterProperties[ id ] = value;
7185}
7186
7187void DomainMapper_Impl::processDeferredCharacterProperties()
7188{
7189 // Actually process in DomainMapper, so that it's the same source file like normal processing.
7190 if( !deferredCharacterProperties.empty())
7191 {
7192 m_rDMapper.processDeferredCharacterProperties( deferredCharacterProperties );
7193 deferredCharacterProperties.clear();
7194 }
7195}
7196
7197sal_Int32 DomainMapper_Impl::getNumberingProperty(const sal_Int32 nListId, sal_Int32 nNumberingLevel, const OUString& aProp)
7198{
7199 sal_Int32 nRet = 0;
7200 if ( nListId < 0 )
7201 return nRet;
7202
7203 try
7204 {
7205 if (nNumberingLevel < 0) // It seems it's valid to omit numbering level, and in that case it means zero.
7206 nNumberingLevel = 0;
7207
7208 auto const pList(GetListTable()->GetList(nListId));
7209 assert(pList)(static_cast <bool> (pList) ? void (0) : __assert_fail (
"pList", "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 7209, __extension__ __PRETTY_FUNCTION__))
;
7210 const OUString aListName = pList->GetStyleName();
7211 const uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier(GetTextDocument(), uno::UNO_QUERY_THROW);
7212 const uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
7213 uno::Reference<container::XNameAccess> xNumberingStyles;
7214 xStyleFamilies->getByName("NumberingStyles") >>= xNumberingStyles;
7215 const uno::Reference<beans::XPropertySet> xStyle(xNumberingStyles->getByName(aListName), uno::UNO_QUERY);
7216 const uno::Reference<container::XIndexAccess> xNumberingRules(xStyle->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
7217 if (xNumberingRules.is())
7218 {
7219 uno::Sequence<beans::PropertyValue> aProps;
7220 xNumberingRules->getByIndex(nNumberingLevel) >>= aProps;
7221 auto pProp = std::find_if(aProps.begin(), aProps.end(),
7222 [&aProp](const beans::PropertyValue& rProp) { return rProp.Name == aProp; });
7223 if (pProp != aProps.end())
7224 pProp->Value >>= nRet;
7225 }
7226 }
7227 catch( const uno::Exception& )
7228 {
7229 // This can happen when the doc contains some hand-crafted invalid list level.
7230 }
7231
7232 return nRet;
7233}
7234
7235sal_Int32 DomainMapper_Impl::getCurrentNumberingProperty(const OUString& aProp)
7236{
7237 sal_Int32 nRet = 0;
7238
7239 std::optional<PropertyMap::Property> pProp = m_pTopContext->getProperty(PROP_NUMBERING_RULES);
7240 uno::Reference<container::XIndexAccess> xNumberingRules;
7241 if (pProp)
7242 xNumberingRules.set(pProp->second, uno::UNO_QUERY);
7243 pProp = m_pTopContext->getProperty(PROP_NUMBERING_LEVEL);
7244 // Default numbering level is the first one.
7245 sal_Int32 nNumberingLevel = 0;
7246 if (pProp)
7247 pProp->second >>= nNumberingLevel;
7248 if (xNumberingRules.is())
7249 {
7250 uno::Sequence<beans::PropertyValue> aProps;
7251 xNumberingRules->getByIndex(nNumberingLevel) >>= aProps;
7252 auto pPropVal = std::find_if(aProps.begin(), aProps.end(),
7253 [&aProp](const beans::PropertyValue& rProp) { return rProp.Name == aProp; });
7254 if (pPropVal != aProps.end())
7255 pPropVal->Value >>= nRet;
7256 }
7257
7258 return nRet;
7259}
7260
7261
7262void DomainMapper_Impl::enableInteropGrabBag(const OUString& aName)
7263{
7264 m_aInteropGrabBagName = aName;
7265}
7266
7267void DomainMapper_Impl::disableInteropGrabBag()
7268{
7269 m_aInteropGrabBagName.clear();
7270 m_aInteropGrabBag.clear();
7271 m_aSubInteropGrabBag.clear();
7272}
7273
7274bool DomainMapper_Impl::isInteropGrabBagEnabled() const
7275{
7276 return !(m_aInteropGrabBagName.isEmpty());
7277}
7278
7279void DomainMapper_Impl::appendGrabBag(std::vector<beans::PropertyValue>& rInteropGrabBag, const OUString& aKey, const OUString& aValue)
7280{
7281 if (m_aInteropGrabBagName.isEmpty())
7282 return;
7283 beans::PropertyValue aProperty;
7284 aProperty.Name = aKey;
7285 aProperty.Value <<= aValue;
7286 rInteropGrabBag.push_back(aProperty);
7287}
7288
7289void DomainMapper_Impl::appendGrabBag(std::vector<beans::PropertyValue>& rInteropGrabBag, const OUString& aKey, std::vector<beans::PropertyValue>& rValue)
7290{
7291 if (m_aInteropGrabBagName.isEmpty())
7292 return;
7293 beans::PropertyValue aProperty;
7294 aProperty.Name = aKey;
7295 aProperty.Value <<= comphelper::containerToSequence(rValue);
7296 rValue.clear();
7297 rInteropGrabBag.push_back(aProperty);
7298}
7299
7300void DomainMapper_Impl::substream(Id rName,
7301 ::writerfilter::Reference<Stream>::Pointer_t const& ref)
7302{
7303#ifndef NDEBUG
7304 size_t contextSize(m_aContextStack.size());
7305 size_t propSize[NUMBER_OF_CONTEXTS];
7306 for (int i = 0; i < NUMBER_OF_CONTEXTS; ++i) {
7307 propSize[i] = m_aPropertyStacks[i].size();
7308 }
7309#endif
7310
7311 // Save "has footnote" state, which is specific to a section in the body
7312 // text, so state from substreams is not relevant.
7313 bool bHasFtn = m_bHasFtn;
7314
7315 //finalize any waiting frames before starting alternate streams
7316 CheckUnregisteredFrameConversion();
7317 ExecuteFrameConversion();
7318
7319 appendTableManager();
7320 // Appending a TableManager resets its TableHandler, so we need to append
7321 // that as well, or tables won't be imported properly in headers/footers.
7322 appendTableHandler();
7323 getTableManager().startLevel();
7324
7325 //import of page header/footer
7326 //Ensure that only one header/footer per section is pushed
7327
7328 switch( rName )
7329 {
7330 case NS_ooxml::LN_headerl:
7331 PushPageHeader(SectionPropertyMap::PAGE_LEFT);
7332 break;
7333 case NS_ooxml::LN_headerr:
7334 PushPageHeader(SectionPropertyMap::PAGE_RIGHT);
7335 break;
7336 case NS_ooxml::LN_headerf:
7337 PushPageHeader(SectionPropertyMap::PAGE_FIRST);
7338 break;
7339 case NS_ooxml::LN_footerl:
7340 PushPageFooter(SectionPropertyMap::PAGE_LEFT);
7341 break;
7342 case NS_ooxml::LN_footerr:
7343 PushPageFooter(SectionPropertyMap::PAGE_RIGHT);
7344 break;
7345 case NS_ooxml::LN_footerf:
7346 PushPageFooter(SectionPropertyMap::PAGE_FIRST);
7347 break;
7348 case NS_ooxml::LN_footnote:
7349 case NS_ooxml::LN_endnote:
7350 PushFootOrEndnote( NS_ooxml::LN_footnote == rName );
7351 break;
7352 case NS_ooxml::LN_annotation :
7353 PushAnnotation();
7354 break;
7355 }
7356 ref->resolve(m_rDMapper);
7357
7358 switch( rName )
7359 {
7360 case NS_ooxml::LN_headerl:
7361 case NS_ooxml::LN_headerr:
7362 case NS_ooxml::LN_headerf:
7363 case NS_ooxml::LN_footerl:
7364 case NS_ooxml::LN_footerr:
7365 case NS_ooxml::LN_footerf:
7366 PopPageHeaderFooter();
7367 break;
7368 case NS_ooxml::LN_footnote:
7369 case NS_ooxml::LN_endnote:
7370 PopFootOrEndnote();
7371 break;
7372 case NS_ooxml::LN_annotation :
7373 PopAnnotation();
7374 break;
7375 }
7376
7377 getTableManager().endLevel();
7378 popTableManager();
7379 m_bHasFtn = bHasFtn;
7380
7381 switch(rName)
7382 {
7383 case NS_ooxml::LN_footnote:
7384 case NS_ooxml::LN_endnote:
7385 m_pTableHandler->setHadFootOrEndnote(true);
7386 m_bHasFtn = true;
7387 break;
7388 }
7389
7390 // check that stacks are the same as before substream
7391 assert(m_aContextStack.size() == contextSize)(static_cast <bool> (m_aContextStack.size() == contextSize
) ? void (0) : __assert_fail ("m_aContextStack.size() == contextSize"
, "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 7391, __extension__ __PRETTY_FUNCTION__))
;
7392 for (int i = 0; i < NUMBER_OF_CONTEXTS; ++i) {
7393 assert(m_aPropertyStacks[i].size() == propSize[i])(static_cast <bool> (m_aPropertyStacks[i].size() == propSize
[i]) ? void (0) : __assert_fail ("m_aPropertyStacks[i].size() == propSize[i]"
, "/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapper_Impl.cxx"
, 7393, __extension__ __PRETTY_FUNCTION__))
;
7394 }
7395}
7396}
7397
7398/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/tools/ref.hxx

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#ifndef INCLUDED_TOOLS_REF_HXX
20#define INCLUDED_TOOLS_REF_HXX
21
22#include <sal/config.h>
23#include <cassert>
24#include <tools/toolsdllapi.h>
25#include <utility>
26
27/**
28 This implements similar functionality to boost::intrusive_ptr
29*/
30
31namespace tools {
32
33/** T must be a class that extends SvRefBase */
34template<typename T> class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SvRef final {
35public:
36 SvRef(): pObj(nullptr) {}
37
38 SvRef(SvRef&& rObj) noexcept
39 {
40 pObj = rObj.pObj;
41 rObj.pObj = nullptr;
42 }
43
44 SvRef(SvRef const & rObj): pObj(rObj.pObj)
45 {
46 if (pObj != nullptr) pObj->AddNextRef();
47 }
48
49 SvRef(T * pObjP): pObj(pObjP)
50 {
51 if (pObj != nullptr) pObj->AddFirstRef();
52 }
53
54 ~SvRef()
55 {
56 if (pObj != nullptr) pObj->ReleaseRef();
11
Taking true branch
12
Calling 'SvRefBase::ReleaseRef'
18
Returning; memory was released
21
Taking true branch
22
Use of memory after it is freed
57 }
58
59 void clear()
60 {
61 if (pObj != nullptr) {
62 T * pRefObj = pObj;
63 pObj = nullptr;
64 pRefObj->ReleaseRef();
65 }
66 }
67
68 SvRef & operator =(SvRef const & rObj)
69 {
70 if (rObj.pObj != nullptr) {
71 rObj.pObj->AddNextRef();
72 }
73 T * pRefObj = pObj;
74 pObj = rObj.pObj;
75 if (pRefObj != nullptr) {
76 pRefObj->ReleaseRef();
77 }
78 return *this;
79 }
80
81 SvRef & operator =(SvRef && rObj)
82 {
83 if (pObj != nullptr) {
84 pObj->ReleaseRef();
85 }
86 pObj = rObj.pObj;
87 rObj.pObj = nullptr;
88 return *this;
89 }
90
91 bool is() const { return pObj != nullptr; }
92
93 explicit operator bool() const { return is(); }
94
95 T * get() const { return pObj; }
96
97 T * operator ->() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail
("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 97, __extension__ __PRETTY_FUNCTION__))
; return pObj; }
98
99 T & operator *() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail
("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 99, __extension__ __PRETTY_FUNCTION__))
; return *pObj; }
100
101 bool operator ==(const SvRef<T> &rhs) const { return pObj == rhs.pObj; }
102 bool operator !=(const SvRef<T> &rhs) const { return !(*this == rhs); }
103
104private:
105 T * pObj;
106};
107
108/**
109 * This implements similar functionality to std::make_shared.
110 */
111template<typename T, typename... Args>
112SvRef<T> make_ref(Args&& ... args)
113{
114 return SvRef<T>(new T(std::forward<Args>(args)...));
115}
116
117}
118
119/** Classes that want to be referenced-counted via SvRef<T>, should extend this base class */
120class TOOLS_DLLPUBLIC__attribute__ ((visibility("default"))) SvRefBase
121{
122 // work around a clang 3.5 optimization bug: if the bNoDelete is *first*
123 // it mis-compiles "if (--nRefCount == 0)" and never deletes any object
124 unsigned int nRefCount : 31;
125 // the only reason this is not bool is because MSVC cannot handle mixed type bitfields
126 unsigned int bNoDelete : 1;
127
128protected:
129 virtual ~SvRefBase() COVERITY_NOEXCEPT_FALSE;
130
131public:
132 SvRefBase() : nRefCount(0), bNoDelete(1) {}
133 SvRefBase(const SvRefBase &) : nRefCount(0), bNoDelete(1) {}
134
135 SvRefBase & operator=(const SvRefBase &) { return *this; }
136
137 void RestoreNoDelete()
138 { bNoDelete = 1; }
139
140 void AddNextRef()
141 {
142 assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) &&
"Do not add refs to dead objects") ? void (0) : __assert_fail
("nRefCount < (1 << 30) && \"Do not add refs to dead objects\""
, "/home/maarten/src/libreoffice/core/include/tools/ref.hxx",
142, __extension__ __PRETTY_FUNCTION__))
;
143 ++nRefCount;
144 }
145
146 void AddFirstRef()
147 {
148 assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) &&
"Do not add refs to dead objects") ? void (0) : __assert_fail
("nRefCount < (1 << 30) && \"Do not add refs to dead objects\""
, "/home/maarten/src/libreoffice/core/include/tools/ref.hxx",
148, __extension__ __PRETTY_FUNCTION__))
;
149 if( bNoDelete )
150 bNoDelete = 0;
151 ++nRefCount;
152 }
153
154 void ReleaseRef()
155 {
156 assert( nRefCount >= 1)(static_cast <bool> (nRefCount >= 1) ? void (0) : __assert_fail
("nRefCount >= 1", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 156, __extension__ __PRETTY_FUNCTION__))
;
13
'?' condition is true
157 if( --nRefCount == 0 && !bNoDelete)
14
Assuming the condition is true
15
Assuming field 'bNoDelete' is 0
16
Taking true branch
158 {
159 // I'm not sure about the original purpose of this line, but right now
160 // it serves the purpose that anything that attempts to do an AddRef()
161 // after an object is deleted will trip an assert.
162 nRefCount = 1 << 30;
163 delete this;
17
Memory is released
164 }
165 }
166
167 unsigned int GetRefCount() const
168 { return nRefCount; }
169};
170
171template<typename T>
172class SvCompatWeakBase;
173
174/** SvCompatWeakHdl acts as an intermediary between SvCompatWeakRef<T> and T.
175*/
176template<typename T>
177class SvCompatWeakHdl final : public SvRefBase
178{
179 friend class SvCompatWeakBase<T>;
180 T* _pObj;
181
182 SvCompatWeakHdl( T* pObj ) : _pObj( pObj ) {}
183
184public:
185 void ResetWeakBase( ) { _pObj = nullptr; }
186 T* GetObj() { return _pObj; }
187};
188
189/** We only have one place that extends this, in include/sfx2/frame.hxx, class SfxFrame.
190 Its function is to notify the SvCompatWeakHdl when an SfxFrame object is deleted.
191*/
192template<typename T>
193class SvCompatWeakBase
194{
195 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
196
197public:
198 /** Does not use initializer due to compiler warnings,
199 because the lifetime of the _xHdl object can exceed the lifetime of this class.
200 */
201 SvCompatWeakBase( T* pObj ) { _xHdl = new SvCompatWeakHdl<T>( pObj ); }
202
203 ~SvCompatWeakBase() { _xHdl->ResetWeakBase(); }
204
205 SvCompatWeakHdl<T>* GetHdl() { return _xHdl.get(); }
206};
207
208/** We only have one weak reference in LO, in include/sfx2/frame.hxx, class SfxFrameWeak.
209*/
210template<typename T>
211class SAL_WARN_UNUSED__attribute__((warn_unused)) SvCompatWeakRef
212{
213 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
214public:
215 SvCompatWeakRef( ) {}
216 SvCompatWeakRef( T* pObj )
217 { if( pObj ) _xHdl = pObj->GetHdl(); }
218#if defined(__COVERITY__)
219 ~SvCompatWeakRef() COVERITY_NOEXCEPT_FALSE {}
220#endif
221 SvCompatWeakRef& operator = ( T * pObj )
222 { _xHdl = pObj ? pObj->GetHdl() : nullptr; return *this; }
223 bool is() const
224 { return _xHdl.is() && _xHdl->GetObj(); }
225 explicit operator bool() const { return is(); }
226 T* operator -> () const
227 { return _xHdl.is() ? _xHdl->GetObj() : nullptr; }
228 operator T* () const
229 { return _xHdl.is() ? _xHdl->GetObj() : nullptr; }
230};
231
232#endif
233
234/* vim:set shiftwidth=4 softtabstop=4 expandtab: */