1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <string_view>
22 #include <svl/itemiter.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/outdev.hxx>
25 #include <sal/log.hxx>
27 #include <vcl/unohelp.hxx>
28 #include <com/sun/star/form/XFormComponent.hpp>
29 #include <com/sun/star/drawing/XShape.hpp>
30 #include <com/sun/star/drawing/XShapes.hpp>
31 #include <com/sun/star/drawing/XControlShape.hpp>
32 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 #include <com/sun/star/container/XIndexContainer.hpp>
34 #include <com/sun/star/text/VertOrientation.hpp>
35 #include <com/sun/star/text/TextContentAnchorType.hpp>
36 #include <com/sun/star/beans/XPropertyContainer.hpp>
37 #include <com/sun/star/beans/PropertyAttribute.hpp>
40 #include <hintids.hxx>
41 #include <editeng/fontitem.hxx>
42 #include <editeng/lrspitem.hxx>
43 #include <editeng/fhgtitem.hxx>
44 #include <editeng/colritem.hxx>
45 #include <editeng/wghtitem.hxx>
46 #include <editeng/crossedoutitem.hxx>
47 #include <editeng/udlnitem.hxx>
48 #include <editeng/postitem.hxx>
49 #include <o3tl/safeint.hxx>
50 #include <o3tl/temporary.hxx>
51 #include <unotextrange.hxx>
54 #include <IDocumentFieldsAccess.hxx>
55 #include <IDocumentMarkAccess.hxx>
57 #include <numrule.hxx>
59 #include <charatr.hxx>
60 #include <charfmt.hxx>
64 #include <flddropdown.hxx>
65 #include "sprmids.hxx"
66 #include "writerhelper.hxx"
67 #include "writerwordglue.hxx"
69 #include "ww8par2.hxx"
72 #include <unotools/fltrcfg.hxx>
73 #include <rtl/character.hxx>
74 #include <xmloff/odffields.hxx>
75 #include <comphelper/string.hxx>
77 using namespace com::sun::star
;
78 using namespace sw::util
;
79 using namespace sw::types
;
80 using namespace sw::mark
;
84 // OCX i.e. word 97 form controls
85 eF_ResT
SwWW8ImplReader::Read_F_OCX( WW8FieldDesc
*, OUString
& )
87 if( m_bObj
&& m_nPicLocFc
)
88 m_nObjLocFc
= m_nPicLocFc
;
93 eF_ResT
SwWW8ImplReader::Read_F_FormTextBox( WW8FieldDesc
* pF
, OUString
& rStr
)
95 WW8FormulaEditBox
aFormula(*this);
97 sal_Int32
const nPos(rStr
.indexOf(0x01));
98 if (pF
->nLCode
&& nPos
!= -1 && nPos
< pF
->nLCode
) {
99 ImportFormulaControl(aFormula
, pF
->nSCode
+ nPos
, WW8_CT_EDIT
);
103 Here we have a small complication. This formula control contains
104 the default text that is displayed if you edit the form field in
105 the "default text" area. But MSOffice does not display that
106 information, instead it display the result of the field,
107 MSOffice just uses the default text of the control as its
108 initial value for the displayed default text. So we will swap in
109 the field result into the formula here in place of the default
113 const SvtFilterOptions
& rOpt
= SvtFilterOptions::Get();
114 const bool bUseEnhFields
= rOpt
.IsUseEnhancedFields();
118 aFormula
.msDefault
= GetFieldResult(pF
);
121 static_cast<SwInputFieldType
*>(m_rDoc
.getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::Input
)),
126 aField
.SetHelp(aFormula
.msHelp
);
127 aField
.SetToolTip(aFormula
.msToolTip
);
129 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(*m_pPaM
, SwFormatField(aField
));
134 WW8PLCFx_Book
* pB
= m_xPlcxMan
->GetBook();
135 OUString aBookmarkName
;
137 WW8_CP currentCP
=pF
->nSCode
;
138 WW8_CP currentLen
=pF
->nLen
;
141 if (o3tl::checked_add(currentCP
, currentLen
-1, nEnd
)) {
142 SAL_WARN("sw.ww8", "broken offset, ignoring");
146 sal_uInt16 bkmFindIdx
;
147 OUString aBookmarkFind
=pB
->GetBookmark(currentCP
-1, nEnd
, bkmFindIdx
);
149 if (!aBookmarkFind
.isEmpty()) {
150 pB
->SetStatus(bkmFindIdx
, BOOK_FIELD
); // mark bookmark as consumed, such that it'll not get inserted as a "normal" bookmark again
151 if (!aBookmarkFind
.isEmpty()) {
152 aBookmarkName
=aBookmarkFind
;
158 if (pB
!=nullptr && aBookmarkName
.isEmpty()) {
159 aBookmarkName
=pB
->GetUniqueBookmarkName(aFormula
.msTitle
);
162 if (!aBookmarkName
.isEmpty()) {
163 m_aFieldStack
.back().SetBookmarkName(aBookmarkName
);
164 m_aFieldStack
.back().SetBookmarkType(ODF_FORMTEXT
);
165 if ( aFormula
.msToolTip
.getLength() < 139 )
166 m_aFieldStack
.back().getParameters()["Description"] <<= aFormula
.msToolTip
;
167 m_aFieldStack
.back().getParameters()["Name"] <<= aFormula
.msTitle
;
168 if (aFormula
.mnMaxLen
&& aFormula
.mnMaxLen
< 32768 )
169 m_aFieldStack
.back().getParameters()["MaxLength"] <<= aFormula
.mnMaxLen
;
171 if ( aFormula
.mfType
== 1 )
172 m_aFieldStack
.back().getParameters()["Type"] <<= OUString("number");
173 else if ( aFormula
.mfType
== 2 )
174 m_aFieldStack
.back().getParameters()["Type"] <<= OUString("date");
175 else if ( aFormula
.mfType
== 3 )
176 m_aFieldStack
.back().getParameters()["Type"] <<= OUString("currentTime");
177 else if ( aFormula
.mfType
== 4 )
178 m_aFieldStack
.back().getParameters()["Type"] <<= OUString("currentDate");
179 else if ( aFormula
.mfType
== 5 )
180 m_aFieldStack
.back().getParameters()["Type"] <<= OUString("calculated");
182 return eF_ResT::TEXT
;
186 eF_ResT
SwWW8ImplReader::Read_F_FormCheckBox( WW8FieldDesc
* pF
, OUString
& rStr
)
188 WW8FormulaCheckBox
aFormula(*this);
191 m_xFormImpl
.reset(new SwMSConvertControls(m_pDocShell
, m_pPaM
));
193 if (rStr
[pF
->nLCode
-1]==0x01)
194 ImportFormulaControl(aFormula
,pF
->nSCode
+pF
->nLCode
-1, WW8_CT_CHECKBOX
);
195 const SvtFilterOptions
& rOpt
= SvtFilterOptions::Get();
196 const bool bUseEnhFields
= rOpt
.IsUseEnhancedFields();
200 m_xFormImpl
->InsertFormula(aFormula
);
204 OUString aBookmarkName
;
205 WW8PLCFx_Book
* pB
= m_xPlcxMan
->GetBook();
207 WW8_CP currentCP
=pF
->nSCode
;
208 WW8_CP currentLen
=pF
->nLen
;
210 sal_uInt16 bkmFindIdx
;
211 OUString aBookmarkFind
=pB
->GetBookmark(currentCP
-1, currentCP
+currentLen
-1, bkmFindIdx
);
213 if (!aBookmarkFind
.isEmpty()) {
214 pB
->SetStatus(bkmFindIdx
, BOOK_FIELD
); // mark as consumed by field
215 if (!aBookmarkFind
.isEmpty()) {
216 aBookmarkName
=aBookmarkFind
;
221 if (pB
!=nullptr && aBookmarkName
.isEmpty()) {
222 aBookmarkName
=pB
->GetUniqueBookmarkName(aFormula
.msTitle
);
225 if (!aBookmarkName
.isEmpty())
227 IDocumentMarkAccess
* pMarksAccess
= m_rDoc
.getIDocumentMarkAccess( );
228 IFieldmark
* pFieldmark
= pMarksAccess
->makeNoTextFieldBookmark(
229 *m_pPaM
, aBookmarkName
, ODF_FORMCHECKBOX
);
230 OSL_ENSURE(pFieldmark
!=nullptr, "hmmm; why was the bookmark not created?");
231 if (pFieldmark
!=nullptr) {
232 IFieldmark::parameter_map_t
* const pParameters
= pFieldmark
->GetParameters();
233 ICheckboxFieldmark
* pCheckboxFm
= dynamic_cast<ICheckboxFieldmark
*>(pFieldmark
);
234 (*pParameters
)[ODF_FORMCHECKBOX_HELPTEXT
] <<= aFormula
.msToolTip
;
237 pCheckboxFm
->SetChecked(aFormula
.mnChecked
!= 0);
238 // set field data here...
244 eF_ResT
SwWW8ImplReader::Read_F_FormListBox( WW8FieldDesc
* pF
, OUString
& rStr
)
246 WW8FormulaListBox
aFormula(*this);
248 if (pF
->nLCode
> 0 && rStr
.getLength() >= pF
->nLCode
&& rStr
[pF
->nLCode
-1] == 0x01)
249 ImportFormulaControl(aFormula
,pF
->nSCode
+pF
->nLCode
-1, WW8_CT_DROPDOWN
);
251 const SvtFilterOptions
& rOpt
= SvtFilterOptions::Get();
252 bool bUseEnhFields
= rOpt
.IsUseEnhancedFields();
256 SwDropDownField
aField(static_cast<SwDropDownFieldType
*>(m_rDoc
.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Dropdown
)));
258 aField
.SetName(aFormula
.msTitle
);
259 aField
.SetHelp(aFormula
.msHelp
);
260 aField
.SetToolTip(aFormula
.msToolTip
);
262 if (!aFormula
.maListEntries
.empty())
264 aField
.SetItems(std::vector(aFormula
.maListEntries
));
265 int nIndex
= aFormula
.mfDropdownIndex
< aFormula
.maListEntries
.size() ? aFormula
.mfDropdownIndex
: 0;
266 aField
.SetSelectedItem(aFormula
.maListEntries
[nIndex
]);
269 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(*m_pPaM
, SwFormatField(aField
));
275 OUString aBookmarkName
;
276 WW8PLCFx_Book
* pB
= m_xPlcxMan
->GetBook();
279 WW8_CP currentCP
=pF
->nSCode
;
280 WW8_CP currentLen
=pF
->nLen
;
282 sal_uInt16 bkmFindIdx
;
283 OUString aBookmarkFind
=pB
->GetBookmark(currentCP
-1, currentCP
+currentLen
-1, bkmFindIdx
);
285 if (!aBookmarkFind
.isEmpty())
287 pB
->SetStatus(bkmFindIdx
, BOOK_FIELD
); // mark as consumed by field
288 if (!aBookmarkFind
.isEmpty())
289 aBookmarkName
=aBookmarkFind
;
293 if (pB
!=nullptr && aBookmarkName
.isEmpty())
294 aBookmarkName
=pB
->GetUniqueBookmarkName(aFormula
.msTitle
);
296 if (!aBookmarkName
.isEmpty())
298 IDocumentMarkAccess
* pMarksAccess
= m_rDoc
.getIDocumentMarkAccess( );
299 IFieldmark
*pFieldmark
=
300 pMarksAccess
->makeNoTextFieldBookmark( *m_pPaM
, aBookmarkName
, ODF_FORMDROPDOWN
);
301 OSL_ENSURE(pFieldmark
!=nullptr, "hmmm; why was the bookmark not created?");
302 if ( pFieldmark
!= nullptr )
304 uno::Sequence
< OUString
> vListEntries(aFormula
.maListEntries
.size());
305 std::copy(aFormula
.maListEntries
.begin(), aFormula
.maListEntries
.end(), vListEntries
.getArray());
306 (*pFieldmark
->GetParameters())[ODF_FORMDROPDOWN_LISTENTRY
] <<= vListEntries
;
307 sal_Int32 nIndex
= aFormula
.mfDropdownIndex
< aFormula
.maListEntries
.size() ? aFormula
.mfDropdownIndex
: -1;
309 (*pFieldmark
->GetParameters())[ODF_FORMDROPDOWN_RESULT
] <<= nIndex
;
310 // set field data here...
318 eF_ResT
SwWW8ImplReader::Read_F_HTMLControl(WW8FieldDesc
*, OUString
&)
320 if( m_bObj
&& m_nPicLocFc
)
321 m_nObjLocFc
= m_nPicLocFc
;
323 return eF_ResT::TEXT
;
326 // Helper declarations
328 // Style Id's for each level
329 typedef sal_uInt16 WW8aIdSty
[WW8ListManager::nMaxLevel
];
330 // Character Style Pointer
331 typedef SwCharFormat
* WW8aCFormat
[WW8ListManager::nMaxLevel
];
335 struct WW8LST
// only THOSE entries, WE need!
337 WW8aIdSty aIdSty
; // Style Id's for each level,
338 // nIStDNil if no style linked
339 sal_uInt32 nIdLst
; // Unique List ID
340 sal_uInt32 nTplC
; // Unique template code - What is this?
341 bool bSimpleList
:1; // Flag: List only has ONE level
342 bool bRestartHdn
:1; // WW6-Compatibility-Flag:
343 // true if the list should start numbering over
344 }; // at the beginning of each section
348 const sal_uInt32 cbLSTF
=28;
352 struct WW8LFO
// only THOSE entries, WE need!
354 SwNumRule
* pNumRule
; // Parent NumRule
355 sal_uInt32 nIdLst
; // Unique List ID
356 sal_uInt8 nLfoLvl
; // count of levels whose format is overridden
360 struct WW8LVL
// only THE entries, WE need!
362 sal_Int32 nStartAt
; // start at value for this value
363 sal_Int32 nV6DxaSpace
;// Ver6-Compatible: min Space between Num and text::Paragraph
364 sal_Int32 nV6Indent
; // Ver6-Compatible: Width of prefix text;
365 // Use definition of first line indent if appropriate!
366 // Paragraph attributes from GrpprlPapx
367 sal_uInt16 nDxaLeft
; // left indent
368 short nDxaLeft1
; // first line indent
370 sal_uInt8 nNFC
; // number format code
371 // Offset of fieldcodes in Num-X-String
372 sal_uInt8 aOfsNumsXCH
[WW8ListManager::nMaxLevel
];
373 sal_uInt8 nLenGrpprlChpx
; // length, in bytes, of the LVL's grpprlChpx
374 sal_uInt8 nLenGrpprlPapx
; // length, in bytes, of the LVL's grpprlPapx
375 sal_uInt8 nAlign
; // alignment (left, right, centered) of the number
376 bool bV6Prev
; // Ver6-Compatible: number will include previous levels
377 bool bV6PrSp
; // Ver6-Compatible: doesn't matter
378 bool bV6
; // if true, pay attention to the V6-Compatible Entries!
384 sal_Int32 nStartAt
; // start-at value if bFormat==false and bStartAt == true
385 // (if bFormat==true, the start-at is stored in the LVL)
386 sal_uInt8 nLevel
; // the level to be overridden
387 // this byte has not been packed into the following byte on _purpose_ !!
388 // (see comment of struct WW8LFOInfo)
390 bool bStartAt
:1; // true if the start-at value is overridden
391 bool bFormat
:1; // true if the formatting is overridden
394 nStartAt(1), nLevel(0), bStartAt(true), bFormat(false) {}
399 // Data to be saved in ListInfo
401 struct WW8LSTInfo
// sorted by nIdLst (in WW8 used list-Id)
403 std::vector
<ww::bytes
> maParaSprms
;
404 WW8aIdSty aIdSty
; // Style Id's for each level
405 WW8aCFormat aCharFormat
= {}; // Character Style Pointer
407 SwNumRule
* pNumRule
; // Pointer to list-template in Writer
408 sal_uInt32 nIdLst
; // WW8Id of this list
409 bool bSimpleList
:1;// Flag, if this NumRule only uses one Level
410 bool bUsedInDoc
:1;// Flag, if this NumRule is used in the Doc,
411 // or is supposed to be deleted on Reader-End
413 WW8LSTInfo(SwNumRule
* pNumRule_
, const WW8LST
& aLST
)
414 : pNumRule(pNumRule_
), nIdLst(aLST
.nIdLst
),
415 bSimpleList(aLST
.bSimpleList
), bUsedInDoc(false)
417 memcpy( aIdSty
, aLST
.aIdSty
, sizeof( aIdSty
));
422 // Data to be saved in ListenFormatOverrideInfos
424 struct WW8LFOInfo
// unordered, means ordered like in WW8 Stream
426 std::vector
<ww::bytes
> maParaSprms
;
427 std::vector
<WW8LFOLVL
> maOverrides
;
428 SwNumRule
* pNumRule
; // Pointer to list template in Writer
429 // either List in LSTInfos or own List
430 // (in Ctor use the list from LSTInfos first)
432 sal_uInt32 nIdLst
; // WW8-Id of the relevant list
433 sal_uInt8 nLfoLvl
; // count of levels whose format is overridden
434 // yes we could include nLfoLvl (via :4) into the following byte,
435 // but it probably would be a source of error once MS increases their Listformat
436 // to more than 15 levels
438 bool bOverride
:1;// Flag if NumRule is not included in maLSTInfos,
439 // but was created for m_LFOInfos
440 bool bUsedInDoc
:1;// Flag if NumRule is used in Doc,
441 // or should be deleted on Reader-End
442 bool bLSTbUIDSet
:1;// Flag, if bUsedInDoc is set in maLSTInfos
444 explicit WW8LFOInfo(const WW8LFO
& rLFO
);
447 WW8LFOInfo::WW8LFOInfo(const WW8LFO
& rLFO
)
448 : maParaSprms(WW8ListManager::nMaxLevel
)
449 , maOverrides(WW8ListManager::nMaxLevel
)
450 , pNumRule(rLFO
.pNumRule
)
451 , nIdLst(rLFO
.nIdLst
)
452 , nLfoLvl(rLFO
.nLfoLvl
)
453 , bOverride(rLFO
.nLfoLvl
!= 0)
461 // find Sprm-Parameter-Data, if Sprm is included in Grpprl
462 SprmResult
WW8ListManager::GrpprlHasSprm(sal_uInt16 nId
, sal_uInt8
& rSprms
,
465 return maSprmParser
.findSprmData(nId
, &rSprms
, nLen
);
475 explicit ListWithId(sal_uInt32 nIdLst
) : mnIdLst(nIdLst
) {}
476 bool operator() (const std::unique_ptr
<WW8LSTInfo
>& pEntry
) const
477 { return (pEntry
->nIdLst
== mnIdLst
); }
482 // Access via List-Id of LST Entry
483 WW8LSTInfo
* WW8ListManager::GetLSTByListId( sal_uInt32 nIdLst
) const
486 std::find_if(maLSTInfos
.begin(),maLSTInfos
.end(),ListWithId(nIdLst
));
487 if (aResult
== maLSTInfos
.end())
489 return aResult
->get();
492 SvxNumType
WW8ListManager::GetSvxNumTypeFromMSONFC(sal_uInt16 nNFC
)
494 SvxNumType
nType(SVX_NUM_ARABIC
);
499 nType
= SVX_NUM_ARABIC
;
502 nType
= SVX_NUM_ROMAN_UPPER
;
505 nType
= SVX_NUM_ROMAN_LOWER
;
508 nType
= SVX_NUM_CHARS_UPPER_LETTER_N
;
511 nType
= SVX_NUM_CHARS_LOWER_LETTER_N
;
514 nType
= SVX_NUM_TEXT_NUMBER
;
516 case 6: // cardinalText
517 nType
= SVX_NUM_TEXT_CARDINAL
;
519 case 7: // ordinalText
520 nType
= SVX_NUM_TEXT_ORDINAL
;
525 // 0x09, msonfcChiManSty
526 nType
= SVX_NUM_SYMBOL_CHICAGO
;
528 //case 15: // decimalHalfWidth
529 //case 17: // japaneseDigitalTenThousand
531 case 18: // decimalEnclosedCircle
532 case 28: // decimalEnclosedCircleChinese
533 case 29: // ideographEnclosedCircle
534 nType
= SVX_NUM_CIRCLE_NUMBER
;
537 // 0x16, msonfcArabicLZ
538 nType
= SVX_NUM_ARABIC_ZERO
;
541 nType
= SVX_NUM_CHAR_SPECIAL
;
545 nType
= SVX_NUM_NUMBER_NONE
;
549 nType
= SVX_NUM_FULL_WIDTH_ARABIC
;
552 nType
= SVX_NUM_TIAN_GAN_ZH
;
554 case 31: // ideographZodiac
555 case 32: // ideographZodiacTraditional
556 nType
= SVX_NUM_DI_ZI_ZH
;
558 case 33: // taiwaneseCounting
564 nType
= SVX_NUM_NUMBER_LOWER_ZH
;
567 nType
= SVX_NUM_NUMBER_UPPER_ZH_TW
;
570 nType
= SVX_NUM_NUMBER_UPPER_ZH
;
573 case 16: // japaneseLegal
574 nType
= SVX_NUM_NUMBER_TRADITIONAL_JA
;
577 nType
= SVX_NUM_AIU_FULLWIDTH_JA
;
580 nType
= SVX_NUM_AIU_HALFWIDTH_JA
;
583 nType
= SVX_NUM_IROHA_FULLWIDTH_JA
;
586 nType
= SVX_NUM_IROHA_HALFWIDTH_JA
;
589 nType
= SVX_NUM_HANGUL_SYLLABLE_KO
;
592 nType
= SVX_NUM_HANGUL_JAMO_KO
;
594 //case 26: // decimalEnclosedFullstop
595 //case 27: // decimalEnclosedParen
596 //case 40: // decimal (Chinese)
598 case 41: // koreanDigital
599 case 42: // koreanCounting
600 case 43: // koreanLegal
601 nType
= SVX_NUM_NUMBER_HANGUL_KO
;
603 case 44: // koreanDigital2
604 nType
= SVX_NUM_NUMBER_UPPER_KO
;
607 nType
= SVX_NUM_NUMBER_HEBREW
;
609 case 46: // arabicAlpha
610 nType
= SVX_NUM_CHARS_ARABIC
;
613 nType
= SVX_NUM_CHARS_HEBREW
;
615 case 48: // arabicAbjad
616 nType
= SVX_NUM_CHARS_ARABIC_ABJAD
;
618 case 49: // hindiVowels
619 nType
= SVX_NUM_CHARS_NEPALI
;
621 //case 50: // hindiConsonants
622 //case 51: // hindiNumbers
623 //case 52: // hindiCounting
625 case 53: // thaiLetters
626 nType
= SVX_NUM_CHARS_THAI
;
628 //case 54: // thaiNumbers
629 //case 55: // thaiCounting
630 //case 56: // vietnameseCounting
631 //case 57: // numberInDash
633 case 58: // russianLower
634 nType
= SVX_NUM_CHARS_CYRILLIC_LOWER_LETTER_RU
;
636 case 59: // russianUpper
637 nType
=SVX_NUM_CHARS_CYRILLIC_UPPER_LETTER_RU
;
640 nType
= SVX_NUM_ARABIC
;
647 bool WW8ListManager::ReadLVL(SwNumFormat
& rNumFormat
, std::unique_ptr
<SfxItemSet
>& rpItemSet
,
648 sal_uInt16 nLevelStyle
, bool bSetStartNo
, sal_uInt16
/*nLevel*/, ww::bytes
&rParaSprms
)
651 SvxNumType
nType(SVX_NUM_ARABIC
);
652 SvxAdjust eAdj
; // Alignment (Left/right/centered)
653 sal_UCS4
cBullet(0x2190); // default safe bullet
655 sal_Unicode
cGrfBulletCP(USHRT_MAX
);
661 m_rSt
.ReadInt32( aLVL
.nStartAt
);
662 m_rSt
.ReadUChar( aLVL
.nNFC
);
663 m_rSt
.ReadUChar( aBits1
);
664 if( ERRCODE_NONE
!= m_rSt
.GetError() ) return false;
665 aLVL
.nAlign
= (aBits1
& 0x03);
666 if( aBits1
& 0x10 ) aLVL
.bV6Prev
= true;
667 if( aBits1
& 0x20 ) aLVL
.bV6PrSp
= true;
668 if( aBits1
& 0x40 ) aLVL
.bV6
= true;
670 for(sal_uInt8 nLevelB
= 0; nLevelB
< nMaxLevel
; ++nLevelB
)
672 m_rSt
.ReadUChar( aLVL
.aOfsNumsXCH
[ nLevelB
] );
673 if( ERRCODE_NONE
!= m_rSt
.GetError() )
683 sal_uInt8
ixchFollow(0);
684 m_rSt
.ReadUChar( ixchFollow
);
685 m_rSt
.ReadInt32( aLVL
.nV6DxaSpace
);
686 m_rSt
.ReadInt32( aLVL
.nV6Indent
);
687 m_rSt
.ReadUChar( aLVL
.nLenGrpprlChpx
);
688 m_rSt
.ReadUChar( aLVL
.nLenGrpprlPapx
);
690 if( ERRCODE_NONE
!= m_rSt
.GetError()) return false;
692 // 2. read PAPx if needed and search for indent values
694 short nTabPos
= 0; // #i86652# - read tab setting
695 if( aLVL
.nLenGrpprlPapx
)
697 sal_uInt8 aGrpprlPapx
[ 255 ];
698 if (aLVL
.nLenGrpprlPapx
!= m_rSt
.ReadBytes(&aGrpprlPapx
, aLVL
.nLenGrpprlPapx
))
700 // "sprmPDxaLeft" pap.dxaLeft;dxa;word;
701 SprmResult aSprm
= GrpprlHasSprm(0x840F,aGrpprlPapx
[0],aLVL
.nLenGrpprlPapx
);
703 aSprm
= GrpprlHasSprm(0x845E,aGrpprlPapx
[0],aLVL
.nLenGrpprlPapx
);
705 if (aSprm
.pSprm
&& aSprm
.nRemainingData
>= 2)
707 const sal_uInt8
*pBegin
= aSprm
.pSprm
- 2;
709 rParaSprms
.push_back(*pBegin
++);
710 short nDxaLeft
= SVBT16ToUInt16(aSprm
.pSprm
);
711 aLVL
.nDxaLeft
= (0 < nDxaLeft
) ? o3tl::narrowing
<sal_uInt16
>(nDxaLeft
)
712 : o3tl::narrowing
<sal_uInt16
>(-nDxaLeft
);
715 // "sprmPDxaLeft1" pap.dxaLeft1;dxa;word;
716 aSprm
= GrpprlHasSprm(0x8411,aGrpprlPapx
[0],aLVL
.nLenGrpprlPapx
);
718 aSprm
= GrpprlHasSprm(0x8460,aGrpprlPapx
[0],aLVL
.nLenGrpprlPapx
);
720 if (aSprm
.pSprm
&& aSprm
.nRemainingData
>= 2)
722 const sal_uInt8
*pBegin
= aSprm
.pSprm
- 2;
724 rParaSprms
.push_back(*pBegin
++);
725 aLVL
.nDxaLeft1
= SVBT16ToUInt16(aSprm
.pSprm
);
728 // #i86652# - read tab setting
729 aSprm
= GrpprlHasSprm(0xC615,aGrpprlPapx
[0],aLVL
.nLenGrpprlPapx
);
730 const sal_uInt8
* pSprm
= aSprm
.pSprm
;
731 if (pSprm
&& aSprm
.nRemainingData
>= 5)
736 if (*pSprm
++ == 0) //nDel
738 if (*pSprm
++ == 1) //nIns
740 nTabPos
= SVBT16ToUInt16(pSprm
);
742 if (*pSprm
== 6) //type
749 OSL_ENSURE(bDone
, "tab setting in numbering is "
750 "of unexpected configuration");
752 if ( rNumFormat
.GetPositionAndSpaceMode() ==
753 SvxNumberFormat::LABEL_WIDTH_AND_POSITION
)
755 // If there is a tab setting with a larger value, then use that.
756 // Ideally we would allow tabs to be used in numbering fields and set
757 // this on the containing paragraph which would make it actually work
761 const sal_uInt16 nDesired
= aLVL
.nDxaLeft
+ aLVL
.nDxaLeft1
;
763 bool bDoAdjust
= false;
764 if ( nDesired
< aLVL
.nDxaLeft
)
766 if ( nDesired
< nTabPos
&& nTabPos
< aLVL
.nDxaLeft
)
773 if ( aLVL
.nDxaLeft
< nTabPos
&& nTabPos
< nDesired
)
781 aLVL
.nDxaLeft
= (0 < nTabPos
)
782 ? o3tl::narrowing
<sal_uInt16
>(nTabPos
)
783 : o3tl::narrowing
<sal_uInt16
>(-nTabPos
);
785 aLVL
.nDxaLeft1
= nDesired
- aLVL
.nDxaLeft
;
791 // 3. read CHPx if needed
793 sal_uInt16 nWitchPicIsBullet
= USHRT_MAX
;
794 bool bIsPicBullet
= false;
796 if( aLVL
.nLenGrpprlChpx
)
798 sal_uInt8 aGrpprlChpx
[ 255 ] = {};
799 if (aLVL
.nLenGrpprlChpx
!= m_rSt
.ReadBytes(&aGrpprlChpx
, aLVL
.nLenGrpprlChpx
))
802 //For i120928,parse the graphic info of bullets
803 SprmResult aSprmWhichPis
= GrpprlHasSprm(NS_sprm::CPbiIBullet::val
, aGrpprlChpx
[0],aLVL
.nLenGrpprlChpx
);
804 SprmResult aSprmIsPicBullet
= GrpprlHasSprm(NS_sprm::CPbiGrf::val
, aGrpprlChpx
[0],aLVL
.nLenGrpprlChpx
);
805 if (aSprmWhichPis
.pSprm
&& aSprmWhichPis
.nRemainingData
>= 1)
807 nWitchPicIsBullet
= *aSprmWhichPis
.pSprm
;
809 if (aSprmIsPicBullet
.pSprm
&& aSprmIsPicBullet
.nRemainingData
>= 1)
811 bIsPicBullet
= (*aSprmIsPicBullet
.pSprm
) & 0x0001;
814 // create new Itemset for character attributes
815 rpItemSet
.reset(new SfxItemSetFixed
<RES_CHRATR_BEGIN
, RES_CHRATR_END
- 1>( m_rDoc
.GetAttrPool() ));
817 // Set Reader-ItemSet-Pointer to the newly created set
818 m_rReader
.SetCurrentItemSet(std::move(rpItemSet
));
819 // Set Reader-Style to Style of this Level
820 sal_uInt16 nOldColl
= m_rReader
.GetCurrentColl();
821 sal_uInt16 nNewColl
= nLevelStyle
;
822 if (ww::stiNil
== nNewColl
)
824 m_rReader
.SetNCurrentColl( nNewColl
);
826 // The Read_xy() methods in WW8PAR6.cxx are calling their respective
827 // NewAttr() or GetFormatAttr() which can determine, by using the assigned
828 // Reader-ItemSet-Pointer, whether this specific ItemSet is relevant
829 // and not a Stack or Style!
830 sal_uInt16 nOldFlags1
= m_rReader
.GetToggleAttrFlags();
831 sal_uInt16 nOldFlags2
= m_rReader
.GetToggleBiDiAttrFlags();
833 WW8SprmIter
aSprmIter(&aGrpprlChpx
[0], aLVL
.nLenGrpprlChpx
,
835 while (const sal_uInt8
* pSprm
= aSprmIter
.GetSprms())
837 m_rReader
.ImportSprm(pSprm
, aSprmIter
.GetRemLen(), aSprmIter
.GetCurrentId());
841 // Reset Reader-ItemSet-Pointer and Reader-Style
842 rpItemSet
= m_rReader
.SetCurrentItemSet(nullptr);
843 m_rReader
.SetNCurrentColl( nOldColl
);
844 m_rReader
.SetToggleAttrFlags(nOldFlags1
);
845 m_rReader
.SetToggleBiDiAttrFlags(nOldFlags2
);
848 // 4. Read numbering String. Results in prefix and postfix
850 OUString
sNumString(comphelper::string::sanitizeStringSurrogates(read_uInt16_PascalString(m_rSt
)));
852 // 5. convert read values into Writer syntax
854 nType
= GetSvxNumTypeFromMSONFC(aLVL
.nNFC
);
855 //For i120928,type info
858 nType
= SVX_NUM_BITMAP
;
861 if (style::NumberingType::CHAR_SPECIAL
== nType
)
863 cBullet
= !sNumString
.isEmpty()
864 ? sNumString
.iterateCodePoints(&o3tl::temporary(sal_Int32(0))) : 0x2190;
866 if (!cBullet
) // unsave control code?
869 else if (style::NumberingType::BITMAP
== nType
) //For i120928,position index info of graphic
871 cGrfBulletCP
= nWitchPicIsBullet
; // This is a bullet picture ID
874 switch( aLVL
.nAlign
)
877 eAdj
= SvxAdjust::Left
;
880 eAdj
= SvxAdjust::Center
;
883 eAdj
= SvxAdjust::Right
;
886 // Writer here cannot do block justification
887 eAdj
= SvxAdjust::Left
;
891 OSL_ENSURE( false, "Value of aLVL.nAlign is not supported" );
893 eAdj
= SvxAdjust::Left
;
897 // 6. Configure NumFormat
898 if( bSetStartNo
&& 0 <= aLVL
.nStartAt
)
899 rNumFormat
.SetStart(o3tl::narrowing
<sal_uInt16
>(aLVL
.nStartAt
));
900 rNumFormat
.SetNumberingType( nType
);
901 rNumFormat
.SetNumAdjust( eAdj
);
903 if( style::NumberingType::CHAR_SPECIAL
== nType
)
905 // first character of the Prefix-Text is the Bullet
906 rNumFormat
.SetBulletChar(cBullet
);
907 // Don't forget: further below, after building styles
908 // Call SetBulletFont() !!!
910 //For i120928,position index info
911 else if (style::NumberingType::BITMAP
== nType
)
913 rNumFormat
.SetGrfBulletCP(cGrfBulletCP
);
917 // Replace symbols at aOfsNumsXCH offsets to %1%, %2% as supported by LO
918 OUString sListFormat
= sNumString
;
919 if (sListFormat
.getLength())
921 sal_uInt32 nExtraOffset
= 0;
922 sal_uInt8 nLevelB
= 0;
923 while (nLevelB
< nMaxLevel
&& aLVL
.aOfsNumsXCH
[nLevelB
])
925 // Replacement symbol is read from source string from position taken from aOfsNumsXCH array
926 sal_uInt8 nOffset
= aLVL
.aOfsNumsXCH
[nLevelB
] + nExtraOffset
- 1;
927 if (nOffset
>= sListFormat
.getLength())
929 SAL_WARN("sw.ww8", "List level reference is beyond the border. Ignored.");
933 sal_uInt8 nReplacement
= sListFormat
[nOffset
] + 1;
935 OUString
sReplacement("%" + OUString::number(nReplacement
) + "%");
936 sListFormat
= sListFormat
.replaceAt(nOffset
, 1, sReplacement
);
938 // We need also update an offset, since we are replacing one symbol by at least two
939 nExtraOffset
+= sReplacement
.getLength() - 1;
944 rNumFormat
.SetListFormat(sListFormat
);
946 // Total count of replacement holders is determining amount of required parent numbering to include
947 // TODO: not sure how "%" symbol is escaped. This is not supported yet
948 sal_Int16 nParentNum
= comphelper::string::getTokenCount(sListFormat
, '%');
949 rNumFormat
.SetIncludeUpperLevels(nParentNum
);
953 if ( rNumFormat
.GetPositionAndSpaceMode() ==
954 SvxNumberFormat::LABEL_WIDTH_AND_POSITION
)
956 if (eAdj
== SvxAdjust::Right
)
958 rNumFormat
.SetAbsLSpace(aLVL
.nDxaLeft
);
959 rNumFormat
.SetFirstLineOffset(-aLVL
.nDxaLeft
);
960 rNumFormat
.SetCharTextDistance(-aLVL
.nDxaLeft1
);
964 rNumFormat
.SetAbsLSpace( aLVL
.nDxaLeft
);
965 rNumFormat
.SetFirstLineOffset(aLVL
.nDxaLeft1
);
970 rNumFormat
.SetIndentAt( aLVL
.nDxaLeft
);
971 rNumFormat
.SetFirstLineIndent(aLVL
.nDxaLeft1
);
973 rNumFormat
.SetListtabPos( nTabPos
);
975 rNumFormat
.SetListtabPos( aLVL
.nV6Indent
);
976 SvxNumberFormat::LabelFollowedBy eNumLabelFollowedBy
= SvxNumberFormat::LISTTAB
;
977 switch ( ixchFollow
)
981 eNumLabelFollowedBy
= SvxNumberFormat::LISTTAB
;
986 eNumLabelFollowedBy
= SvxNumberFormat::SPACE
;
991 eNumLabelFollowedBy
= SvxNumberFormat::NOTHING
;
995 rNumFormat
.SetLabelFollowedBy( eNumLabelFollowedBy
);
1001 void WW8ListManager::AdjustLVL( sal_uInt8 nLevel
, SwNumRule
& rNumRule
,
1002 WW8aISet
const & rListItemSet
, WW8aCFormat
& rCharFormat
, bool& bNewCharFormatCreated
,
1003 const OUString
& sPrefix
)
1005 bNewCharFormatCreated
= false;
1006 sal_uInt8 nIdenticalItemSetLevel
;
1007 const SfxPoolItem
* pItem
;
1009 SwNumFormat aNumFormat
= rNumRule
.Get( nLevel
);
1011 SfxItemSet
* pThisLevelItemSet
= rListItemSet
[nLevel
].get();
1013 if( pThisLevelItemSet
&& pThisLevelItemSet
->Count())
1015 nIdenticalItemSetLevel
= nMaxLevel
;
1016 SfxItemIter
aIter( *pThisLevelItemSet
);
1017 for (sal_uInt8 nLowerLevel
= 0; nLowerLevel
< nLevel
; ++nLowerLevel
)
1019 SfxItemSet
* pLowerLevelItemSet
= rListItemSet
[nLowerLevel
].get();
1020 if( pLowerLevelItemSet
1021 && (pLowerLevelItemSet
->Count() == pThisLevelItemSet
->Count()) )
1023 nIdenticalItemSetLevel
= nLowerLevel
;
1024 const SfxPoolItem
* pItemIter
= aIter
.GetCurItem();
1027 if( // search for appropriate pItem in pLowerLevelItemSet
1028 (SfxItemState::SET
!= pLowerLevelItemSet
->GetItemState(
1029 pItemIter
->Which(), false, &pItem
) )
1030 || // use virtual "!=" Operator
1031 (*pItem
!= *pItemIter
) )
1032 // if no Item with equal nWhich was found or Item value was not equal
1033 // store inequality and break!
1035 nIdenticalItemSetLevel
= nMaxLevel
;
1038 pItemIter
= aIter
.NextItem();
1039 } while (pItemIter
);
1041 if( nIdenticalItemSetLevel
!= nMaxLevel
)
1046 SwCharFormat
* pFormat
;
1047 if (nMaxLevel
== nIdenticalItemSetLevel
)
1050 const OUString
aName( (!sPrefix
.isEmpty() ? sPrefix
: rNumRule
.GetName())
1051 + "z" + OUString::number( nLevel
) );
1053 // remove const by casting
1054 pFormat
= m_rDoc
.MakeCharFormat(aName
, m_rDoc
.GetDfltCharFormat());
1055 bNewCharFormatCreated
= true;
1057 pFormat
->SetFormatAttr( *pThisLevelItemSet
);
1062 pFormat
= rCharFormat
[ nIdenticalItemSetLevel
];
1066 rCharFormat
[ nLevel
] = pFormat
;
1068 // Append Style to NumFormat
1070 aNumFormat
.SetCharFormat( pFormat
);
1073 // if necessary: Append Bullet Font to NumFormat
1075 if( SVX_NUM_CHAR_SPECIAL
== aNumFormat
.GetNumberingType() )
1077 SwCharFormat
* pFormat
= aNumFormat
.GetCharFormat();
1081 aFont
= numfunc::GetDefBulletFont();
1085 const SvxFontItem
& rFontItem
= pFormat
->GetFont();
1086 aFont
.SetFamily( rFontItem
.GetFamily() );
1087 aFont
.SetFamilyName( rFontItem
.GetFamilyName() );
1088 aFont
.SetStyleName( rFontItem
.GetStyleName() );
1089 aFont
.SetPitch( rFontItem
.GetPitch() );
1090 aFont
.SetCharSet( rFontItem
.GetCharSet() );
1092 aNumFormat
.SetBulletFont( &aFont
);
1095 // Set NumFormat in NumRule
1097 rNumRule
.Set(nLevel
, aNumFormat
);
1100 SwNumRule
* WW8ListManager::CreateNextRule(bool bSimple
)
1102 // Used to build the Style Name
1103 const OUString
sPrefix("WW8Num" + OUString::number(m_nUniqueList
++));
1106 m_rDoc
.MakeNumRule( m_rDoc
.GetUniqueNumRuleName(&sPrefix
), nullptr, false,
1107 SvxNumberFormat::LABEL_ALIGNMENT
);
1108 SwNumRule
* pMyNumRule
= m_rDoc
.GetNumRuleTable()[nRul
];
1109 pMyNumRule
->SetAutoRule(false);
1110 pMyNumRule
->SetContinusNum(bSimple
);
1114 SwNumRule
* WW8ListManager::GetNumRule(size_t i
)
1116 if (i
< maLSTInfos
.size())
1117 return maLSTInfos
[i
]->pNumRule
;
1124 WW8ListManager::WW8ListManager(SvStream
& rSt_
, SwWW8ImplReader
& rReader_
)
1125 : maSprmParser(rReader_
.GetFib()), m_rReader(rReader_
)
1126 , m_rDoc(m_rReader
.GetDoc())
1127 , m_rFib(m_rReader
.GetFib()), m_rSt(rSt_
)
1129 , m_nLastLFOPosition(USHRT_MAX
)
1132 // LST and LFO only since WW8
1133 if( ( 8 > m_rFib
.m_nVersion
)
1134 || ( m_rFib
.m_fcPlcfLst
== m_rFib
.m_fcPlfLfo
)
1135 || ( m_rFib
.m_lcbPlcfLst
< 2 )
1136 || ( m_rFib
.m_lcbPlfLfo
< 2) ) return; // no public lists
1141 sal_uInt64 nOriginalPos
= m_rSt
.Tell();
1143 // 1. read PLCF LST and create list templates in Writer
1145 bool bOk
= checkSeek(m_rSt
, m_rFib
.m_fcPlcfLst
);
1150 sal_uInt32 nRemainingPlcfLst
= m_rFib
.m_lcbPlcfLst
;
1152 sal_uInt16
nListCount(0);
1153 m_rSt
.ReadUInt16( nListCount
);
1154 nRemainingPlcfLst
-= 2;
1155 bOk
= nListCount
> 0;
1161 const size_t nMinRecordSize
= 10 + 2*nMaxLevel
;
1162 const size_t nMaxRecords
= m_rSt
.remainingSize() / nMinRecordSize
;
1163 if (nListCount
> nMaxRecords
)
1165 SAL_WARN("sw.ww8", "Parsing error: " << nMaxRecords
<<
1166 " max possible entries, but " << nListCount
<< " claimed, truncating");
1167 nListCount
= nMaxRecords
;
1169 for (sal_uInt16 nList
=0; nList
< nListCount
; ++nList
)
1171 if (nRemainingPlcfLst
< cbLSTF
)
1178 m_rSt
.ReadUInt32( aLST
.nIdLst
);
1179 m_rSt
.ReadUInt32( aLST
.nTplC
);
1180 for (sal_uInt16
& nLevel
: aLST
.aIdSty
)
1181 m_rSt
.ReadUInt16( nLevel
);
1183 sal_uInt8
aBits1(0);
1184 m_rSt
.ReadUChar( aBits1
);
1189 aLST
.bSimpleList
= true;
1191 aLST
.bRestartHdn
= true;
1193 // 1.1.2 new NumRule inserted in Doc and WW8LSTInfo marked
1197 In word 2000 microsoft got rid of creating new "simple lists" with
1198 only 1 level, all new lists are created with 9 levels. To hack it
1199 so that the list types formerly known as simple lists still have
1200 their own tab page to themselves one of the reserved bits is used
1201 to show that a given list is to be in the simple list tabpage.
1202 This has now nothing to do with the actual number of list level a
1203 list has, only how many will be shown in the user interface.
1205 i.e. create a simple list in 2000 and open it in 97 and 97 will
1206 claim (correctly) that it is an outline list. We can set our
1207 continuous flag in these lists to store this information.
1209 SwNumRule
* pMyNumRule
= CreateNextRule(
1210 aLST
.bSimpleList
|| (aBits1
& 0x10));
1212 WW8LSTInfo
* pLSTInfo
= new WW8LSTInfo(pMyNumRule
, aLST
);
1213 maLSTInfos
.emplace_back(pLSTInfo
);
1215 nRemainingPlcfLst
-= cbLSTF
;
1218 // 1.2 read all LVL of all aLST
1220 sal_uInt16 nLSTInfos
= static_cast< sal_uInt16
>(maLSTInfos
.size());
1221 for (sal_uInt16 nList
= 0; nList
< nLSTInfos
; ++nList
)
1223 WW8aISet aItemSet
; // Character attributes from GrpprlChpx
1225 WW8LSTInfo
* pListInfo
= maLSTInfos
[nList
].get();
1226 if( !pListInfo
|| !pListInfo
->pNumRule
) break;
1227 SwNumRule
& rMyNumRule
= *pListInfo
->pNumRule
;
1229 // 1.2.1 read specific LVL(s) for this aLST
1231 sal_uInt16 nLvlCount
= static_cast< sal_uInt16
>(pListInfo
->bSimpleList
? nMinLevel
: nMaxLevel
);
1232 pListInfo
->maParaSprms
.resize(nMaxLevel
);
1233 for (sal_uInt16 nLevel
= 0; nLevel
< nLvlCount
; ++nLevel
)
1235 SwNumFormat
aNumFormat( rMyNumRule
.Get( nLevel
) );
1237 bLVLOk
= ReadLVL( aNumFormat
, aItemSet
[nLevel
],
1238 pListInfo
->aIdSty
[nLevel
], true, nLevel
,
1239 pListInfo
->maParaSprms
[nLevel
]);
1242 // and set in rMyNumRule
1243 rMyNumRule
.Set( nLevel
, aNumFormat
);
1248 // 1.2.2 compare ItemPools and CHPx Settings of different Levels
1249 // and create Style(s) if necessary
1251 for (sal_uInt16 nLevel
= 0; nLevel
< nLvlCount
; ++nLevel
)
1254 AdjustLVL( nLevel
, rMyNumRule
, aItemSet
,
1255 pListInfo
->aCharFormat
, bDummy
);
1259 // 2. read and save PLF LFO
1261 bOk
= checkSeek(m_rSt
, m_rFib
.m_fcPlfLfo
);
1266 sal_Int32
nLfoCount(0);
1267 m_rSt
.ReadInt32( nLfoCount
);
1268 bOk
= nLfoCount
> 0;
1275 for (sal_Int32 nLfo
= 0; nLfo
< nLfoCount
; ++nLfo
)
1281 m_rSt
.ReadUInt32( aLFO
.nIdLst
);
1283 m_rSt
.ReadUChar( aLFO
.nLfoLvl
);
1287 // as many Overrides as there are
1288 if ((nMaxLevel
< aLFO
.nLfoLvl
) || m_rSt
.GetError())
1291 // get the Parent NumRule of the current List
1292 WW8LSTInfo
* pParentListInfo
= GetLSTByListId(aLFO
.nIdLst
);
1293 if (pParentListInfo
)
1295 // Save the NumRule in this first step
1296 aLFO
.pNumRule
= pParentListInfo
->pNumRule
;
1298 // are there multiple Levels in the List?
1299 aLFO
.bSimpleList
= pParentListInfo
->bSimpleList
;
1302 std::unique_ptr
<WW8LFOInfo
> pLFOInfo(new WW8LFOInfo(aLFO
));
1303 if (pParentListInfo
)
1305 //Copy the basic paragraph properties for each level from the
1306 //original list into the list format override levels.
1307 int nMaxSize
= pParentListInfo
->maParaSprms
.size();
1308 pLFOInfo
->maParaSprms
.resize(nMaxSize
);
1309 for (int i
= 0; i
< nMaxSize
; ++i
)
1310 pLFOInfo
->maParaSprms
[i
] = pParentListInfo
->maParaSprms
[i
];
1312 m_LFOInfos
.push_back(std::move(pLFOInfo
));
1319 // 2.2 read specific LFOLVL for all LFO
1321 size_t nLFOInfos
= m_LFOInfos
.size();
1322 for (size_t nLfo
= 0; nLfo
< nLFOInfos
; ++nLfo
)
1324 WW8LFOInfo
& rLFOInfo
= *m_LFOInfos
[nLfo
];
1326 if( rLFOInfo
.bOverride
)
1328 WW8LSTInfo
* pParentListInfo
= GetLSTByListId(rLFOInfo
.nIdLst
);
1329 if (!pParentListInfo
)
1332 // 2.2.1 create new NumRule for this List
1334 SwNumRule
* pParentNumRule
= rLFOInfo
.pNumRule
;
1335 OSL_ENSURE(pParentNumRule
, "ww: Impossible lists, please report");
1336 if( !pParentNumRule
)
1338 // create name-prefix for NumRule-Name
1339 // and (if necessary) for Style-Name
1340 const OUString
sPrefix("WW8NumSt" + OUString::number( nLfo
+ 1 ));
1341 // Now assign pNumRule its actual value!!!
1342 // (it contained the parent NumRule up to this point)
1344 // check if a Style is referencing this LFO
1345 if( USHRT_MAX
> m_rReader
.StyleUsingLFO( nLfo
) )
1347 sal_uInt16 nRul
= m_rDoc
.MakeNumRule(
1348 m_rDoc
.GetUniqueNumRuleName( &sPrefix
), pParentNumRule
);
1349 rLFOInfo
.pNumRule
= m_rDoc
.GetNumRuleTable()[ nRul
];
1350 rLFOInfo
.pNumRule
->SetAutoRule(false);
1354 sal_uInt16 nRul
= m_rDoc
.MakeNumRule(
1355 m_rDoc
.GetUniqueNumRuleName(), pParentNumRule
);
1356 rLFOInfo
.pNumRule
= m_rDoc
.GetNumRuleTable()[ nRul
];
1357 rLFOInfo
.pNumRule
->SetAutoRule(true); // = default
1360 // 2.2.2 read all LFOLVL (and LVL) for the new NumRule
1362 WW8aISet aItemSet
; // Character attributes from GrpprlChpx
1363 WW8aCFormat aCharFormat
= {}; // Character Style Pointer
1365 //2.2.2.0 skip inter-group of override header ?
1366 //See #i25438# for why I moved this here, compare
1367 //that original bugdoc's binary to what it looks like
1368 //when resaved with word, i.e. there is always a
1369 //4 byte header, there might be more than one if
1370 //that header was 0xFFFFFFFF, e.g. #114412# ?
1372 m_rSt
.ReadUInt32( nTest
);
1376 m_rSt
.ReadUInt32( nTest
);
1378 while (nTest
== 0xFFFFFFFF);
1381 for (sal_uInt8 nLevel
= 0; nLevel
< rLFOInfo
.nLfoLvl
; ++nLevel
)
1386 // 2.2.2.1 read LFOLVL
1388 m_rSt
.ReadInt32( aLFOLVL
.nStartAt
);
1389 sal_uInt8
aBits1(0);
1390 m_rSt
.ReadUChar( aBits1
);
1392 if (m_rSt
.GetError())
1395 // Note: MS writes the Override-Level-Number into 4 bit.
1396 // We do not! (See comment at "struct WW8LFOInfo")
1397 aLFOLVL
.nLevel
= aBits1
& 0x0F;
1398 if( (0xFF > aBits1
) &&
1399 (nMaxLevel
> aLFOLVL
.nLevel
) )
1402 aLFOLVL
.bStartAt
= true;
1404 aLFOLVL
.bStartAt
= false;
1406 // 2.2.2.2 load dedicated LVL if necessary
1408 SwNumFormat
aNumFormat(
1409 rLFOInfo
.pNumRule
->Get(aLFOLVL
.nLevel
));
1412 aLFOLVL
.bFormat
= true;
1413 // if bStartup is true, replace Startup-Level
1414 // with the LVLF that is saved in the LVL
1415 bLVLOk
= nLevel
< rLFOInfo
.maParaSprms
.size() &&
1416 ReadLVL(aNumFormat
, aItemSet
[nLevel
],
1417 pParentListInfo
->aIdSty
[nLevel
],
1418 aLFOLVL
.bStartAt
, nLevel
,
1419 rLFOInfo
.maParaSprms
[nLevel
]);
1424 else if (aLFOLVL
.bStartAt
)
1426 aNumFormat
.SetStart(
1427 writer_cast
<sal_uInt16
>(aLFOLVL
.nStartAt
));
1430 // 2.2.2.3 Set NumFormat in NumRule
1432 rLFOInfo
.pNumRule
->Set(aLFOLVL
.nLevel
, aNumFormat
);
1436 if (nMaxLevel
> aLFOLVL
.nLevel
)
1437 rLFOInfo
.maOverrides
[aLFOLVL
.nLevel
] = aLFOLVL
;
1442 // 2.2.3 adjust LVL of the new NumRule
1444 bool bNewCharFormatCreated
= false;
1445 for (sal_uInt8 nLevel
= 0; nLevel
< rLFOInfo
.nLfoLvl
; ++nLevel
)
1447 AdjustLVL( nLevel
, *rLFOInfo
.pNumRule
, aItemSet
, aCharFormat
,
1448 bNewCharFormatCreated
, sPrefix
);
1454 m_rSt
.Seek( nOriginalPos
);
1457 void WW8ListManager::ImplDestroy()
1460 named lists remain in document
1461 unused automatic lists are removed from document (DelNumRule)
1463 for(auto & rpInfo
: maLSTInfos
)
1465 if (rpInfo
->pNumRule
&& !rpInfo
->bUsedInDoc
&&
1466 rpInfo
->pNumRule
->IsAutoRule())
1468 m_rDoc
.DelNumRule(rpInfo
->pNumRule
->GetName());
1472 for (auto aIter
= m_LFOInfos
.rbegin(); aIter
!= m_LFOInfos
.rend(); ++aIter
)
1474 if ((*aIter
)->bOverride
1475 && (*aIter
)->pNumRule
1476 && !(*aIter
)->bUsedInDoc
1477 && (*aIter
)->pNumRule
->IsAutoRule())
1479 m_rDoc
.DelNumRule( (*aIter
)->pNumRule
->GetName() );
1484 WW8ListManager::~WW8ListManager()
1486 suppress_fun_call_w_exception(ImplDestroy());
1489 static bool IsEqualFormatting(const SwNumRule
&rOne
, const SwNumRule
&rTwo
)
1493 rOne
.GetRuleType() == rTwo
.GetRuleType() &&
1494 rOne
.IsContinusNum() == rTwo
.IsContinusNum() &&
1495 rOne
.IsAbsSpaces() == rTwo
.IsAbsSpaces() &&
1496 rOne
.GetPoolFormatId() == rTwo
.GetPoolFormatId() &&
1497 rOne
.GetPoolHelpId() == rTwo
.GetPoolHelpId() &&
1498 rOne
.GetPoolHlpFileId() == rTwo
.GetPoolHlpFileId()
1503 for (sal_uInt8 n
= 0; n
< MAXLEVEL
; ++n
)
1505 //The SvxNumberFormat compare, not the SwNumFormat compare
1506 const SvxNumberFormat
&rO
= rOne
.Get(n
);
1507 const SvxNumberFormat
&rT
= rTwo
.Get(n
);
1518 SwNumRule
* WW8ListManager::GetNumRuleForActivation(sal_uInt16 nLFOPosition
,
1519 const sal_uInt8 nLevel
, std::vector
<sal_uInt8
> &rParaSprms
, SwTextNode
*pNode
)
1521 if (m_LFOInfos
.size() <= nLFOPosition
)
1524 WW8LFOInfo
& rLFOInfo
= *m_LFOInfos
[nLFOPosition
];
1526 bool bFirstUse
= !rLFOInfo
.bUsedInDoc
;
1527 rLFOInfo
.bUsedInDoc
= true;
1529 if( !rLFOInfo
.pNumRule
)
1533 // #i100132# - a number format does not have to exist on given list level
1534 SwNumFormat
aFormat(rLFOInfo
.pNumRule
->Get(nLevel
));
1536 if (m_rReader
.IsRightToLeft() && m_nLastLFOPosition
!= nLFOPosition
) {
1537 if ( aFormat
.GetNumAdjust() == SvxAdjust::Right
)
1538 aFormat
.SetNumAdjust(SvxAdjust::Left
);
1539 else if ( aFormat
.GetNumAdjust() == SvxAdjust::Left
)
1540 aFormat
.SetNumAdjust(SvxAdjust::Right
);
1541 rLFOInfo
.pNumRule
->Set(nLevel
, aFormat
);
1543 m_nLastLFOPosition
= nLFOPosition
;
1546 If this list has had its bits set in word 2000 to pretend that it is a
1547 simple list from the point of view of the user, then it is almost
1548 certainly a simple continuous list, and we will try to keep it like that.
1549 Otherwise when we save again it will be shown as the true outline list
1550 that it is, confusing the user that just wanted what they thought was a
1551 simple list. On the other hand it is possible that some of the other levels
1552 were used by the user, in which case we will not pretend anymore that it
1553 is a simple list. Something that word 2000 does anyway, that 97 didn't, to
1556 if (nLevel
&& rLFOInfo
.pNumRule
->IsContinusNum())
1557 rLFOInfo
.pNumRule
->SetContinusNum(false);
1559 if( (!rLFOInfo
.bOverride
) && (!rLFOInfo
.bLSTbUIDSet
) )
1561 WW8LSTInfo
* pParentListInfo
= GetLSTByListId( rLFOInfo
.nIdLst
);
1562 if( pParentListInfo
)
1563 pParentListInfo
->bUsedInDoc
= true;
1564 rLFOInfo
.bLSTbUIDSet
= true;
1567 if (rLFOInfo
.maParaSprms
.size() > nLevel
)
1568 rParaSprms
= rLFOInfo
.maParaSprms
[nLevel
];
1570 SwNumRule
*pRet
= rLFOInfo
.pNumRule
;
1572 bool bRestart(false);
1573 sal_uInt16
nStart(0);
1574 bool bNewstart(false);
1576 Note: If you fiddle with this then you have to make sure that #i18322#
1577 #i13833#, #i20095# and #112466# continue to work
1579 Check if there were overrides for this level
1581 if (rLFOInfo
.bOverride
&& nLevel
< rLFOInfo
.nLfoLvl
)
1583 WW8LSTInfo
* pParentListInfo
= GetLSTByListId(rLFOInfo
.nIdLst
);
1584 OSL_ENSURE(pParentListInfo
, "ww: Impossible lists, please report");
1585 if (pParentListInfo
&& pParentListInfo
->pNumRule
)
1587 const WW8LFOLVL
&rOverride
= rLFOInfo
.maOverrides
[nLevel
];
1588 bool bNoChangeFromParent
=
1589 IsEqualFormatting(*pRet
, *(pParentListInfo
->pNumRule
));
1591 //If so then I think word still uses the parent (maybe)
1592 if (bNoChangeFromParent
)
1594 pRet
= pParentListInfo
->pNumRule
;
1596 //did it not affect start at value ?
1597 if (bFirstUse
&& rOverride
.bStartAt
)
1599 const SwNumFormat
&rFormat
=
1600 pParentListInfo
->pNumRule
->Get(nLevel
);
1602 rFormat
.GetStart() ==
1603 rLFOInfo
.maOverrides
[nLevel
].nStartAt
1611 nStart
= writer_cast
<sal_uInt16
>
1612 (rLFOInfo
.maOverrides
[nLevel
].nStartAt
);
1616 pParentListInfo
->bUsedInDoc
= true;
1623 pNode
->SetAttrListLevel(nLevel
);
1625 if (bRestart
|| bNewstart
)
1626 pNode
->SetListRestart(true);
1628 pNode
->SetAttrListRestartValue(nStart
);
1633 // SwWW8ImplReader: append a List to a Style or Paragraph
1635 bool SwWW8ImplReader::SetTextFormatCollAndListLevel(const SwPaM
& rRg
,
1636 SwWW8StyInf
& rStyleInfo
)
1639 if( rStyleInfo
.m_pFormat
&& rStyleInfo
.m_bColl
)
1641 bRes
= m_rDoc
.SetTextFormatColl(rRg
, static_cast<SwTextFormatColl
*>(rStyleInfo
.m_pFormat
));
1642 SwTextNode
* pTextNode
= m_pPaM
->GetPointNode().GetTextNode();
1643 OSL_ENSURE( pTextNode
, "No Text-Node at PaM-Position" );
1650 const SwNumRule
* pNumRule
= pTextNode
->GetNumRule(); // #i27610#
1652 if( !IsInvalidOrToBeMergedTabCell() &&
1653 ! (pNumRule
&& pNumRule
->IsOutlineRule()) ) // #i27610#
1655 pTextNode
->ResetAttr( RES_PARATR_NUMRULE
);
1658 if (USHRT_MAX
> rStyleInfo
.m_nLFOIndex
&& WW8ListManager::nMaxLevel
1659 > rStyleInfo
.m_nListLevel
)
1661 const bool bApplyListStyle
= false;
1662 RegisterNumFormatOnTextNode(rStyleInfo
.m_nLFOIndex
, rStyleInfo
.m_nListLevel
,
1669 void UseListIndent(SwWW8StyInf
&rStyle
, const SwNumFormat
&rFormat
)
1672 if ( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
)
1674 const auto nAbsLSpace
= rFormat
.GetAbsLSpace();
1675 const tools::Long nListFirstLineIndent
= GetListFirstLineIndent(rFormat
);
1676 SvxFirstLineIndentItem
firstLine(rStyle
.m_pFormat
->GetFormatAttr(RES_MARGIN_FIRSTLINE
));
1677 SvxTextLeftMarginItem
leftMargin(rStyle
.m_pFormat
->GetFormatAttr(RES_MARGIN_TEXTLEFT
));
1678 leftMargin
.SetTextLeft(nAbsLSpace
);
1679 firstLine
.SetTextFirstLineOffset(writer_cast
<short>(nListFirstLineIndent
));
1680 rStyle
.m_pFormat
->SetFormatAttr(firstLine
);
1681 rStyle
.m_pFormat
->SetFormatAttr(leftMargin
);
1682 rStyle
.m_bListRelevantIndentSet
= true;
1686 void SetStyleIndent(SwWW8StyInf
&rStyle
, const SwNumFormat
&rFormat
)
1688 if ( rFormat
.GetPositionAndSpaceMode() != SvxNumberFormat::LABEL_WIDTH_AND_POSITION
) // #i86652#
1691 SvxFirstLineIndentItem
firstLine(rStyle
.m_pFormat
->GetFormatAttr(RES_MARGIN_FIRSTLINE
));
1692 SvxTextLeftMarginItem
leftMargin(rStyle
.m_pFormat
->GetFormatAttr(RES_MARGIN_TEXTLEFT
));
1693 if (rStyle
.m_bListRelevantIndentSet
)
1696 SyncIndentWithList(firstLine
, leftMargin
, rFormat
, false, false); // #i103711#, #i105414#
1700 leftMargin
.SetTextLeft(0);
1701 firstLine
.SetTextFirstLineOffset(0);
1703 rStyle
.m_pFormat
->SetFormatAttr(firstLine
);
1704 rStyle
.m_pFormat
->SetFormatAttr(leftMargin
);
1707 void SwWW8ImplReader::SetStylesList(sal_uInt16 nStyle
, sal_uInt16 nCurrentLFO
,
1708 sal_uInt8 nCurrentLevel
)
1710 if (nStyle
>= m_vColl
.size())
1713 SwWW8StyInf
&rStyleInf
= m_vColl
[nStyle
];
1714 if (!rStyleInf
.m_bValid
)
1717 OSL_ENSURE(m_pCurrentColl
, "Cannot be called outside of style import");
1718 // Phase 1: Numbering attributes when reading a StyleDef
1719 if( !m_pCurrentColl
)
1722 if (nCurrentLFO
< USHRT_MAX
)
1723 rStyleInf
.m_nLFOIndex
= nCurrentLFO
;
1724 if (nCurrentLevel
< MAXLEVEL
)
1725 rStyleInf
.m_nListLevel
= nCurrentLevel
;
1727 // only save the Parameters for now. The actual List will be appended
1728 // at a later point, when the Listdefinitions is read...
1729 if (rStyleInf
.m_nLFOIndex
< USHRT_MAX
&& rStyleInf
.m_nListLevel
< WW8ListManager::nMaxLevel
)
1731 std::vector
<sal_uInt8
> aParaSprms
;
1732 SwNumRule
* pNmRule
= m_xLstManager
->GetNumRuleForActivation(
1733 rStyleInf
.m_nLFOIndex
, rStyleInf
.m_nListLevel
, aParaSprms
);
1735 UseListIndent(rStyleInf
, pNmRule
->Get(rStyleInf
.m_nListLevel
));
1739 void SwWW8ImplReader::RegisterNumFormatOnStyle(sal_uInt16 nStyle
)
1742 if (nStyle
>= m_vColl
.size())
1745 SwWW8StyInf
&rStyleInf
= m_vColl
[nStyle
];
1746 if (!(rStyleInf
.m_bValid
&& rStyleInf
.m_pFormat
))
1749 //Save old pre-list modified indent, which are the word indent values
1750 rStyleInf
.m_pWordFirstLine
.reset(rStyleInf
.m_pFormat
->GetFormatAttr(RES_MARGIN_FIRSTLINE
).Clone());
1751 rStyleInf
.m_pWordLeftMargin
.reset(rStyleInf
.m_pFormat
->GetFormatAttr(RES_MARGIN_TEXTLEFT
).Clone());
1752 rStyleInf
.m_pWordRightMargin
.reset(rStyleInf
.m_pFormat
->GetFormatAttr(RES_MARGIN_RIGHT
).Clone());
1754 // Phase 2: refresh StyleDef after reading all Lists
1755 if (rStyleInf
.m_nLFOIndex
>= USHRT_MAX
|| rStyleInf
.m_nListLevel
>= WW8ListManager::nMaxLevel
)
1758 std::vector
<sal_uInt8
> aParaSprms
;
1759 SwNumRule
* pNmRule
= m_xLstManager
->GetNumRuleForActivation(
1760 rStyleInf
.m_nLFOIndex
, rStyleInf
.m_nListLevel
, aParaSprms
);
1762 if (pNmRule
!= nullptr)
1764 if (rStyleInf
.IsWW8BuiltInHeadingStyle()
1765 && rStyleInf
.HasWW8OutlineLevel())
1767 rStyleInf
.m_pOutlineNumrule
= pNmRule
;
1771 rStyleInf
.m_pFormat
->SetFormatAttr(
1772 SwNumRuleItem(pNmRule
->GetName()));
1773 rStyleInf
.m_bHasStyNumRule
= true;
1776 SetStyleIndent(rStyleInf
, pNmRule
->Get(rStyleInf
.m_nListLevel
));
1780 void SwWW8ImplReader::RegisterNumFormatOnTextNode(sal_uInt16 nCurrentLFO
,
1781 sal_uInt8 nCurrentLevel
,
1782 const bool bSetAttr
)
1784 // Note: the method appends NumRule to the Text Node if
1785 // bSetAttr (of course the lists have to be read before)
1786 // and only sets the Level. It does not check if there is a NumRule
1787 // attached to the STYLE !!!
1789 if (!m_xLstManager
) // are all list declarations read?
1792 SwTextNode
* pTextNd
= m_pPaM
->GetPointNode().GetTextNode();
1793 OSL_ENSURE(pTextNd
, "No Text-Node at PaM-Position");
1797 // WW8ListManager::nMaxLevel indicates body text, cancelling an inherited numbering.
1798 if (nCurrentLFO
< USHRT_MAX
&& nCurrentLevel
== WW8ListManager::nMaxLevel
)
1800 pTextNd
->SetAttr(SwNumRuleItem(OUString()));
1804 // Undefined listLevel is treated as the first level with valid numbering rule.
1805 // TODO:This doesn't allow for inheriting from a style(HOW?), but it matches previous behaviour.
1806 if (nCurrentLFO
< USHRT_MAX
&& nCurrentLevel
== MAXLEVEL
)
1809 std::vector
<sal_uInt8
> aParaSprms
;
1810 const SwNumRule
* pRule
= bSetAttr
?
1811 m_xLstManager
->GetNumRuleForActivation( nCurrentLFO
, nCurrentLevel
,
1812 aParaSprms
, pTextNd
) : nullptr;
1814 if (pRule
== nullptr && bSetAttr
)
1817 if (bSetAttr
&& pTextNd
->GetNumRule() != pRule
1818 && (pTextNd
->GetNumRule() != m_rDoc
.GetOutlineNumRule()
1819 || pRule
!= m_pChosenWW8OutlineStyle
))
1821 // Now this is either not a part of Chapter Numbering,
1822 // or else it is using a different numRule than the one copied to Chapter Numbering.
1823 OUString sName
= pRule
== m_pChosenWW8OutlineStyle
? m_rDoc
.GetOutlineNumRule()->GetName()
1825 pTextNd
->SetAttr(SwNumRuleItem(sName
));
1827 pTextNd
->SetAttrListLevel(nCurrentLevel
);
1829 // <IsCounted()> state of text node has to be adjusted accordingly.
1830 if ( /*nCurrentLevel >= 0 &&*/ nCurrentLevel
< MAXLEVEL
)
1832 pTextNd
->SetCountedInList( true );
1836 // Direct application of the list level formatting no longer
1837 // needed for list levels of mode LABEL_ALIGNMENT
1838 bool bApplyListLevelIndentDirectlyAtPara(true);
1840 if (pTextNd
->GetNumRule() && nCurrentLevel
< MAXLEVEL
)
1842 const SwNumFormat
& rFormat
= pTextNd
->GetNumRule()->Get(nCurrentLevel
);
1843 if (rFormat
.GetPositionAndSpaceMode()
1844 == SvxNumberFormat::LABEL_ALIGNMENT
)
1846 bApplyListLevelIndentDirectlyAtPara
= false;
1851 if (!bApplyListLevelIndentDirectlyAtPara
)
1854 auto pListIndent
= std::make_unique
<SfxItemSet
>(m_rDoc
.GetAttrPool(), svl::Items
<RES_MARGIN_FIRSTLINE
, RES_MARGIN_TEXTLEFT
>);
1855 const SfxPoolItem
*pItem
;
1856 pItem
= GetFormatAttr(RES_MARGIN_FIRSTLINE
);
1857 OSL_ENSURE(pItem
, "impossible");
1859 pListIndent
->Put(*pItem
);
1860 pItem
= GetFormatAttr(RES_MARGIN_TEXTLEFT
);
1862 pListIndent
->Put(*pItem
);
1865 Take the original paragraph sprms attached to this list level
1866 formatting and apply them to the paragraph. I'm convinced that
1867 this is exactly what word does.
1869 if (short nLen
= static_cast< short >(aParaSprms
.size()))
1871 std::unique_ptr
<SfxItemSet
> pOldCurrentItemSet(SetCurrentItemSet(std::move(pListIndent
)));
1873 sal_uInt8
* pSprms1
= aParaSprms
.data();
1876 sal_uInt16 nL1
= ImportSprm(pSprms1
, nLen
);
1881 pListIndent
= SetCurrentItemSet(std::move(pOldCurrentItemSet
));
1884 if (const SvxFirstLineIndentItem
*const pFirstLine
= pListIndent
->GetItem
<SvxFirstLineIndentItem
>(RES_MARGIN_FIRSTLINE
))
1886 m_xCtrlStck
->NewAttr(*m_pPaM
->GetPoint(), *pFirstLine
);
1887 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_MARGIN_FIRSTLINE
);
1889 if (const SvxTextLeftMarginItem
*const pLeftMargin
= pListIndent
->GetItem
<SvxTextLeftMarginItem
>(RES_MARGIN_TEXTLEFT
))
1891 m_xCtrlStck
->NewAttr(*m_pPaM
->GetPoint(), *pLeftMargin
);
1892 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_MARGIN_TEXTLEFT
);
1896 void SwWW8ImplReader::RegisterNumFormat(sal_uInt16 nCurrentLFO
, sal_uInt8 nCurrentLevel
)
1898 // Are we reading the StyleDef ?
1900 SetStylesList( m_nCurrentColl
, nCurrentLFO
, nCurrentLevel
);
1902 RegisterNumFormatOnTextNode(nCurrentLFO
, nCurrentLevel
);
1905 void SwWW8ImplReader::Read_ListLevel(sal_uInt16
, const sal_uInt8
* pData
,
1908 if (m_xPlcxMan
&& m_xPlcxMan
->GetDoingDrawTextBox())
1913 // the current level is finished, what should we do ?
1914 m_nListLevel
= MAXLEVEL
;
1915 if (m_xStyles
&& !m_bVer67
)
1916 m_xStyles
->mnWwNumLevel
= 0;
1924 // the Streamdata is zero based
1925 m_nListLevel
= *pData
;
1927 if (m_xStyles
&& !m_bVer67
)
1930 if this is the case, then if the numbering is actually stored in
1931 winword 6 format, and its likely that sprmPIlvl has been abused
1932 to set the ww6 list level information which we will need when we
1933 reach the true ww6 list def. So set it now
1935 m_xStyles
->mnWwNumLevel
= m_nListLevel
;
1938 // Treat an invalid level as body-level
1939 if (WW8ListManager::nMaxLevel
< m_nListLevel
)
1940 m_nListLevel
= WW8ListManager::nMaxLevel
;
1942 RegisterNumFormat(m_nLFOPosition
, m_nListLevel
);
1943 if (USHRT_MAX
> m_nLFOPosition
)
1945 assert(false && "m_nLFOPosition is usually reset immediately, so we rarely ever get here.");
1946 m_nLFOPosition
= USHRT_MAX
;
1947 m_nListLevel
= MAXLEVEL
;
1952 void SwWW8ImplReader::Read_LFOPosition(sal_uInt16
, const sal_uInt8
* pData
,
1955 if (m_xPlcxMan
&& m_xPlcxMan
->GetDoingDrawTextBox())
1960 // the current level is finished, what should we do ?
1961 m_nLFOPosition
= USHRT_MAX
;
1962 m_nListLevel
= MAXLEVEL
;
1970 short nData
= SVBT16ToUInt16( pData
);
1973 // disable the numbering/list style apply to the paragraph or the style
1976 If you have a paragraph in word with left and/or hanging indent
1977 and remove its numbering, then the indentation appears to get
1978 reset, but not back to the base style, instead it goes to a blank
1980 Unless it's a broken ww6 list in 97 in which case more hackery is
1981 required, some more details about broken ww6 list in
1982 ww8par6.cxx#SwWW8ImplReader::Read_LR
1987 // here a "named" style is being configured
1989 // disable the numbering/list in the style currently configured
1990 m_pCurrentColl
->SetFormatAttr(*GetDfltAttr(RES_PARATR_NUMRULE
));
1992 // reset/blank the indent
1993 m_pCurrentColl
->SetFormatAttr(SvxFirstLineIndentItem(RES_MARGIN_FIRSTLINE
));
1994 m_pCurrentColl
->SetFormatAttr(SvxTextLeftMarginItem(RES_MARGIN_TEXTLEFT
));
1995 m_pCurrentColl
->SetFormatAttr(SvxRightMarginItem(RES_MARGIN_RIGHT
));
1997 // These sprmPIlfos are supposed to indicate "cancel" numbering.
1998 // Since m_nLFOPosition is "data - 1", then zero becomes USHRT_MAX
1999 // which is no good since that indicates "unspecified, available for inheritance".
2000 // So instead use USHRT_MAX-1 for indicating an explicit "cancel numbering".
2001 RegisterNumFormat(USHRT_MAX
-1, MAXLEVEL
);
2003 else if (SwTextNode
* pTextNode
= m_pPaM
->GetPointNode().GetTextNode())
2005 // here a paragraph is being directly formatted
2007 // empty the numbering/list style applied to the current paragraph
2008 SwNumRuleItem aEmptyRule
;
2009 pTextNode
->SetAttr( aEmptyRule
);
2011 // create an empty SvxLRSpaceItem
2012 std::shared_ptr
<SvxFirstLineIndentItem
> pFirstLine(std::make_shared
<SvxFirstLineIndentItem
>(RES_MARGIN_FIRSTLINE
));
2014 // replace it with the one of the current node if it exist
2015 const SfxPoolItem
*const pItem
= GetFormatAttr(RES_MARGIN_FIRSTLINE
);
2018 pFirstLine
.reset(static_cast<SvxFirstLineIndentItem
*>(pItem
->Clone()));
2021 // reset/blank the left indent (and only the left)
2022 pFirstLine
->SetTextFirstLineOffset(0);
2023 SvxTextLeftMarginItem
leftMargin(0, RES_MARGIN_TEXTLEFT
);
2025 // apply the modified SvxLRSpaceItem to the current paragraph
2026 pTextNode
->SetAttr(*pFirstLine
);
2027 pTextNode
->SetAttr(leftMargin
);
2030 m_nLFOPosition
= USHRT_MAX
;
2032 else // nData in (0..0x7FFF]
2034 m_nLFOPosition
= o3tl::narrowing
<sal_uInt16
>(nData
)-1; // m_nLFOPosition in [0..0x7FFF)
2036 If we are a ww8+ style with ww7- style lists then there is a
2037 bizarre broken word bug where when the list is removed from a para
2038 the ww6 list first line indent still affects the first line
2039 indentation. Setting this flag will allow us to recover from this
2042 if (m_pCurrentColl
&& (m_nLFOPosition
== 2047-1) && m_nCurrentColl
< m_vColl
.size())
2043 m_vColl
[m_nCurrentColl
].m_bHasBrokenWW6List
= true;
2045 // here the stream data is 1-based, we subtract ONE
2046 if (m_nLFOPosition
!= 2047-1) //Normal ww8+ list behaviour
2048 RegisterNumFormat(m_nLFOPosition
, m_nListLevel
);
2049 m_nLFOPosition
= USHRT_MAX
;
2050 m_nListLevel
= MAXLEVEL
;
2052 else if (m_xPlcxMan
&& m_xPlcxMan
->HasParaSprm(NS_sprm::LN_PAnld
).pSprm
)
2055 #i8114# Horrific backwards compatible ww7- lists in ww8+
2058 m_nListLevel
= std::min
<sal_uInt8
>(WW8ListManager::nMaxLevel
, m_nListLevel
);
2059 Read_ANLevelNo(13 /*equiv ww7- sprm no*/, &m_nListLevel
, 1);
2067 bool SwWW8ImplReader::ImportFormulaControl(WW8FormulaControl
&aFormula
,
2068 WW8_CP nStart
, SwWw8ControlType nWhich
)
2072 * Save the reader state and process the sprms for this anchor cp.
2073 * Doing so will set the nPicLocFc to the offset to find the hypertext
2074 * data in the data stream.
2076 WW8_CP nEndCp
= nStart
+1; //Only interested in the single 0x01 character
2078 WW8ReaderSave
aSave(this,nStart
);
2080 WW8PLCFManResult aRes
;
2081 nStart
= m_xPlcxMan
->Where();
2082 while(nStart
<= nEndCp
)
2084 if ( m_xPlcxMan
->Get(&aRes
)
2085 && aRes
.pMemPos
&& aRes
.nSprmId
)
2087 //only interested in sprms which would set nPicLocFc
2088 if ( (68 == aRes
.nSprmId
) || (0x6A03 == aRes
.nSprmId
) )
2090 Read_PicLoc( aRes
.nSprmId
, aRes
.pMemPos
+
2091 m_oSprmParser
->DistanceToData(aRes
.nSprmId
), 4);
2095 m_xPlcxMan
->advance();
2096 nStart
= m_xPlcxMan
->Where();
2098 sal_uLong nOffset
= m_nPicLocFc
;
2099 aSave
.Restore(this);
2101 sal_uInt64 nOldPos
= m_pDataStream
->Tell();
2103 bool bValid
= checkSeek(*m_pDataStream
, nOffset
) &&
2104 PicRead(m_pDataStream
, &aPic
, m_bVer67
);
2106 if (bValid
&& aPic
.lcb
> 0x3A)
2108 aFormula
.FormulaRead(nWhich
,m_pDataStream
);
2113 There is a problem with aPic, the WW8_PIC is always used even though it
2114 is too big for the WW95 files, it needs to be modified to check the
2117 m_pDataStream
->Seek( nOldPos
);
2121 void SwMSConvertControls::InsertFormula(WW8FormulaControl
&rFormula
)
2123 const uno::Reference
< lang::XMultiServiceFactory
> & rServiceFactory
=
2124 GetServiceFactory();
2126 if(!rServiceFactory
.is())
2130 uno::Reference
< form::XFormComponent
> xFComp
;
2132 if (rFormula
.Import(rServiceFactory
, xFComp
, aSz
))
2134 uno::Reference
<drawing::XShape
> xShapeRef
;
2135 if (InsertControl(xFComp
, aSz
, &xShapeRef
, false))
2136 GetShapes()->add(xShapeRef
);
2140 void WW8FormulaControl::FormulaRead(SwWw8ControlType nWhich
,
2141 SvStream
*pDataStream
)
2145 // The following is a FFData structure as described in
2146 // Microsoft's DOC specification (chapter 2.9.78)
2147 sal_uInt32 nVersion
= 0;
2148 pDataStream
->ReadUInt32(nVersion
);
2149 // An unsigned integer that MUST be 0xFFFFFFFF
2150 if (nVersion
!= 0xFFFFFFFF)
2152 SAL_WARN("sw.ww8", "Parsing error: invalid header for FFData");
2156 // might be better to read the bits as a 16 bit word
2157 // ( like it is in the spec. )
2158 sal_uInt8 bits1
= 0;
2159 pDataStream
->ReadUChar( bits1
);
2160 sal_uInt8 bits2
= 0;
2161 pDataStream
->ReadUChar( bits2
);
2163 sal_uInt8 iType
= ( bits1
& 0x3 );
2165 // we should verify that bits.iType & nWhich concur
2166 OSL_ENSURE( iType
== nWhich
, "something wrong, expect control type read from stream doesn't match nWhich passed in");
2167 if ( iType
!= nWhich
)
2170 sal_uInt8 iRes
= (bits1
& 0x7C) >> 2;
2172 pDataStream
->ReadUInt16( mnMaxLen
);
2175 pDataStream
->ReadUInt16( hps
);
2178 msTitle
= read_uInt16_BeltAndBracesString(*pDataStream
);
2180 if (nWhich
== WW8_CT_EDIT
)
2181 { // Field is a textbox
2184 msDefault
= read_uInt16_BeltAndBracesString(*pDataStream
);
2188 // CheckBox or ComboBox
2189 sal_uInt16 wDef
= 0;
2190 pDataStream
->ReadUInt16( wDef
);
2191 mnChecked
= wDef
; // default
2192 if (nWhich
== WW8_CT_CHECKBOX
)
2196 msDefault
= ( wDef
== 0 ) ? std::u16string_view( u
"0" ) : std::u16string_view( u
"1" );
2200 msFormatting
= read_uInt16_BeltAndBracesString(*pDataStream
);
2202 msHelp
= read_uInt16_BeltAndBracesString(*pDataStream
);
2204 msToolTip
= read_uInt16_BeltAndBracesString(*pDataStream
);
2207 msEntryMcr
= read_uInt16_BeltAndBracesString(*pDataStream
);
2209 msExitMcr
= read_uInt16_BeltAndBracesString(*pDataStream
);
2211 if (nWhich
== WW8_CT_DROPDOWN
)
2214 // SSTB (see Spec. 2.2.4)
2215 sal_uInt16 fExtend
= 0;
2216 pDataStream
->ReadUInt16( fExtend
);
2217 sal_uInt16 nStringsCnt
= 0;
2219 // Isn't it that if fExtend isn't 0xFFFF then fExtend actually
2220 // doesn't exist and we really have just read nStringsCnt ( or cData )?
2221 if (fExtend
!= 0xFFFF)
2223 pDataStream
->ReadUInt16( nStringsCnt
);
2225 // I guess this should be zero ( and we should ensure that )
2226 sal_uInt16 cbExtra
= 0;
2227 pDataStream
->ReadUInt16( cbExtra
);
2229 OSL_ENSURE(bAllOk
, "Unknown formfield dropdown list structure");
2230 if (!bAllOk
) //Not as expected, don't risk it at all.
2232 const size_t nMinRecordSize
= sizeof(sal_uInt16
);
2233 const size_t nMaxRecords
= pDataStream
->remainingSize() / nMinRecordSize
;
2234 if (nStringsCnt
> nMaxRecords
)
2236 SAL_WARN("sw.ww8", "Parsing error: " << nMaxRecords
<<
2237 " max possible entries, but " << nStringsCnt
<< " claimed, truncating");
2238 nStringsCnt
= nMaxRecords
;
2240 maListEntries
.reserve(nStringsCnt
);
2241 for (sal_uInt32 nI
= 0; nI
< nStringsCnt
; ++nI
)
2243 OUString sEntry
= read_uInt16_PascalString(*pDataStream
);
2244 maListEntries
.push_back(sEntry
);
2247 mfDropdownIndex
= iRes
;
2249 mbHelp
= bits1
& 0x80;
2252 mfToolTip
= nField
& 0x01;
2253 mfNoMark
= (nField
& 0x02)>>1;
2254 mfType
= (nField
& 0x38)>>3;
2255 mfUnused
= (nField
& 0xE0)>>5;
2258 WW8FormulaListBox::WW8FormulaListBox(SwWW8ImplReader
&rR
)
2259 : WW8FormulaControl(SL::aListBox
, rR
)
2263 //Miserable hack to get a hardcoded guesstimate of the size of a list dropdown
2264 //box's first entry to set as the lists default size
2265 awt::Size
SwWW8ImplReader::MiserableDropDownFormHack(const OUString
&rString
,
2266 uno::Reference
<beans::XPropertySet
> const & rPropSet
)
2269 struct CtrlFontMapEntry
2271 sal_uInt16 nWhichId
;
2272 const char* pPropNm
;
2274 const CtrlFontMapEntry aMapTable
[] =
2276 { RES_CHRATR_COLOR
, "TextColor" },
2277 { RES_CHRATR_FONT
, "FontName" },
2278 { RES_CHRATR_FONTSIZE
, "FontHeight" },
2279 { RES_CHRATR_WEIGHT
, "FontWeight" },
2280 { RES_CHRATR_UNDERLINE
, "FontUnderline" },
2281 { RES_CHRATR_CROSSEDOUT
, "FontStrikeout" },
2282 { RES_CHRATR_POSTURE
, "FontSlant" },
2287 uno::Reference
< beans::XPropertySetInfo
> xPropSetInfo
=
2288 rPropSet
->getPropertySetInfo();
2291 for (const CtrlFontMapEntry
* pMap
= aMapTable
; pMap
->nWhichId
; ++pMap
)
2294 const SfxPoolItem
* pItem
= GetFormatAttr( pMap
->nWhichId
);
2295 OSL_ENSURE(pItem
, "Impossible");
2299 switch ( pMap
->nWhichId
)
2301 case RES_CHRATR_COLOR
:
2304 if (xPropSetInfo
->hasPropertyByName(aNm
= "TextColor"))
2306 aTmp
<<= static_cast<sal_Int32
>(static_cast<const SvxColorItem
*>(pItem
)->GetValue());
2307 rPropSet
->setPropertyValue(aNm
, aTmp
);
2310 aFont
.SetColor(static_cast<const SvxColorItem
*>(pItem
)->GetValue());
2312 case RES_CHRATR_FONT
:
2314 const SvxFontItem
*pFontItem
= static_cast<const SvxFontItem
*>(pItem
);
2316 if (xPropSetInfo
->hasPropertyByName(aNm
= "FontStyleName"))
2318 aTmp
<<= pFontItem
->GetStyleName();
2319 rPropSet
->setPropertyValue( aNm
, aTmp
);
2321 if (xPropSetInfo
->hasPropertyByName(aNm
= "FontFamily"))
2323 aTmp
<<= static_cast<sal_Int16
>(pFontItem
->GetFamily());
2324 rPropSet
->setPropertyValue( aNm
, aTmp
);
2326 if (xPropSetInfo
->hasPropertyByName(aNm
= "FontCharset"))
2328 aTmp
<<= static_cast<sal_Int16
>(pFontItem
->GetCharSet());
2329 rPropSet
->setPropertyValue( aNm
, aTmp
);
2331 if (xPropSetInfo
->hasPropertyByName(aNm
= "FontPitch"))
2333 aTmp
<<= static_cast<sal_Int16
>(pFontItem
->GetPitch());
2334 rPropSet
->setPropertyValue( aNm
, aTmp
);
2337 aTmp
<<= pFontItem
->GetFamilyName();
2338 aFont
.SetFamilyName( pFontItem
->GetFamilyName() );
2339 aFont
.SetStyleName( pFontItem
->GetStyleName() );
2340 aFont
.SetFamily( pFontItem
->GetFamily() );
2341 aFont
.SetCharSet( pFontItem
->GetCharSet() );
2342 aFont
.SetPitch( pFontItem
->GetPitch() );
2346 case RES_CHRATR_FONTSIZE
:
2348 Size
aSize( aFont
.GetFontSize().Width(),
2349 static_cast<const SvxFontHeightItem
*>(pItem
)->GetHeight() );
2350 aTmp
<<= static_cast<float>(aSize
.Height()) / 20.0;
2352 aFont
.SetFontSize(o3tl::convert(aSize
, o3tl::Length::twip
, o3tl::Length::mm100
));
2356 case RES_CHRATR_WEIGHT
:
2357 aTmp
<<= vcl::unohelper::ConvertFontWeight(
2358 static_cast<const SvxWeightItem
*>(pItem
)->GetWeight() );
2359 aFont
.SetWeight( static_cast<const SvxWeightItem
*>(pItem
)->GetWeight() );
2362 case RES_CHRATR_UNDERLINE
:
2363 aTmp
<<= static_cast<sal_Int16
>(static_cast<const SvxUnderlineItem
*>(pItem
)->GetLineStyle());
2364 aFont
.SetUnderline(static_cast<const SvxUnderlineItem
*>(pItem
)->GetLineStyle());
2367 case RES_CHRATR_CROSSEDOUT
:
2368 aTmp
<<= static_cast<sal_Int16
>( static_cast<const SvxCrossedOutItem
*>(pItem
)->GetStrikeout() );
2369 aFont
.SetStrikeout( static_cast<const SvxCrossedOutItem
*>(pItem
)->GetStrikeout() );
2372 case RES_CHRATR_POSTURE
:
2373 aTmp
<<= static_cast<sal_Int16
>( static_cast<const SvxPostureItem
*>(pItem
)->GetPosture() );
2374 aFont
.SetItalic( static_cast<const SvxPostureItem
*>(pItem
)->GetPosture() );
2382 if (bSet
&& xPropSetInfo
->hasPropertyByName(OUString::createFromAscii(pMap
->pPropNm
)))
2383 rPropSet
->setPropertyValue(OUString::createFromAscii(pMap
->pPropNm
), aTmp
);
2385 // now calculate the size of the control
2386 OutputDevice
* pOut
= Application::GetDefaultDevice();
2387 OSL_ENSURE(pOut
, "Impossible");
2390 pOut
->Push( vcl::PushFlags::FONT
| vcl::PushFlags::MAPMODE
);
2391 pOut
->SetMapMode( MapMode( MapUnit::Map100thMM
));
2392 pOut
->SetFont( aFont
);
2393 aRet
.Width
= pOut
->GetTextWidth(rString
);
2394 aRet
.Width
+= 500; //plus size of button, total hack territory
2395 aRet
.Height
= pOut
->GetTextHeight();
2401 bool WW8FormulaListBox::Import(const uno::Reference
<
2402 lang::XMultiServiceFactory
> &rServiceFactory
,
2403 uno::Reference
<form::XFormComponent
> &rFComp
,awt::Size
&rSz
)
2405 uno::Reference
<uno::XInterface
> xCreate
= rServiceFactory
->createInstance("com.sun.star.form.component.ComboBox");
2409 rFComp
.set(xCreate
, uno::UNO_QUERY
);
2413 uno::Reference
<beans::XPropertySet
> xPropSet(xCreate
, uno::UNO_QUERY
);
2416 if (!msTitle
.isEmpty())
2420 xPropSet
->setPropertyValue("Name", aTmp
);
2422 if (!msToolTip
.isEmpty())
2425 xPropSet
->setPropertyValue("HelpText", aTmp
);
2428 xPropSet
->setPropertyValue("Dropdown", css::uno::Any(true));
2430 if (!maListEntries
.empty())
2432 sal_uInt32 nLen
= maListEntries
.size();
2433 uno::Sequence
< OUString
> aListSource(nLen
);
2434 auto aListSourceRange
= asNonConstRange(aListSource
);
2435 for (sal_uInt32 nI
= 0; nI
< nLen
; ++nI
)
2436 aListSourceRange
[nI
] = maListEntries
[nI
];
2437 aTmp
<<= aListSource
;
2438 xPropSet
->setPropertyValue("StringItemList", aTmp
);
2440 if (mfDropdownIndex
< nLen
)
2442 aTmp
<<= aListSource
[mfDropdownIndex
];
2446 aTmp
<<= aListSource
[0];
2449 xPropSet
->setPropertyValue("DefaultText", aTmp
);
2451 rSz
= mrRdr
.MiserableDropDownFormHack(maListEntries
[0], xPropSet
);
2455 static constexpr OUStringLiteral aBlank
=
2456 u
"\u2002\u2002\u2002\u2002\u2002";
2457 rSz
= mrRdr
.MiserableDropDownFormHack(aBlank
, xPropSet
);
2463 WW8FormulaCheckBox::WW8FormulaCheckBox(SwWW8ImplReader
&rR
)
2464 : WW8FormulaControl(SL::aCheckBox
, rR
)
2468 static void lcl_AddToPropertyContainer
2469 (uno::Reference
<beans::XPropertySet
> const & xPropSet
,
2470 const OUString
& rPropertyName
, const OUString
& rValue
)
2472 uno::Reference
<beans::XPropertySetInfo
> xPropSetInfo
=
2473 xPropSet
->getPropertySetInfo();
2474 if (xPropSetInfo
.is() &&
2475 ! xPropSetInfo
->hasPropertyByName(rPropertyName
))
2477 uno::Reference
<beans::XPropertyContainer
>
2478 xPropContainer(xPropSet
, uno::UNO_QUERY
);
2479 uno::Any
aAny((OUString()));
2480 xPropContainer
->addProperty
2482 static_cast<sal_Int16
>(beans::PropertyAttribute::BOUND
|
2483 beans::PropertyAttribute::REMOVABLE
),
2487 uno::Any
aAnyValue(rValue
);
2488 xPropSet
->setPropertyValue(rPropertyName
, aAnyValue
);
2491 bool WW8FormulaCheckBox::Import(const uno::Reference
<
2492 lang::XMultiServiceFactory
> &rServiceFactory
,
2493 uno::Reference
<form::XFormComponent
> &rFComp
,awt::Size
&rSz
)
2495 uno::Reference
< uno::XInterface
> xCreate
= rServiceFactory
->createInstance("com.sun.star.form.component.CheckBox");
2499 rFComp
.set( xCreate
, uno::UNO_QUERY
);
2503 uno::Reference
< beans::XPropertySet
> xPropSet( xCreate
, uno::UNO_QUERY
);
2505 rSz
.Width
= 16 * mhpsCheckBox
;
2506 rSz
.Height
= 16 * mhpsCheckBox
;
2509 if (!msTitle
.isEmpty())
2513 xPropSet
->setPropertyValue("Name", aTmp
);
2515 aTmp
<<= static_cast<sal_Int16
>(mnChecked
);
2516 xPropSet
->setPropertyValue("DefaultState", aTmp
);
2518 if (!msToolTip
.isEmpty())
2519 lcl_AddToPropertyContainer(xPropSet
, "HelpText", msToolTip
);
2521 if (!msHelp
.isEmpty())
2522 lcl_AddToPropertyContainer(xPropSet
, "HelpF1Text", msHelp
);
2528 WW8FormulaEditBox::WW8FormulaEditBox(SwWW8ImplReader
&rR
)
2529 : WW8FormulaControl(SL::aTextField
,rR
)
2533 bool SwMSConvertControls::InsertControl(
2534 const uno::Reference
< form::XFormComponent
> & rFComp
,
2535 const awt::Size
& rSize
, uno::Reference
< drawing::XShape
> *pShape
,
2538 const uno::Reference
< container::XIndexContainer
> &rComps
= GetFormComps();
2539 uno::Any
aTmp( &rFComp
, cppu::UnoType
<form::XFormComponent
>::get());
2540 rComps
->insertByIndex( rComps
->getCount(), aTmp
);
2542 const uno::Reference
< lang::XMultiServiceFactory
> &rServiceFactory
=
2543 GetServiceFactory();
2544 if( !rServiceFactory
.is() )
2547 uno::Reference
< uno::XInterface
> xCreate
= rServiceFactory
->createInstance(
2548 "com.sun.star.drawing.ControlShape");
2552 uno::Reference
< drawing::XShape
> xShape(xCreate
, uno::UNO_QUERY
);
2554 OSL_ENSURE(xShape
.is(), "Did not get XShape");
2555 xShape
->setSize(rSize
);
2557 uno::Reference
< beans::XPropertySet
> xShapePropSet(
2558 xCreate
, uno::UNO_QUERY
);
2560 //I lay a small bet that this will change to
2561 //sal_Int16 nTemp=TextContentAnchorType::AS_CHARACTER;
2562 text::TextContentAnchorType nTemp
;
2564 nTemp
= text::TextContentAnchorType_AT_PARAGRAPH
;
2566 nTemp
= text::TextContentAnchorType_AS_CHARACTER
;
2568 xShapePropSet
->setPropertyValue("AnchorType", uno::Any(static_cast<sal_Int16
>(nTemp
)) );
2570 xShapePropSet
->setPropertyValue("VertOrient", uno::Any(sal_Int16(text::VertOrientation::TOP
)) );
2572 uno::Reference
< text::XText
> xDummyTextRef
;
2573 uno::Reference
< text::XTextRange
> xTextRg
=
2574 new SwXTextRange( *m_pPaM
, xDummyTextRef
);
2577 xShapePropSet
->setPropertyValue("TextRange", aTmp
);
2579 // Set the Control-Model for the Control-Shape
2580 uno::Reference
< drawing::XControlShape
> xControlShape( xShape
,
2582 uno::Reference
< awt::XControlModel
> xControlModel( rFComp
,
2584 xControlShape
->setControl( xControlModel
);
2592 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */