xref: /trunk/main/sw/source/filter/ww8/ww8par3.cxx (revision 5f551de6)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
27 
28 
29 #include <svl/itemiter.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/outdev.hxx>
32 
33 #include <toolkit/helper/vclunohelper.hxx>
34 #include <com/sun/star/form/XFormsSupplier.hpp>
35 #include <com/sun/star/form/XForm.hpp>
36 #include <com/sun/star/form/XImageProducerSupplier.hpp>
37 #include <com/sun/star/form/XFormController.hpp>
38 #include <com/sun/star/frame/XStorable.hpp>
39 #include <com/sun/star/frame/XModel.hpp>
40 #include <com/sun/star/drawing/XConnectableShape.hpp>
41 #include <com/sun/star/drawing/XConnectorShape.hpp>
42 #include <com/sun/star/drawing/XShape.hpp>
43 #include <com/sun/star/drawing/XControlShape.hpp>
44 #include <com/sun/star/drawing/XShapeAligner.hpp>
45 #include <com/sun/star/drawing/XShapeGroup.hpp>
46 #include <com/sun/star/drawing/XUniversalShapeDescriptor.hpp>
47 #include <com/sun/star/drawing/XShapeMirror.hpp>
48 #include <com/sun/star/drawing/XShapeArranger.hpp>
49 #include <com/sun/star/drawing/XDrawPage.hpp>
50 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
51 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
52 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
53 #include <com/sun/star/container/XIndexContainer.hpp>
54 #include <com/sun/star/text/VertOrientation.hpp>
55 #include <com/sun/star/text/TextContentAnchorType.hpp>
56 #include <comphelper/extract.hxx>
57 #include <comphelper/stlunosequence.hxx>
58 #include <com/sun/star/beans/XPropertyContainer.hpp>
59 #include <com/sun/star/beans/PropertyAttribute.hpp>
60 
61 #include <algorithm>
62 #include <functional>
63 #include <hintids.hxx>
64 #include <editeng/fontitem.hxx>
65 #include <editeng/lrspitem.hxx>
66 #include <editeng/fhgtitem.hxx>
67 #include <editeng/colritem.hxx>
68 #include <editeng/wghtitem.hxx>
69 #include <editeng/crsditem.hxx>
70 #include <editeng/udlnitem.hxx>
71 #include <editeng/postitem.hxx>
72 #include <filter/msfilter/msocximex.hxx>
73 #include <errhdl.hxx>
74 #include <unotextrange.hxx>
75 #include <doc.hxx>
76 #include <docary.hxx>
77 #include <docsh.hxx>
78 #include <numrule.hxx>
79 #include <paratr.hxx>
80 #include <charatr.hxx>
81 #include <charfmt.hxx>
82 #include <ndtxt.hxx>
83 #include <expfld.hxx>
84 #include <fmtfld.hxx>
85 #include <flddropdown.hxx>
86 #include "writerhelper.hxx"
87 #include "writerwordglue.hxx"
88 #include "ww8par.hxx"
89 #include "ww8par2.hxx" // wg. Listen-Attributen in Styles
90 
91 #include <IMark.hxx>
92 #include <unotools/fltrcfg.hxx>
93 #include <xmloff/odffields.hxx>
94 
95 #include <stdio.h>
96 #include <algorithm>
97 
98 using namespace com::sun::star;
99 using namespace sw::util;
100 using namespace sw::types;
101 using namespace sw::mark;
102 
103 //-----------------------------------------
104 //            UNO-Controls
105 //-----------------------------------------
106 
107 //cmc, OCX i.e. Word 97 form controls
Read_F_OCX(WW8FieldDesc *,String &)108 eF_ResT SwWW8ImplReader::Read_F_OCX( WW8FieldDesc*, String& )
109 {
110     if( bObj && nPicLocFc )
111         nObjLocFc = nPicLocFc;
112     bEmbeddObj = true;
113     return FLD_TEXT;
114 }
115 
Read_F_FormTextBox(WW8FieldDesc * pF,String & rStr)116 eF_ResT SwWW8ImplReader::Read_F_FormTextBox( WW8FieldDesc* pF, String& rStr )
117 {
118     WW8FormulaEditBox aFormula(*this);
119 
120     if (0x01 == rStr.GetChar(writer_cast<xub_StrLen>(pF->nLCode-1))) {
121         ImportFormulaControl(aFormula,pF->nSCode+pF->nLCode-1, WW8_CT_EDIT);
122     }
123 
124     /* #80205#
125     Here we have a small complication. This formula control contains
126     the default text that is displayed if you edit the form field in
127     the "default text" area. But MS Office does not display that
128     information, instead it display the result of the field,
129     MS Office just uses the default text of the control as its
130     initial value for the displayed default text. So we will swap in
131     the field result into the formula here in place of the default
132     text.
133     */
134 
135     const SvtFilterOptions* pOpt = SvtFilterOptions::Get();
136     const sal_Bool bUseEnhFields=(pOpt && pOpt->IsUseEnhancedFields());
137 
138     if (!bUseEnhFields)
139     {
140         aFormula.sDefault = GetFieldResult(pF);
141 
142 #if 0 // why not? (flr)
143         //substituting Unicode spacing 0x2002 with double space for layout
144         aFormula.sDefault.SearchAndReplaceAll(
145             String(static_cast< sal_Unicode >(0x2002)),
146             CREATE_CONST_ASC("  "));
147 #endif
148 
149         SwInputField aFld(
150             static_cast<SwInputFieldType*>(rDoc.GetSysFldType( RES_INPUTFLD )),
151             aFormula.sDefault,
152             aFormula.sTitle,
153             INP_TXT,
154             0 );
155         aFld.SetHelp(aFormula.sHelp);
156         aFld.SetToolTip(aFormula.sToolTip);
157 
158         rDoc.InsertPoolItem( *pPaM, SwFmtFld(aFld), 0 );
159         return FLD_OK;
160     }
161     else
162     {
163         WW8PLCFx_Book* pB = pPlcxMan->GetBook();
164         String aBookmarkName;
165         if (pB!=NULL) {
166             WW8_CP currentCP=pF->nSCode;
167             WW8_CP currentLen=pF->nLen;
168 
169             sal_uInt16 bkmFindIdx;
170             String aBookmarkFind=pB->GetBookmark(currentCP-1, currentCP+currentLen-1, bkmFindIdx);
171 
172             if (aBookmarkFind.Len()>0) {
173                 pB->SetStatus(bkmFindIdx, BOOK_FIELD); // mark bookmark as consumed, such that it will not get inserted as a "normal" bookmark again
174                 if (aBookmarkFind.Len()>0) {
175                     aBookmarkName=aBookmarkFind;
176                 }
177             }
178         }
179 
180         if (pB!=NULL && aBookmarkName.Len()==0) {
181             aBookmarkName=pB->GetUniqueBookmarkName(aFormula.sTitle);
182         }
183 
184 
185         if (aBookmarkName.Len()>0) {
186             maFieldStack.back().SetBookmarkName(aBookmarkName);
187             maFieldStack.back().SetBookmarkType(::rtl::OUString::createFromAscii(ODF_FORMTEXT));
188             maFieldStack.back().getParameters()[::rtl::OUString::createFromAscii("Description")] = uno::makeAny(::rtl::OUString(aFormula.sToolTip));
189             maFieldStack.back().getParameters()[::rtl::OUString::createFromAscii("Name")] = uno::makeAny(::rtl::OUString(aFormula.sTitle));
190         }
191         return FLD_TEXT;
192     }
193 }
194 
Read_F_FormCheckBox(WW8FieldDesc * pF,String & rStr)195 eF_ResT SwWW8ImplReader::Read_F_FormCheckBox( WW8FieldDesc* pF, String& rStr )
196 {
197     WW8FormulaCheckBox aFormula(*this);
198 
199     if (!pFormImpl)
200         pFormImpl = new SwMSConvertControls(mpDocShell, pPaM);
201 
202     if (0x01 == rStr.GetChar(writer_cast<xub_StrLen>(pF->nLCode-1)))
203         ImportFormulaControl(aFormula,pF->nSCode+pF->nLCode-1, WW8_CT_CHECKBOX);
204     const SvtFilterOptions* pOpt = SvtFilterOptions::Get();
205     sal_Bool bUseEnhFields=(pOpt && pOpt->IsUseEnhancedFields());
206 
207     if (!bUseEnhFields)
208     {
209         pFormImpl->InsertFormula(aFormula);
210         return FLD_OK;
211     }
212     else
213     {
214         String aBookmarkName;
215         WW8PLCFx_Book* pB = pPlcxMan->GetBook();
216         if (pB!=NULL) {
217             WW8_CP currentCP=pF->nSCode;
218             WW8_CP currentLen=pF->nLen;
219 
220             sal_uInt16 bkmFindIdx;
221             String aBookmarkFind=pB->GetBookmark(currentCP-1, currentCP+currentLen-1, bkmFindIdx);
222 
223             if (aBookmarkFind.Len()>0) {
224                 pB->SetStatus(bkmFindIdx, BOOK_FIELD); // mark as consumed by field
225                 if (aBookmarkFind.Len()>0) {
226                     aBookmarkName=aBookmarkFind;
227                 }
228             }
229         }
230 
231         if (pB!=NULL && aBookmarkName.Len()==0) {
232             aBookmarkName=pB->GetUniqueBookmarkName(aFormula.sTitle);
233         }
234 
235         if (aBookmarkName.Len()>0)
236         {
237             IDocumentMarkAccess* pMarksAccess = rDoc.getIDocumentMarkAccess( );
238             IFieldmark* pFieldmark = dynamic_cast<IFieldmark*>( pMarksAccess->makeNoTextFieldBookmark(
239                 *pPaM, aBookmarkName,
240                 rtl::OUString::createFromAscii( ODF_FORMCHECKBOX ) ) );
241             ASSERT(pFieldmark!=NULL, "hmmm; why was the bookmark not created?");
242             if (pFieldmark!=NULL) {
243                 IFieldmark::parameter_map_t* const pParameters = pFieldmark->GetParameters();
244                 ICheckboxFieldmark* pCheckboxFm = dynamic_cast<ICheckboxFieldmark*>(pFieldmark);
245                 (*pParameters)[::rtl::OUString::createFromAscii(ODF_FORMCHECKBOX_NAME)] = uno::makeAny(::rtl::OUString(aFormula.sTitle));
246                 (*pParameters)[::rtl::OUString::createFromAscii(ODF_FORMCHECKBOX_HELPTEXT)] = uno::makeAny(::rtl::OUString(aFormula.sToolTip));
247                 if(pCheckboxFm)
248                     pCheckboxFm->SetChecked(aFormula.nChecked);
249                 // set field data here...
250             }
251         }
252         return FLD_OK;
253     }
254 }
255 
Read_F_FormListBox(WW8FieldDesc * pF,String & rStr)256 eF_ResT SwWW8ImplReader::Read_F_FormListBox( WW8FieldDesc* pF, String& rStr)
257 {
258     WW8FormulaListBox aFormula(*this);
259 
260     if (0x01 == rStr.GetChar(writer_cast<xub_StrLen>(pF->nLCode-1)))
261         ImportFormulaControl(aFormula,pF->nSCode+pF->nLCode-1, WW8_CT_DROPDOWN);
262 
263     const SvtFilterOptions* pOpt = SvtFilterOptions::Get();
264     sal_Bool bUseEnhFields=(pOpt && pOpt->IsUseEnhancedFields());
265 
266     if (!bUseEnhFields)
267     {
268         SwDropDownField aFld((SwDropDownFieldType*)rDoc.GetSysFldType(RES_DROPDOWN));
269 
270         aFld.SetName(aFormula.sTitle);
271         aFld.SetHelp(aFormula.sHelp);
272         aFld.SetToolTip(aFormula.sToolTip);
273 
274         if (!aFormula.maListEntries.empty())
275         {
276             aFld.SetItems(aFormula.maListEntries);
277             int nIndex = aFormula.fDropdownIndex < aFormula.maListEntries.size() ? aFormula.fDropdownIndex : 0;
278             aFld.SetSelectedItem(aFormula.maListEntries[nIndex]);
279         }
280 
281         rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
282         return FLD_OK;
283     }
284     else
285     {
286         // TODO: review me
287         String aBookmarkName;
288         WW8PLCFx_Book* pB = pPlcxMan->GetBook();
289         if (pB!=NULL)
290         {
291             WW8_CP currentCP=pF->nSCode;
292             WW8_CP currentLen=pF->nLen;
293 
294             sal_uInt16 bkmFindIdx;
295             String aBookmarkFind=pB->GetBookmark(currentCP-1, currentCP+currentLen-1, bkmFindIdx);
296 
297             if (aBookmarkFind.Len()>0)
298             {
299                 pB->SetStatus(bkmFindIdx, BOOK_FIELD); // mark as consumed by field
300                 if (aBookmarkFind.Len()>0)
301                     aBookmarkName=aBookmarkFind;
302             }
303         }
304 
305         if (pB!=NULL && aBookmarkName.Len()==0)
306             aBookmarkName=pB->GetUniqueBookmarkName(aFormula.sTitle);
307 
308         if (aBookmarkName.Len()>0)
309         {
310             IDocumentMarkAccess* pMarksAccess = rDoc.getIDocumentMarkAccess( );
311             IFieldmark *pFieldmark = dynamic_cast<IFieldmark*>(
312                     pMarksAccess->makeNoTextFieldBookmark( *pPaM, aBookmarkName,
313                            ::rtl::OUString::createFromAscii( ODF_FORMDROPDOWN ) ) );
314             ASSERT(pFieldmark!=NULL, "hmmm; why was the bookmark not created?");
315             if ( pFieldmark != NULL )
316             {
317                 uno::Sequence< ::rtl::OUString > vListEntries(aFormula.maListEntries.size());
318                 ::std::copy(aFormula.maListEntries.begin(), aFormula.maListEntries.end(), ::comphelper::stl_begin(vListEntries));
319                 (*pFieldmark->GetParameters())[::rtl::OUString::createFromAscii(ODF_FORMDROPDOWN_LISTENTRY)] = uno::makeAny(vListEntries);
320                 sal_Int32 nIndex = aFormula.fDropdownIndex < aFormula.maListEntries.size() ? aFormula.fDropdownIndex : 0;
321                 (*pFieldmark->GetParameters())[::rtl::OUString::createFromAscii(ODF_FORMDROPDOWN_RESULT)] = uno::makeAny(nIndex);
322                 // set field data here...
323             }
324         }
325 
326         return FLD_OK;
327     }
328 }
329 
DeleteFormImpl()330 void SwWW8ImplReader::DeleteFormImpl()
331 {
332     delete pFormImpl, pFormImpl = 0;
333 }
334 
335 //----------------------------------------------------------------------------
336 //          WW8ListManager          oeffentliche Methoden stehen ganz am Ende
337 //------------------------- ============ --------------- ============ --------
338 
339 
340 
341 // Hilfs-Deklarationen ///////////////////////////////////////////////////////
342 //
343 // Style Id's for each level
344 typedef sal_uInt16 WW8aIdSty[WW8ListManager::nMaxLevel];
345 // Zeichenattribute aus GrpprlChpx
346 typedef SfxItemSet* WW8aISet[WW8ListManager::nMaxLevel];
347 // Zeichen Style Pointer
348 typedef SwCharFmt* WW8aCFmt[WW8ListManager::nMaxLevel];
349 
350 struct WW8LST   // nur DIE Eintraege, die WIR benoetigen!
351 {
352     WW8aIdSty aIdSty;     // Style Id's for each level,
353                             //   nIStDNil if no style linked
354     sal_uInt32 nIdLst;     // Unique List ID
355     sal_uInt32 nTplC;      // Unique template code - Was ist das bloss?
356     sal_uInt8 bSimpleList:1; // Flag: Liste hat nur EINEN Level
357     sal_uInt8 bRestartHdn:1; // WW6-Kompatibilitaets-Flag:
358                                                         //   true if the list should start numbering over
359 };                                                      //   at the beginning of each section
360 
361 struct WW8LFO   // nur DIE Eintraege, die WIR benoetigen!
362 {
363     SwNumRule*      pNumRule;   // Parent NumRule
364     sal_uInt32      nIdLst;     // Unique List ID
365     sal_uInt8       nLfoLvl;    // count of levels whose format is overridden
366     bool bSimpleList;
367 };
368 
369 struct WW8LVL   // nur DIE Eintraege, die WIR benoetigen!
370 {
371     long    nStartAt;       // start at value for this value
372     long    nV6DxaSpace;// Ver6-Compatible: min Space between Num anf text::Paragraph
373     long    nV6Indent;  // Ver6-Compatible: Breite des Prefix Textes; ggfs. zur
374                         // Definition d. Erstzl.einzug nutzen!
375     // Absatzattribute aus GrpprlPapx
376     sal_uInt16  nDxaLeft;               // linker Einzug
377     short   nDxaLeft1;          // Erstzeilen-Einzug
378 
379     sal_uInt8   nNFC;               // number format code
380     // Offset der Feldkodes im Num-X-String
381     sal_uInt8   aOfsNumsXCH[WW8ListManager::nMaxLevel];
382     sal_uInt8   nLenGrpprlChpx; // length, in bytes, of the LVL's grpprlChpx
383     sal_uInt8   nLenGrpprlPapx; // length, in bytes, of the LVL's grpprlPapx
384     sal_uInt8   nAlign: 2;  // alignment (left, right, centered) of the number
385     sal_uInt8 bLegal:    1;  // egal
386     sal_uInt8 bNoRest:1; // egal
387     sal_uInt8 bV6Prev:1; // Ver6-Compatible: number will include previous levels
388     sal_uInt8 bV6PrSp:1; // Ver6-Compatible: egal
389     sal_uInt8 bV6:       1;  // falls true , beachte die V6-Compatible Eintraege!
390     sal_uInt8   bDummy: 1;  // (macht das Byte voll)
391 
392 };
393 
394 struct WW8LFOLVL
395 {
396     long nStartAt;          // start-at value if bFormat==false and bStartAt == true
397                                             // (if bFormat==true, the start-at is stored in the LVL)
398     sal_uInt8 nLevel;               // the level to be overridden
399     // dieses Byte ist _absichtlich_ nicht in das folgende Byte hineingepackt!
400     // (siehe Kommentar unten bei struct WW8LFOInfo)
401 
402     sal_uInt8 bStartAt :1;       // true if the start-at value is overridden
403     sal_uInt8 bFormat :1;        // true if the formatting is overridden
404 
WW8LFOLVLWW8LFOLVL405     WW8LFOLVL() :
406         nStartAt(1), nLevel(0), bStartAt(1), bFormat(0) {}
407 };
408 
409 // in den ListenInfos zu speichernde Daten ///////////////////////////////////
410 //
411 struct WW8LSTInfo   // sortiert nach nIdLst (in WW8 verwendete Listen-Id)
412 {
413     std::vector<ww::bytes> maParaSprms;
414     WW8aIdSty   aIdSty;          // Style Id's for each level
415     WW8aISet    aItemSet;        // Zeichenattribute aus GrpprlChpx
416     WW8aCFmt    aCharFmt;        // Zeichen Style Pointer
417 
418     SwNumRule*  pNumRule;        // Zeiger auf entsprechende Listenvorlage im Writer
419     sal_uInt32      nIdLst;          // WW8Id dieser Liste
420     sal_uInt8 bSimpleList:1;// Flag, ob diese NumRule nur einen Level verwendet
421     sal_uInt8 bUsedInDoc :1;// Flag, ob diese NumRule im Doc verwendet wird,
422                                                      //   oder beim Reader-Ende geloescht werden sollte
423 
WW8LSTInfoWW8LSTInfo424     WW8LSTInfo(SwNumRule* pNumRule_, WW8LST& aLST)
425         : pNumRule(pNumRule_), nIdLst(aLST.nIdLst),
426         bSimpleList(aLST.bSimpleList), bUsedInDoc(0)
427     {
428         memcpy( aIdSty, aLST.aIdSty, sizeof( aIdSty ));
429         memset(&aItemSet, 0,  sizeof( aItemSet ));
430         memset(&aCharFmt, 0,  sizeof( aCharFmt ));
431     }
432 
433 };
434 
435 // in den ListenFormatOverrideInfos zu speichernde Daten /////////////////////
436 //
437 struct WW8LFOInfo   // unsortiert, d.h. Reihenfolge genau wie im WW8 Stream
438 {
439     std::vector<ww::bytes> maParaSprms;
440     std::vector<WW8LFOLVL> maOverrides;
441     SwNumRule* pNumRule;         // Zeiger auf entsprechende Listenvorlage im Writer
442                                                      // entweder: Liste in LSTInfos oder eigene Liste
443                                                      // (im Ctor erstmal die aus den LSTInfos merken)
444 
445     sal_uInt32  nIdLst;          // WW8-Id der betreffenden Liste
446     sal_uInt8   nLfoLvl;             // count of levels whose format is overridden
447     // Ja, ich natuerlich koennten wir nLfoLvl (mittels :4) noch in das folgende
448     // Byte mit hineinpacken, doch waere das eine ziemliche Fehlerquelle,
449     // an dem Tag, wo MS ihr Listenformat auf mehr als 15 Level aufbohren.
450 
451     sal_uInt8 bOverride  :1;// Flag, ob die NumRule nicht in maLSTInfos steht,
452                                                      //   sondern fuer pLFOInfos NEU angelegt wurde
453     sal_uInt8 bSimpleList:1;// Flag, ob diese NumRule nur einen Level verwendet
454     sal_uInt8 bUsedInDoc :1;// Flag, ob diese NumRule im Doc verwendet wird,
455                                                      //   oder beim Reader-Ende geloescht werden sollte
456     sal_uInt8 bLSTbUIDSet    :1;// Flag, ob bUsedInDoc in maLSTInfos gesetzt wurde,
457                                                      //   und nicht nochmals gesetzt zu werden braucht
458     WW8LFOInfo(const WW8LFO& rLFO);
459 };
460 
WW8LFOInfo(const WW8LFO & rLFO)461 WW8LFOInfo::WW8LFOInfo(const WW8LFO& rLFO)
462     : maParaSprms(WW8ListManager::nMaxLevel)
463     , maOverrides(WW8ListManager::nMaxLevel)
464     , pNumRule(rLFO.pNumRule)
465     , nIdLst(rLFO.nIdLst)
466     , nLfoLvl(rLFO.nLfoLvl)
467     , bOverride(rLFO.nLfoLvl ? true : false)
468     , bSimpleList(rLFO.bSimpleList)
469     , bUsedInDoc(0)
470     , bLSTbUIDSet(0)
471 {
472 }
473 
474 SV_IMPL_PTRARR( WW8LFOInfos, WW8LFOInfo_Ptr );
475 
476 
477 // Hilfs-Methoden ////////////////////////////////////////////////////////////
478 //
479 
480 // finden der Sprm-Parameter-Daten, falls Sprm im Grpprl enthalten
GrpprlHasSprm(sal_uInt16 nId,sal_uInt8 & rSprms,sal_uInt8 nLen)481 sal_uInt8* WW8ListManager::GrpprlHasSprm(sal_uInt16 nId, sal_uInt8& rSprms,
482     sal_uInt8 nLen)
483 {
484     sal_uInt8* pSprms = &rSprms;
485     sal_uInt16 i=0;
486     while (i < nLen)
487     {
488         sal_uInt16 nAktId = maSprmParser.GetSprmId(pSprms);
489         if( nAktId == nId ) // Sprm found
490             return pSprms + maSprmParser.DistanceToData(nId);
491 
492         // gib Zeiger auf Daten
493         sal_uInt16 x = maSprmParser.GetSprmSize(nAktId, pSprms);
494         i = i + x;
495         pSprms += x;
496     }
497     return 0;                           // Sprm not found
498 }
499 
500 class ListWithId : public std::unary_function<const WW8LSTInfo *, bool>
501 {
502 private:
503     sal_uInt32 mnIdLst;
504 public:
ListWithId(sal_uInt32 nIdLst)505     explicit ListWithId(sal_uInt32 nIdLst) : mnIdLst(nIdLst) {}
operator ()(const WW8LSTInfo * pEntry) const506     bool operator() (const WW8LSTInfo *pEntry) const
507         { return (pEntry->nIdLst == mnIdLst); }
508 };
509 
510 // Zugriff ueber die List-Id des LST Eintrags
GetLSTByListId(sal_uInt32 nIdLst) const511 WW8LSTInfo* WW8ListManager::GetLSTByListId( sal_uInt32 nIdLst ) const
512 {
513     std::vector<WW8LSTInfo *>::const_iterator aResult =
514         std::find_if(maLSTInfos.begin(),maLSTInfos.end(),ListWithId(nIdLst));
515     if (aResult == maLSTInfos.end())
516         return 0;
517     return *aResult;
518 }
519 
lcl_CopyGreaterEight(String & rDest,String & rSrc,xub_StrLen nStart,xub_StrLen nLen=STRING_LEN)520 void lcl_CopyGreaterEight(String &rDest, String &rSrc,
521     xub_StrLen nStart, xub_StrLen nLen = STRING_LEN)
522 {
523     if (nLen == STRING_LEN)
524         nLen = rSrc.Len();
525     for (xub_StrLen nI = nStart; nI < nLen; ++nI)
526     {
527         sal_Unicode nChar = rSrc.GetChar(nI);
528         if (nChar > WW8ListManager::nMaxLevel)
529             rDest.Append(nChar);
530     }
531 }
532 
ReadLVL(SwNumFmt & rNumFmt,SfxItemSet * & rpItemSet,sal_uInt16 nLevelStyle,bool bSetStartNo,std::deque<bool> & rNotReallyThere,sal_uInt16 nLevel,ww::bytes & rParaSprms)533 bool WW8ListManager::ReadLVL(
534     SwNumFmt& rNumFmt,
535     SfxItemSet*& rpItemSet,
536     sal_uInt16 nLevelStyle,
537     bool bSetStartNo,
538     std::deque< bool > &rNotReallyThere,
539     sal_uInt16 nLevel,
540     ww::bytes &rParaSprms )
541 {
542     sal_uInt8       aBits1;
543     sal_uInt16      nStartNo    = 0;    // Start-Nr. fuer den Writer
544     sal_Int16       nType(style::NumberingType::ARABIC);
545     SvxAdjust       eAdj;               // Ausrichtung (Links/rechts/zent.)
546     sal_Unicode     cBullet(0x2190);    // default safe bullet
547 
548     sal_Unicode     cGrfBulletCP(USHRT_MAX);
549 
550     String          sPrefix;
551     String          sPostfix;
552     WW8LVL          aLVL;
553     //
554     // 1. LVLF einlesen
555     //
556     memset(&aLVL, 0, sizeof( aLVL ));
557     rSt >> aLVL.nStartAt;
558     rSt >> aLVL.nNFC;
559     rSt >> aBits1;
560     if( 0 != rSt.GetError() ) return false;
561     aLVL.nAlign = (aBits1 & 0x03);
562     if( aBits1 & 0x10 ) aLVL.bV6Prev    = true;
563     if( aBits1 & 0x20 ) aLVL.bV6PrSp    = true;
564     if( aBits1 & 0x40 ) aLVL.bV6        = true;
565     bool bLVLOkB = true;
566     sal_uInt8 nLevelB = 0;
567     for(nLevelB = 0; nLevelB < nMaxLevel; ++nLevelB)
568     {
569         rSt >> aLVL.aOfsNumsXCH[ nLevelB ];
570         if( 0 != rSt.GetError() )
571         {
572             bLVLOkB = false;
573             break;
574         }
575     }
576 
577     if( !bLVLOkB )
578         return false;
579 
580     sal_uInt8 ixchFollow;
581     rSt >> ixchFollow;
582     if (ixchFollow == 0)
583         rReader.maTracer.Log(sw::log::eTabInNumbering);
584     rSt >> aLVL.nV6DxaSpace;
585     rSt >> aLVL.nV6Indent;
586     rSt >> aLVL.nLenGrpprlChpx;
587     rSt >> aLVL.nLenGrpprlPapx;
588     rSt.SeekRel( 2 );
589     if( 0 != rSt.GetError()) return false;
590 
591     //
592     // 2. ggfs. PAPx einlesen und nach Einzug-Werten suchen
593     //
594     // --> OD 2008-06-04 #i86652# - read tab setting
595     short nTabPos = 0;
596     // <--
597     if( aLVL.nLenGrpprlPapx )
598     {
599         sal_uInt8 aGrpprlPapx[ 255 ];
600         if(aLVL.nLenGrpprlPapx != rSt.Read(&aGrpprlPapx,aLVL.nLenGrpprlPapx))
601             return false;
602         // "sprmPDxaLeft"  pap.dxaLeft;dxa;word;
603         sal_uInt8* pSprm;
604         if (
605             (0 != (pSprm = GrpprlHasSprm(0x840F,aGrpprlPapx[0],aLVL.nLenGrpprlPapx))) ||
606             (0 != (pSprm = GrpprlHasSprm(0x845E,aGrpprlPapx[0],aLVL.nLenGrpprlPapx)))
607             )
608         {
609             sal_uInt8 *pBegin = pSprm-2;
610             for(int i=0;i<4;++i)
611                 rParaSprms.push_back(*pBegin++);
612             short nDxaLeft = SVBT16ToShort( pSprm );
613             aLVL.nDxaLeft = (0 < nDxaLeft) ? (sal_uInt16)nDxaLeft
614                             : (sal_uInt16)(-nDxaLeft);
615         }
616 
617         // "sprmPDxaLeft1" pap.dxaLeft1;dxa;word;
618         if (
619             (0 != (pSprm = GrpprlHasSprm(0x8411,aGrpprlPapx[0],aLVL.nLenGrpprlPapx)) ) ||
620             (0 != (pSprm = GrpprlHasSprm(0x8460,aGrpprlPapx[0],aLVL.nLenGrpprlPapx)) )
621             )
622         {
623             sal_uInt8 *pBegin = pSprm-2;
624             for(int i=0;i<4;++i)
625                 rParaSprms.push_back(*pBegin++);
626             aLVL.nDxaLeft1 = SVBT16ToShort( pSprm );
627         }
628 
629         // --> OD 2008-06-04 #i86652# - read tab setting
630         if(0 != (pSprm = GrpprlHasSprm(0xC615,aGrpprlPapx[0],aLVL.nLenGrpprlPapx)) )
631         {
632             bool bDone = false;
633             if (*(pSprm-1) == 5)
634             {
635                 if (*pSprm++ == 0) //nDel
636                 {
637                     if (*pSprm++ == 1) //nIns
638                     {
639                         nTabPos = SVBT16ToShort(pSprm);
640                         pSprm+=2;
641                         if (*pSprm == 6) //type
642                         {
643                             bDone = true;
644                         }
645                     }
646                 }
647             }
648             ASSERT(bDone, "tab setting in numbering is "
649                 "of unexpected configuration");
650         }
651         if ( rNumFmt.GetPositionAndSpaceMode() ==
652                                   SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
653         {
654             // If there is a tab setting with a larger value, then use that.
655             // Ideally we would allow tabs to be used in numbering fields and set
656             // this on the containing paragraph which would make it actually work
657             // most of the time.
658             if ( nTabPos != 0 )
659             {
660                 const sal_uInt16 nDesired = aLVL.nDxaLeft + aLVL.nDxaLeft1;
661 
662                 bool bDoAdjust = false;
663                 if ( nDesired < aLVL.nDxaLeft )
664                 {
665                     if ( nDesired < nTabPos && nTabPos < aLVL.nDxaLeft )
666                     {
667                         bDoAdjust = true;
668                     }
669                 }
670                 else
671                 {
672                     if ( aLVL.nDxaLeft < nTabPos && nTabPos < nDesired )
673                     {
674                         bDoAdjust = true;
675                     }
676                 }
677 
678                 if (bDoAdjust)
679                 {
680                     aLVL.nDxaLeft = (0 < nTabPos)
681                                     ? (sal_uInt16)nTabPos
682                                     : (sal_uInt16)(-nTabPos);
683 
684                     aLVL.nDxaLeft1 = nDesired - aLVL.nDxaLeft;
685                 }
686             }
687         }
688         // <--
689     }
690     //
691     // 3. ggfs. CHPx einlesen und
692     //
693 	sal_uInt16 nWitchPicIsBullet = USHRT_MAX;
694 	bool bIsPicBullet = false;
695 
696     if( aLVL.nLenGrpprlChpx )
697     {
698         sal_uInt8 aGrpprlChpx[ 255 ];
699         memset(&aGrpprlChpx, 0, sizeof( aGrpprlChpx ));
700         if(aLVL.nLenGrpprlChpx != rSt.Read(&aGrpprlChpx, aLVL.nLenGrpprlChpx))
701             return false;
702 
703 	//For i120928,parse the graphic info of bullets
704 	sal_uInt8 *pSprmWhichPis = GrpprlHasSprm(0x6887,aGrpprlChpx[0],aLVL.nLenGrpprlChpx);
705 	sal_uInt8 *pSprmIsPicBullet = GrpprlHasSprm(0x4888,aGrpprlChpx[0],aLVL.nLenGrpprlChpx);
706 	if (pSprmWhichPis)
707 	{
708 		nWitchPicIsBullet = *pSprmWhichPis;
709 	}
710 	if (pSprmIsPicBullet)
711 	{
712 		bIsPicBullet = (*pSprmIsPicBullet) & 0x0001;
713 	}
714 
715         // neues ItemSet fuer die Zeichenattribute anlegen
716         rpItemSet = new SfxItemSet( rDoc.GetAttrPool(), RES_CHRATR_BEGIN,
717             RES_CHRATR_END - 1 );
718 
719         // Reader-ItemSet-Pointer darauf zeigen lassen
720         rReader.SetAktItemSet( rpItemSet );
721         // Reader-Style auf den Style dieses Levels setzen
722         sal_uInt16 nOldColl = rReader.GetNAktColl();
723         sal_uInt16 nNewColl = nLevelStyle;
724         if (ww::stiNil == nNewColl)
725             nNewColl = 0;
726         rReader.SetNAktColl( nNewColl );
727 
728         // Nun den GrpprlChpx einfach durchnudeln: die Read_xy() Methoden
729         // in WW8PAR6.CXX rufen ganz normal ihr NewAttr() oder GetFmtAttr()
730         // und diese merken am besetzten Reader-ItemSet-Pointer, dass dieser
731         // spezielle ItemSet relevant ist - und nicht ein Stack oder Style!
732         sal_uInt16 nOldFlags1 = rReader.GetToggleAttrFlags();
733         sal_uInt16 nOldFlags2 = rReader.GetToggleBiDiAttrFlags();
734         short nLen      = aLVL.nLenGrpprlChpx;
735         sal_uInt8* pSprms1  = &aGrpprlChpx[0];
736         while (0 < nLen)
737         {
738             sal_uInt16 nL1 = rReader.ImportSprm( pSprms1 );
739             nLen       = nLen - nL1;
740             pSprms1   += nL1;
741         }
742         // Reader-ItemSet-Pointer und Reader-Style zuruecksetzen
743         rReader.SetAktItemSet( 0 );
744         rReader.SetNAktColl( nOldColl );
745         rReader.SetToggleAttrFlags(nOldFlags1);
746         rReader.SetToggleBiDiAttrFlags(nOldFlags2);
747     }
748     //
749     // 4. den Nummerierungsstring einlesen: ergibt Prefix und Postfix
750     //
751     String sNumString(WW8Read_xstz(rSt, 0, false));
752     //
753     // 5. gelesene Werte in Writer Syntax umwandeln
754     //
755     if( 0 <= aLVL.nStartAt )
756         nStartNo = (sal_uInt16)aLVL.nStartAt;
757     switch( aLVL.nNFC )
758     {
759         case 0:
760             nType = style::NumberingType::ARABIC;
761             break;
762         case 1:
763             nType = style::NumberingType::ROMAN_UPPER;
764             break;
765         case 2:
766             nType = style::NumberingType::ROMAN_LOWER;
767             break;
768         case 3:
769             nType = style::NumberingType::CHARS_UPPER_LETTER_N;
770             break;
771         case 4:
772             nType = style::NumberingType::CHARS_LOWER_LETTER_N;
773             break;
774         case 5:
775             // eigentlich: ORDINAL
776             nType = style::NumberingType::ARABIC;
777             break;
778         case 23:
779             nType = style::NumberingType::CHAR_SPECIAL;
780 			//For i120928,type info
781 			if (bIsPicBullet)
782 			{
783 				nType = style::NumberingType::BITMAP;
784 			}
785 
786             break;
787         case 255:
788             nType = style::NumberingType::NUMBER_NONE;
789             break;
790         case 18: 	nType = style::NumberingType::CIRCLE_NUMBER ;	break;
791         case 14:
792         case 19: 	nType = style::NumberingType::FULLWIDTH_ARABIC ;	break;
793         case 30: 	nType = style::NumberingType::TIAN_GAN_ZH ;	break;
794         case 31: 	nType = style::NumberingType::DI_ZI_ZH ;	break;
795         case 35:
796         case 36:
797         case 37:
798         case 39:
799                     nType = style::NumberingType::NUMBER_LOWER_ZH ;	break;
800         case 34: 	nType = style::NumberingType::NUMBER_UPPER_ZH_TW ;	break;
801         case 38: 	nType = style::NumberingType::NUMBER_UPPER_ZH ;	break;
802         case 10:
803         case 11:
804                     nType = style::NumberingType::NUMBER_TRADITIONAL_JA ;	break;
805         case 20: 	nType = style::NumberingType::AIU_FULLWIDTH_JA ;	break;
806         case 12: 	nType = style::NumberingType::AIU_HALFWIDTH_JA ;	break;
807         case 21: 	nType = style::NumberingType::IROHA_FULLWIDTH_JA ;	break;
808         case 13: 	nType = style::NumberingType::IROHA_HALFWIDTH_JA ;	break;
809         case 24: 	nType = style::NumberingType::HANGUL_SYLLABLE_KO;	break;
810         case 25:	nType = style::NumberingType::HANGUL_JAMO_KO;		break;
811         case 41:	nType = style::NumberingType::NUMBER_HANGUL_KO; break;
812         case 44:	nType = style::NumberingType::NUMBER_UPPER_KO; break;
813 
814         default:
815             // take default
816         nType = style::NumberingType::ARABIC;
817         break;
818     }
819 
820     // If a number level is not going to be used, then record this fact
821     if (style::NumberingType::NUMBER_NONE == nType)
822         rNotReallyThere[nLevel] = true;
823 
824     /*
825      If a number level was not used (i.e. is in NotReallyThere), and that
826      number level appears at one of the positions in the display string of the
827      list, then it effectively is not there at all. So remove that level entry
828      from a copy of the aOfsNumsXCH.
829     */
830     std::vector<sal_uInt8> aOfsNumsXCH;
831     typedef std::vector<sal_uInt8>::iterator myIter;
832     aOfsNumsXCH.reserve(nMaxLevel);
833 
834     for(nLevelB = 0; nLevelB < nMaxLevel; ++nLevelB)
835         aOfsNumsXCH.push_back(aLVL.aOfsNumsXCH[nLevelB]);
836 
837     for(nLevelB = 0; nLevelB <= nLevel; ++nLevelB)
838     {
839         sal_uInt8 nPos = aOfsNumsXCH[nLevelB];
840         if (nPos && sNumString.GetChar(nPos-1) < nMaxLevel)
841         {
842             if (rNotReallyThere[nLevelB])
843                 aOfsNumsXCH[nLevelB] = 0;
844         }
845     }
846     myIter aIter = std::remove(aOfsNumsXCH.begin(), aOfsNumsXCH.end(), 0);
847     myIter aEnd = aOfsNumsXCH.end();
848     // --> OD 2006-01-16 #i60633# - suppress access on <aOfsNumsXCH.end()>
849     if ( aIter != aEnd )
850     {
851         // Somehow the first removed vector element, at which <aIter>
852         // points to, isn't reset to zero.
853         // Investigation is needed to clarify why. It seems that only
854         // special arrays are handled correctly by this code.
855         ++aIter;
856         while (aIter != aEnd)
857         {
858             (*aIter) = 0;
859             ++aIter;
860         }
861     }
862     // <--
863 
864     sal_uInt8 nUpperLevel = 0;  // akt. Anzeigetiefe fuer den Writer
865     for(nLevelB = 0; nLevelB < nMaxLevel; ++nLevelB)
866     {
867         if (!nUpperLevel && !aOfsNumsXCH[nLevelB])
868             nUpperLevel = nLevelB;
869     }
870 
871     // falls kein NULL als Terminierungs-Char kam,
872     // ist die Liste voller Indices, d.h. alle Plaetze sind besetzt,
873     // also sind alle Level anzuzeigen
874     if (!nUpperLevel)
875         nUpperLevel = nMaxLevel;
876 
877     if (style::NumberingType::CHAR_SPECIAL == nType)
878     {
879         cBullet = sNumString.Len() ? sNumString.GetChar(0) : 0x2190;
880 
881         if (!cBullet)  // unsave control code?
882             cBullet = 0x2190;
883     }	else if (style::NumberingType::BITMAP == nType)	//For i120928, position index info of graphic
884 	{
885 		cGrfBulletCP = nWitchPicIsBullet;       // This is a bullet picture ID
886 	} else
887     {
888         /*
889         #83154#, #82192#, #i173#, #109158#
890         Our aOfsNumsXCH seems generally to be an array that contains the
891         offset into sNumString of locations where the numbers should be
892         filled in, so if the first "fill in a number" slot is greater than
893         1 there is a "prefix" before the number
894         */
895         //First number appears at
896         sal_uInt8 nOneBasedFirstNoIndex = aOfsNumsXCH[0];
897         xub_StrLen nFirstNoIndex =
898             nOneBasedFirstNoIndex > 0 ? nOneBasedFirstNoIndex -1 : STRING_LEN;
899         lcl_CopyGreaterEight(sPrefix, sNumString, 0, nFirstNoIndex);
900 
901         //Next number appears at
902         if (nUpperLevel)
903         {
904             sal_uInt8 nOneBasedNextNoIndex = aOfsNumsXCH[nUpperLevel-1];
905             xub_StrLen nNextNoIndex =
906                 nOneBasedNextNoIndex > 0 ? nOneBasedNextNoIndex -1 : STRING_LEN;
907             if (nNextNoIndex != STRING_LEN)
908                 ++nNextNoIndex;
909             if (sNumString.Len() > nNextNoIndex)
910                 lcl_CopyGreaterEight(sPostfix, sNumString, nNextNoIndex);
911         }
912 
913         /*
914          We use lcl_CopyGreaterEight because once if we have removed unused
915          number indexes from the aOfsNumsXCH then placeholders remain in
916          sNumString which must not be copied into the final numbering strings
917         */
918     }
919 
920     switch( aLVL.nAlign )
921     {
922         case 0:
923             eAdj = SVX_ADJUST_LEFT;
924             break;
925         case 1:
926             eAdj = SVX_ADJUST_CENTER;
927             break;
928         case 2:
929             eAdj = SVX_ADJUST_RIGHT;
930             break;
931         case 3:
932             // Writer here cannot do block justification
933             eAdj = SVX_ADJUST_LEFT;
934             break;
935          default:
936             // undefined value
937             ASSERT( sal_False, "Value of aLVL.nAlign is not supported" );
938             // take default
939             eAdj = SVX_ADJUST_LEFT;
940             break;
941     }
942 
943     // 6. entsprechendes NumFmt konfigurieren
944     if( bSetStartNo )
945         rNumFmt.SetStart( nStartNo );
946     rNumFmt.SetNumberingType( nType );
947     rNumFmt.SetNumAdjust( eAdj );
948 
949     if( style::NumberingType::CHAR_SPECIAL == nType )
950     {
951         // first character of the Prefix-Text is the Bullet
952         rNumFmt.SetBulletChar(cBullet);
953         // Don't forget: unten, nach dem Bauen eventueller Styles auch noch
954         // SetBulletFont() rufen !!!
955     }
956 	//For i120928,position index info
957 	else if (style::NumberingType::BITMAP == nType)
958 	{
959 		rNumFmt.SetGrfBulletCP(cGrfBulletCP);
960 	}
961     else
962     {
963         // reminder: Garnix ist default Prefix
964         if( sPrefix.Len() )
965             rNumFmt.SetPrefix( sPrefix );
966         // reminder: Point is default Postfix
967         rNumFmt.SetSuffix( sPostfix );
968         rNumFmt.SetIncludeUpperLevels( nUpperLevel );
969     }
970 
971     // --> OD 2008-06-04 #i89181#
972     if ( rNumFmt.GetPositionAndSpaceMode() ==
973                               SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
974     {
975         if (eAdj == SVX_ADJUST_RIGHT)
976         {
977             rNumFmt.SetAbsLSpace(aLVL.nDxaLeft);
978             rNumFmt.SetFirstLineOffset(-aLVL.nDxaLeft);
979             rNumFmt.SetCharTextDistance(-aLVL.nDxaLeft1);
980         }
981         else
982         {
983             rNumFmt.SetAbsLSpace( aLVL.nDxaLeft );
984             rNumFmt.SetFirstLineOffset(aLVL.nDxaLeft1);
985         }
986     }
987     else
988     {
989         rNumFmt.SetIndentAt( aLVL.nDxaLeft );
990         rNumFmt.SetFirstLineIndent(aLVL.nDxaLeft1);
991         rNumFmt.SetListtabPos( nTabPos );
992         SvxNumberFormat::SvxNumLabelFollowedBy eNumLabelFollowedBy = SvxNumberFormat::LISTTAB;
993         switch ( ixchFollow )
994         {
995             case 0:
996             {
997                 eNumLabelFollowedBy = SvxNumberFormat::LISTTAB;
998             }
999             break;
1000             case 1:
1001             {
1002                 eNumLabelFollowedBy = SvxNumberFormat::SPACE;
1003             }
1004             break;
1005             case 2:
1006             {
1007                 eNumLabelFollowedBy = SvxNumberFormat::NOTHING;
1008             }
1009             break;
1010         }
1011         rNumFmt.SetLabelFollowedBy( eNumLabelFollowedBy );
1012     }
1013 
1014     return true;
1015 }
1016 
AdjustLVL(sal_uInt8 nLevel,SwNumRule & rNumRule,WW8aISet & rListItemSet,WW8aCFmt & rCharFmt,bool & bNewCharFmtCreated,String sPrefix)1017 void WW8ListManager::AdjustLVL( sal_uInt8 nLevel, SwNumRule& rNumRule,
1018     WW8aISet& rListItemSet, WW8aCFmt& rCharFmt, bool& bNewCharFmtCreated,
1019     String sPrefix )
1020 {
1021     bNewCharFmtCreated = false;
1022     SfxItemSet* pThisLevelItemSet;
1023     SfxItemSet* pLowerLevelItemSet;
1024     sal_uInt8        nIdenticalItemSetLevel;
1025     const SfxPoolItem* pItem;
1026 
1027     SwNumFmt aNumFmt  = rNumRule.Get( nLevel );
1028 
1029     pThisLevelItemSet = rListItemSet[ nLevel ];
1030 
1031     if( pThisLevelItemSet && pThisLevelItemSet->Count())
1032     {
1033         nIdenticalItemSetLevel = nMaxLevel;
1034         SfxItemIter aIter( *pThisLevelItemSet );
1035         for (sal_uInt8 nLowerLevel = 0; nLowerLevel < nLevel; ++nLowerLevel)
1036         {
1037             pLowerLevelItemSet = rListItemSet[ nLowerLevel ];
1038             if(     pLowerLevelItemSet
1039                 && (pLowerLevelItemSet->Count() == pThisLevelItemSet->Count()) )
1040             {
1041                 nIdenticalItemSetLevel = nLowerLevel;
1042                 sal_uInt16 nWhich = aIter.GetCurItem()->Which();
1043                 while (true)
1044                 {
1045                     if(  // ggfs. passenden pItem im pLowerLevelItemSet finden
1046                          (SFX_ITEM_SET != pLowerLevelItemSet->GetItemState(
1047                                             nWhich, false, &pItem ) )
1048                         || // virtuellen "!=" Operator anwenden
1049                          (*pItem != *aIter.GetCurItem() ) )
1050                     // falls kein Item mit gleicher nWhich gefunden oder Werte
1051                     // der Items ungleich, Ungleichheit merken und abbrechen!
1052                     {
1053                         nIdenticalItemSetLevel = nMaxLevel;
1054                         break;
1055                     }
1056                     if( aIter.IsAtEnd() )
1057                         break;
1058                     nWhich = aIter.NextItem()->Which();
1059                 }
1060 
1061                 if( nIdenticalItemSetLevel != nMaxLevel )
1062                     break;
1063             }
1064         }
1065 
1066         SwCharFmt* pFmt;
1067         if (nMaxLevel == nIdenticalItemSetLevel)
1068         {
1069             // Style definieren
1070             String aName( sPrefix.Len() ? sPrefix : rNumRule.GetName() );
1071             (aName += 'z') += String::CreateFromInt32( nLevel );
1072 
1073             // const Wegcasten
1074             pFmt = rDoc.MakeCharFmt(aName, (SwCharFmt*)rDoc.GetDfltCharFmt());
1075             bNewCharFmtCreated = true;
1076             // Attribute reinsetzen
1077             pFmt->SetFmtAttr( *pThisLevelItemSet );
1078         }
1079         else
1080         {
1081             // passenden Style hier anhaengen
1082             pFmt = rCharFmt[ nIdenticalItemSetLevel ];
1083         }
1084 
1085         // merken
1086         rCharFmt[ nLevel ] = pFmt;
1087 
1088         //
1089         // Style an das NumFormat haengen
1090         //
1091         aNumFmt.SetCharFmt( pFmt );
1092     }
1093 	//Modify for #119405 by chengjh, 2012-08-16
1094 	//Ensure the default char fmt is initialized for any level of num ruler if no customized attr
1095 	else
1096 	{
1097 		SwCharFmt* pFmt = aNumFmt.GetCharFmt();
1098 		if ( !pFmt)
1099 		{
1100 			String aName( sPrefix.Len() ? sPrefix : rNumRule.GetName() );
1101 	            	(aName += 'z') += String::CreateFromInt32( nLevel );
1102 
1103 	            	pFmt = rDoc.MakeCharFmt(aName, (SwCharFmt*)rDoc.GetDfltCharFmt());
1104 	            	bNewCharFmtCreated = true;
1105 			rCharFmt[ nLevel ] = pFmt;
1106 			aNumFmt.SetCharFmt( pFmt );
1107 		}
1108 	}
1109 	//End
1110     //
1111     // ggfs. Bullet Font an das NumFormat haengen
1112     //
1113     if( SVX_NUM_CHAR_SPECIAL == aNumFmt.GetNumberingType() )
1114     {
1115         SwCharFmt* pFmt = aNumFmt.GetCharFmt();
1116         Font aFont;
1117         if( !pFmt )
1118         {
1119             // --> OD 2006-06-27 #b6440955#
1120 //            aFont = SwNumRule::GetDefBulletFont();
1121             aFont = numfunc::GetDefBulletFont();
1122             // <--
1123         }
1124         else
1125         {
1126             const SvxFontItem& rFontItem = pFmt->GetFont();
1127             aFont.SetFamily(    rFontItem.GetFamily()     );
1128             aFont.SetName(      rFontItem.GetFamilyName() );
1129             aFont.SetStyleName( rFontItem.GetStyleName()  );
1130             aFont.SetPitch(     rFontItem.GetPitch()      );
1131             aFont.SetCharSet(   rFontItem.GetCharSet()    );
1132         }
1133         aNumFmt.SetBulletFont( &aFont );
1134     }
1135     //
1136     // und wieder rein in die NumRule
1137     //
1138     rNumRule.Set(nLevel, aNumFmt);
1139 }
1140 
CreateNextRule(bool bSimple)1141 SwNumRule* WW8ListManager::CreateNextRule(bool bSimple)
1142 {
1143     // wird erstmal zur Bildung des Style Namens genommen
1144     String sPrefix(CREATE_CONST_ASC("WW8Num"));
1145     sPrefix += String::CreateFromInt32(nUniqueList++);
1146     // --> OD 2008-06-04 #i86652#
1147 //    sal_uInt16 nRul = rDoc.MakeNumRule(rDoc.GetUniqueNumRuleName(&sPrefix));
1148     sal_uInt16 nRul =
1149             rDoc.MakeNumRule( rDoc.GetUniqueNumRuleName(&sPrefix), 0, sal_False,
1150                               SvxNumberFormat::LABEL_ALIGNMENT );
1151     // <--
1152     SwNumRule* pMyNumRule = rDoc.GetNumRuleTbl()[nRul];
1153     pMyNumRule->SetAutoRule(false);
1154     pMyNumRule->SetContinusNum(bSimple);
1155     return pMyNumRule;
1156 }
1157 
GetNumRule(sal_uInt16 i)1158 SwNumRule* WW8ListManager::GetNumRule(sal_uInt16 i)
1159 {
1160 	if ( i < maLSTInfos.size() )
1161 		return maLSTInfos[i]->pNumRule;
1162 	else
1163 		return 0;
1164 }
1165 
1166 // oeffentliche Methoden /////////////////////////////////////////////////////
1167 //
WW8ListManager(SvStream & rSt_,SwWW8ImplReader & rReader_)1168 WW8ListManager::WW8ListManager(
1169     SvStream& rSt_,
1170     SwWW8ImplReader& rReader_ )
1171     : maSprmParser( rReader_.GetFib().GetFIBVersion() )
1172     , rReader(rReader_)
1173     , rDoc(rReader.GetDoc())
1174     , rFib(rReader.GetFib())
1175     , rSt(rSt_)
1176     , maLSTInfos()
1177     , pLFOInfos( NULL )
1178     , nUniqueList( 1 )
1179     , maStyleInList()
1180 {
1181     // LST und LFO gibts erst ab WW8
1182     if(    ( 8 > rFib.nVersion )
1183             || ( rFib.fcPlcfLst == rFib.fcPlfLfo )
1184             || ( !rFib.lcbPlcfLst )
1185             || ( !rFib.lcbPlfLfo ) ) return; // offensichtlich keine Listen da
1186 
1187     // Arrays anlegen
1188     pLFOInfos = new WW8LFOInfos;
1189     bool bLVLOk = true;
1190     sal_uInt8  aBits1;
1191 
1192     nLastLFOPosition = USHRT_MAX;
1193     long nOriginalPos = rSt.Tell();
1194     //
1195     // 1. PLCF LST auslesen und die Listen Vorlagen im Writer anlegen
1196     //
1197     rSt.Seek( rFib.fcPlcfLst );
1198     sal_uInt16 nListCount;
1199     rSt >> nListCount;
1200     bool bOk = 0 < nListCount;
1201     if( bOk )
1202     {
1203         WW8LST aLST;
1204         //
1205         // 1.1 alle LST einlesen
1206         //
1207         for (sal_uInt16 nList=0; nList < nListCount; ++nList)
1208         {
1209             bOk = false;
1210             memset(&aLST, 0, sizeof( aLST ));
1211             sal_uInt16 nLevel;
1212             //
1213             // 1.1.1 Daten einlesen
1214             //
1215             rSt >> aLST.nIdLst;
1216             rSt >> aLST.nTplC;
1217             for (nLevel = 0; nLevel < nMaxLevel; ++nLevel)
1218                 rSt >> aLST.aIdSty[ nLevel ];
1219 
1220 
1221             rSt >> aBits1;
1222 
1223             rSt.SeekRel( 1 );
1224 
1225             if (rSt.GetError())
1226                 break;
1227 
1228             if( aBits1 & 0x01 )
1229                 aLST.bSimpleList = true;
1230             if( aBits1 & 0x02 )
1231                 aLST.bRestartHdn = true;
1232 
1233             // 1.1.2 new NumRule inserted in Doc and  WW8LSTInfo marked
1234 
1235             /*
1236             #i1869#
1237             In Word 2000 Microsoft got rid of creating new "simple lists" with
1238             only 1 level, all new lists are created with 9 levels. To hack it
1239             so that the list types formerly known as simple lists still have
1240             their own tab page to themselves one of the reserved bits is used
1241             to show that a given list is to be in the simple list tabpage.
1242             This has now nothing to do with the actual number of list level a
1243             list has, only how many will be shown in the user interface.
1244 
1245             i.e. create a simple list in 2000 and open it in 97 and 97 will
1246             claim (correctly) that it is an outline list. We can set our
1247             continuous flag in these lists to store this information.
1248             */
1249             SwNumRule* pMyNumRule = CreateNextRule(
1250                 aLST.bSimpleList || (aBits1 & 0x10));
1251 
1252             WW8LSTInfo* pLSTInfo = new WW8LSTInfo(pMyNumRule, aLST);
1253             maLSTInfos.push_back(pLSTInfo);
1254             bOk = true;
1255         }
1256     }
1257 
1258     if( bOk )
1259     {
1260         //
1261         // 1.2 alle LVL aller aLST einlesen
1262         //
1263         sal_uInt8 nLevel;
1264         sal_uInt16 nLSTInfos = static_cast< sal_uInt16 >(maLSTInfos.size());
1265         for (sal_uInt16 nList = 0; nList < nLSTInfos; ++nList)
1266         {
1267             bOk = false;
1268             WW8LSTInfo* pListInfo = maLSTInfos[nList];
1269             if( !pListInfo || !pListInfo->pNumRule ) break;
1270             SwNumRule& rMyNumRule = *pListInfo->pNumRule;
1271             //
1272             // 1.2.1 betreffende(n) LVL(s) fuer diese aLST einlesen
1273             //
1274             sal_uInt16 nLvlCount = static_cast< sal_uInt16 >(pListInfo->bSimpleList ? nMinLevel : nMaxLevel);
1275             std::deque<bool> aNotReallyThere;
1276             aNotReallyThere.resize(nMaxLevel);
1277             pListInfo->maParaSprms.resize(nMaxLevel);
1278             for (nLevel = 0; nLevel < nLvlCount; ++nLevel)
1279             {
1280                 SwNumFmt aNumFmt( rMyNumRule.Get( nLevel ) );
1281                 // LVLF einlesen
1282                 bLVLOk = ReadLVL( aNumFmt, pListInfo->aItemSet[nLevel],
1283                     pListInfo->aIdSty[nLevel], true, aNotReallyThere, nLevel,
1284                     pListInfo->maParaSprms[nLevel]);
1285                 if( !bLVLOk )
1286                     break;
1287                 // und in die rMyNumRule aufnehmen
1288                 rMyNumRule.Set( nLevel, aNumFmt );
1289             }
1290             if( !bLVLOk )
1291                 break;
1292             //
1293             // 1.2.2 die ItemPools mit den CHPx Einstellungen der verschiedenen
1294             //       Level miteinander vergleichen und ggfs. Style(s) erzeugen
1295             //
1296             bool bDummy;
1297             for (nLevel = 0; nLevel < nLvlCount; ++nLevel)
1298             {
1299                 AdjustLVL( nLevel, rMyNumRule, pListInfo->aItemSet,
1300                                                pListInfo->aCharFmt, bDummy );
1301             }
1302             //
1303             // 1.2.3 ItemPools leeren und loeschen
1304             //
1305             for (nLevel = 0; nLevel < nLvlCount; ++nLevel)
1306                 delete pListInfo->aItemSet[ nLevel ];
1307             bOk = true;
1308         }
1309     }
1310     if( !bOk )
1311     {
1312         // Fehler aufgetreten - LSTInfos abraeumen !!!
1313 
1314         ;
1315     }
1316 
1317     //
1318     // 2. PLF LFO auslesen und speichern
1319     //
1320     long nLfoCount(0);
1321     if (bOk)
1322     {
1323         rSt.Seek(rFib.fcPlfLfo);
1324         rSt >> nLfoCount;
1325         if (0 >= nLfoCount)
1326             bOk = false;
1327     }
1328 
1329     if(bOk)
1330     {
1331         WW8LFO aLFO;
1332         //
1333         // 2.1 alle LFO einlesen
1334         //
1335         for (sal_uInt16 nLfo = 0; nLfo < nLfoCount; ++nLfo)
1336         {
1337             bOk = false;
1338             memset(&aLFO, 0, sizeof( aLFO ));
1339             rSt >> aLFO.nIdLst;
1340             rSt.SeekRel( 8 );
1341             rSt >> aLFO.nLfoLvl;
1342             rSt.SeekRel( 3 );
1343             // soviele Overrides existieren
1344             if ((nMaxLevel < aLFO.nLfoLvl) || rSt.GetError())
1345                 break;
1346 
1347             // die Parent NumRule der entsprechenden Liste ermitteln
1348             WW8LSTInfo* pParentListInfo = GetLSTByListId(aLFO.nIdLst);
1349             if (pParentListInfo)
1350             {
1351                 // hier, im ersten Schritt, erst mal diese NumRule festhalten
1352                 aLFO.pNumRule = pParentListInfo->pNumRule;
1353 
1354                 // hat die Liste mehrere Level ?
1355                 aLFO.bSimpleList = pParentListInfo->bSimpleList;
1356             }
1357             // und rein ins Merk-Array mit dem Teil
1358             WW8LFOInfo* pLFOInfo = new WW8LFOInfo(aLFO);
1359             if ( pParentListInfo != NULL )
1360             {
1361                 // Copy the basic paragraph properties for each level from the
1362                 // original list into the list format override levels.
1363                 int nMaxSize = pParentListInfo->maParaSprms.size();
1364                 pLFOInfo->maParaSprms.resize(nMaxSize);
1365                 for (int i = 0; i < nMaxSize; ++i)
1366                 {
1367                     pLFOInfo->maParaSprms[i] = pParentListInfo->maParaSprms[i];
1368                 }
1369 
1370                 const sal_uInt16 nLFOInfoArrayPos = pLFOInfos->Count();
1371                 for ( sal_uInt8 j = 0 ; j < nMaxLevel; ++j )
1372                 {
1373                     maStyleInList[pParentListInfo->aIdSty[j]] = nLFOInfoArrayPos;
1374                 }
1375             }
1376             pLFOInfos->Insert( pLFOInfo, pLFOInfos->Count() );
1377             bOk = true;
1378         }
1379     }
1380     if( bOk )
1381     {
1382         //
1383         // 2.2 fuer alle LFO die zugehoerigen LFOLVL einlesen
1384         //
1385         sal_uInt16 nLFOInfos = pLFOInfos ? pLFOInfos->Count() : 0;
1386         for (sal_uInt16 nLfo = 0; nLfo < nLFOInfos; ++nLfo)
1387         {
1388             bOk = false;
1389             WW8LFOInfo* pLFOInfo = pLFOInfos->GetObject( nLfo );
1390             if (!pLFOInfo)
1391                 break;
1392             // stehen hierfuer ueberhaupt LFOLVL an ?
1393             if( pLFOInfo->bOverride )
1394             {
1395                 WW8LSTInfo* pParentListInfo = GetLSTByListId(pLFOInfo->nIdLst);
1396                 if (!pParentListInfo) //e.g. #112324#
1397                     break;
1398                 //
1399                 // 2.2.1 eine neue NumRule fuer diese Liste anlegen
1400                 //
1401                 SwNumRule* pParentNumRule = pLFOInfo->pNumRule;
1402                 ASSERT(pParentNumRule, "ww: Impossible lists, please report");
1403                 if( !pParentNumRule )
1404                     break;
1405                 // Nauemsprefix aufbauen: fuer NumRule-Name (eventuell)
1406                 // und (falls vorhanden) fuer Style-Name (dann auf jeden Fall)
1407                 String sPrefix(CREATE_CONST_ASC( "WW8NumSt" ));
1408                 sPrefix += String::CreateFromInt32( nLfo + 1 );
1409                 // jetzt dem pNumRule seinen RICHTIGEN Wert zuweisen !!!
1410                 // (bis dahin war hier die Parent NumRule vermerkt )
1411                 //
1412                 // Dazu erst mal nachsehen, ob ein Style diesen LFO
1413                 // referenziert:
1414                 if( USHRT_MAX > rReader.StyleUsingLFO( nLfo ) )
1415                 {
1416                     sal_uInt16 nRul = rDoc.MakeNumRule(
1417                         rDoc.GetUniqueNumRuleName( &sPrefix ), pParentNumRule);
1418                     pLFOInfo->pNumRule = rDoc.GetNumRuleTbl()[ nRul ];
1419                     pLFOInfo->pNumRule->SetAutoRule(false);
1420                 }
1421                 else
1422                 {
1423                     sal_uInt16 nRul = rDoc.MakeNumRule(
1424                         rDoc.GetUniqueNumRuleName(), pParentNumRule);
1425                     pLFOInfo->pNumRule = rDoc.GetNumRuleTbl()[ nRul ];
1426                     pLFOInfo->pNumRule->SetAutoRule(true);  // = default
1427                 }
1428                 //
1429                 // 2.2.2 alle LFOLVL (und ggfs. LVL) fuer die neue NumRule
1430                 // einlesen
1431                 //
1432                 WW8aISet aItemSet;       // Zeichenattribute aus GrpprlChpx
1433                 WW8aCFmt aCharFmt;       // Zeichen Style Pointer
1434                 memset(&aItemSet, 0,  sizeof( aItemSet ));
1435                 memset(&aCharFmt, 0,  sizeof( aCharFmt ));
1436 
1437                 //2.2.2.0 skip inter-group of override header ?
1438                 //See #i25438# for why I moved this here, compare
1439                 //that original bugdoc's binary to what it looks like
1440                 //when resaved with Word, i.e. there is always a
1441                 //4 byte header, there might be more than one if
1442                 //that header was 0xFFFFFFFF, e.g. #114412# ?
1443                 sal_uInt32 nTest;
1444                 rSt >> nTest;
1445                 do
1446                     rSt >> nTest;
1447                 while (nTest == 0xFFFFFFFF);
1448                 rSt.SeekRel(-4);
1449 
1450                 std::deque<bool> aNotReallyThere(WW8ListManager::nMaxLevel);
1451                 sal_uInt8 nLevel = 0;
1452                 for (nLevel = 0; nLevel < pLFOInfo->nLfoLvl; ++nLevel)
1453                 {
1454                     WW8LFOLVL aLFOLVL;
1455                     bLVLOk = false;
1456 
1457                     //
1458                     // 2.2.2.1 den LFOLVL einlesen
1459                     //
1460                     rSt >> aLFOLVL.nStartAt;
1461                     rSt >> aBits1;
1462                     rSt.SeekRel( 3 );
1463                     if (rSt.GetError())
1464                         break;
1465 
1466                     // beachte: Die Witzbolde bei MS quetschen die
1467                     // Override-Level-Nummer in vier Bits hinein, damit sie
1468                     // wieder einen Grund haben, ihr Dateiformat zu aendern,
1469                     // falls ihnen einfaellt, dass sie eigentlich doch gerne
1470                     // bis zu 16 Listen-Level haetten.  Wir tun das *nicht*
1471                     // (siehe Kommentar oben bei "struct
1472                     // WW8LFOInfo")
1473                     aLFOLVL.nLevel = aBits1 & 0x0F;
1474                     if( (0xFF > aBits1) &&
1475                         (nMaxLevel > aLFOLVL.nLevel) )
1476                     {
1477                         if (aBits1 & 0x10)
1478                             aLFOLVL.bStartAt = true;
1479                         else
1480                             aLFOLVL.bStartAt = false;
1481                         //
1482                         // 2.2.2.2 eventuell auch den zugehoerigen LVL einlesen
1483                         //
1484                         SwNumFmt aNumFmt(
1485                             pLFOInfo->pNumRule->Get(aLFOLVL.nLevel));
1486                         if (aBits1 & 0x20)
1487                         {
1488                             aLFOLVL.bFormat = true;
1489                             // falls bStartup true, hier den Startup-Level
1490                             // durch den im LVL vermerkten ersetzen LVLF
1491                             // einlesen
1492                             bLVLOk = ReadLVL(aNumFmt, aItemSet[nLevel],
1493                                 pParentListInfo->aIdSty[nLevel],
1494                                 aLFOLVL.bStartAt, aNotReallyThere, nLevel,
1495                                 pLFOInfo->maParaSprms[nLevel]);
1496 
1497                             if (!bLVLOk)
1498                                 break;
1499                         }
1500                         else if (aLFOLVL.bStartAt)
1501                         {
1502                             aNumFmt.SetStart(
1503                                 writer_cast<sal_uInt16>(aLFOLVL.nStartAt));
1504                         }
1505                         //
1506                         // 2.2.2.3 das NumFmt in die NumRule aufnehmen
1507                         //
1508                         pLFOInfo->pNumRule->Set(aLFOLVL.nLevel, aNumFmt);
1509                     }
1510                     bLVLOk = true;
1511 
1512                     if (nMaxLevel > aLFOLVL.nLevel)
1513                         pLFOInfo->maOverrides[aLFOLVL.nLevel] = aLFOLVL;
1514                 }
1515                 if( !bLVLOk )
1516                     break;
1517                 //
1518                 // 2.2.3 die LVL der neuen NumRule anpassen
1519                 //
1520                 sal_uInt16 aFlagsNewCharFmt = 0;
1521                 bool bNewCharFmtCreated = false;
1522                 for (nLevel = 0; nLevel < pLFOInfo->nLfoLvl; ++nLevel)
1523                 {
1524                     AdjustLVL( nLevel, *pLFOInfo->pNumRule, aItemSet, aCharFmt,
1525                         bNewCharFmtCreated, sPrefix );
1526                     if( bNewCharFmtCreated )
1527                         aFlagsNewCharFmt += (1 << nLevel);
1528                 }
1529                 //
1530                 // 2.2.4 ItemPools leeren und loeschen
1531                 //
1532                 for (nLevel = 0; nLevel < pLFOInfo->nLfoLvl; ++nLevel)
1533                     delete aItemSet[ nLevel ];
1534                 bOk = true;
1535             }
1536         }
1537     }
1538     if( !bOk )
1539     {
1540         // Fehler aufgetreten - LSTInfos und LFOInfos abraeumen !!!
1541         ;
1542     }
1543     // und schon sind wir fertig!
1544     rSt.Seek( nOriginalPos );
1545 }
1546 
~WW8ListManager()1547 WW8ListManager::~WW8ListManager()
1548 {
1549     /*
1550     named lists remain in doc!!!
1551     unnamed lists are deleted when unused
1552     pLFOInfos are in any case destructed
1553     */
1554     for(std::vector<WW8LSTInfo *>::iterator aIter = maLSTInfos.begin();
1555         aIter != maLSTInfos.end(); ++aIter)
1556     {
1557         if ((*aIter)->pNumRule && !(*aIter)->bUsedInDoc &&
1558             (*aIter)->pNumRule->IsAutoRule())
1559         {
1560             rDoc.DelNumRule((*aIter)->pNumRule->GetName());
1561         }
1562         delete *aIter;
1563     }
1564 
1565     if (pLFOInfos)
1566     {
1567         for(sal_uInt16 nInfo = pLFOInfos->Count(); nInfo; )
1568         {
1569             WW8LFOInfo *pActInfo = pLFOInfos->GetObject(--nInfo);
1570             if (pActInfo->bOverride && pActInfo->pNumRule
1571                 && !pActInfo->bUsedInDoc && pActInfo->pNumRule->IsAutoRule())
1572             {
1573                 rDoc.DelNumRule( pActInfo->pNumRule->GetName() );
1574             }
1575         }
1576         delete pLFOInfos;
1577     }
1578 }
1579 
GetPossibleLFOPosition(const sal_uInt16 nStyleID,const sal_uInt8 nGivenListLevel)1580 sal_uInt16 WW8ListManager::GetPossibleLFOPosition(
1581     const sal_uInt16 nStyleID,
1582     const sal_uInt8 nGivenListLevel )
1583 {
1584     sal_uInt16 nPossibleLFOPosition = USHRT_MAX;
1585 
1586     StyleInList::iterator aItr = maStyleInList.find( nStyleID );
1587     if ( aItr != maStyleInList.end()
1588          && aItr->second < pLFOInfos->Count() )
1589     {
1590         WW8LFOInfo* pLFOInfo = pLFOInfos->GetObject( aItr->second );
1591         WW8LSTInfo* pParentListInfo = GetLSTByListId( pLFOInfo->nIdLst );
1592         if ( pParentListInfo != NULL
1593              && pParentListInfo->aIdSty[nGivenListLevel] == nStyleID )
1594         {
1595             nPossibleLFOPosition = aItr->second;
1596         }
1597     }
1598 
1599     return nPossibleLFOPosition;
1600 }
1601 
1602 
IsEqualFormatting(const SwNumRule & rOne,const SwNumRule & rTwo)1603 bool IsEqualFormatting(const SwNumRule &rOne, const SwNumRule &rTwo)
1604 {
1605     bool bRet =
1606         (
1607           rOne.GetRuleType() == rTwo.GetRuleType() &&
1608           rOne.IsContinusNum() == rTwo.IsContinusNum() &&
1609           rOne.IsAbsSpaces() == rTwo.IsAbsSpaces() &&
1610           rOne.GetPoolFmtId() == rTwo.GetPoolFmtId() &&
1611           rOne.GetPoolHelpId() == rTwo.GetPoolHelpId() &&
1612           rTwo.GetPoolHlpFileId() == rTwo.GetPoolHlpFileId()
1613         );
1614 
1615     if (bRet)
1616     {
1617         for (sal_uInt8 n = 0; n < MAXLEVEL; ++n )
1618         {
1619             // The SvxNumberFormat compare, not the SwNumFmt compare
1620             const SvxNumberFormat &rO = rOne.Get(n);
1621             const SvxNumberFormat &rT = rTwo.Get(n);
1622             if (!(rO == rT))
1623             {
1624                 bRet = false;
1625                 break;
1626             }
1627         }
1628     }
1629     return bRet;
1630 }
1631 
GetNumRuleForActivation(sal_uInt16 nLFOPosition,const sal_uInt8 nLevel,std::vector<sal_uInt8> & rParaSprms,SwTxtNode * pNode)1632 SwNumRule* WW8ListManager::GetNumRuleForActivation(sal_uInt16 nLFOPosition,
1633     const sal_uInt8 nLevel, std::vector<sal_uInt8> &rParaSprms, SwTxtNode *pNode)
1634 {
1635     sal_uInt16 nLFOInfos = pLFOInfos ? pLFOInfos->Count() : 0;
1636     if( nLFOInfos <= nLFOPosition )
1637         return 0;
1638 
1639     WW8LFOInfo* pLFOInfo = pLFOInfos->GetObject( nLFOPosition );
1640 
1641     if( !pLFOInfo )
1642         return 0;
1643 
1644     bool bFirstUse = !pLFOInfo->bUsedInDoc;
1645     pLFOInfo->bUsedInDoc = true;
1646 
1647     if( !pLFOInfo->pNumRule )
1648         return 0;
1649 
1650     // #i25545#
1651     // --> OD 2009-03-12 #i100132# - a number format does not have to exist on given list level
1652 //    SwNumFmt pFmt(*(pLFOInfo->pNumRule->GetNumFmt(nLevel)));
1653     SwNumFmt pFmt(pLFOInfo->pNumRule->Get(nLevel));
1654     // <--
1655     if (rReader.IsRightToLeft() && nLastLFOPosition != nLFOPosition) {
1656         if ( pFmt.GetNumAdjust() == SVX_ADJUST_RIGHT)
1657             pFmt.SetNumAdjust(SVX_ADJUST_LEFT);
1658         else if ( pFmt.GetNumAdjust() == SVX_ADJUST_LEFT)
1659             pFmt.SetNumAdjust(SVX_ADJUST_RIGHT);
1660         pLFOInfo->pNumRule->Set(nLevel, pFmt);
1661     }
1662     nLastLFOPosition = nLFOPosition;
1663     /*
1664     #i1869#
1665     If this list has had its bits set in Word 2000 to pretend that it is a
1666     simple list from the point of view of the user, then it is almost
1667     certainly a simple continuous list, and we will try to keep it like that.
1668     Otherwise when we save again it will be shown as the true outline list
1669     that it is, confusing the user that just wanted what they thought was a
1670     simple list. On the other hand it is possible that some of the other levels
1671     were used by the user, in which case we will not pretend anymore that it
1672     is a simple list. Something that Word 2000 does anyway, that 97 didn't, to
1673     my bewilderment.
1674     */
1675     if (nLevel && pLFOInfo->pNumRule->IsContinusNum())
1676         pLFOInfo->pNumRule->SetContinusNum(false);
1677 
1678     if( (!pLFOInfo->bOverride) && (!pLFOInfo->bLSTbUIDSet) )
1679     {
1680         WW8LSTInfo* pParentListInfo = GetLSTByListId( pLFOInfo->nIdLst );
1681         if( pParentListInfo )
1682             pParentListInfo->bUsedInDoc = true;
1683         pLFOInfo->bLSTbUIDSet = true;
1684     }
1685 
1686     if (pLFOInfo->maParaSprms.size() > nLevel)
1687         rParaSprms = pLFOInfo->maParaSprms[nLevel];
1688 
1689     SwNumRule *pRet = pLFOInfo->pNumRule;
1690 
1691     bool bRestart(false);
1692     sal_uInt16 nStart(0);
1693     bool bNewstart(false);
1694     /*
1695       Note: If you fiddle with this then you have to make sure that #i18322#
1696       #i13833#, #i20095# and #112466# continue to work
1697 
1698       Check if there were overrides for this level
1699     */
1700     if (pLFOInfo->bOverride && nLevel < pLFOInfo->nLfoLvl)
1701     {
1702         WW8LSTInfo* pParentListInfo = GetLSTByListId(pLFOInfo->nIdLst);
1703         ASSERT(pParentListInfo, "ww: Impossible lists, please report");
1704         if (pParentListInfo && pParentListInfo->pNumRule)
1705         {
1706             const WW8LFOLVL &rOverride = pLFOInfo->maOverrides[nLevel];
1707             bool bNoChangeFromParent =
1708                 IsEqualFormatting(*pRet, *(pParentListInfo->pNumRule));
1709 
1710             // If so then I think Word still uses the parent (maybe)
1711             if (bNoChangeFromParent)
1712             {
1713                 pRet = pParentListInfo->pNumRule;
1714 
1715                 //did it not affect start at value ?
1716                 if (bFirstUse)
1717                 {
1718                     if (rOverride.bStartAt)
1719                     {
1720                         const SwNumFmt &rFmt =
1721                             pParentListInfo->pNumRule->Get(nLevel);
1722                         if (
1723                              rFmt.GetStart() ==
1724                              pLFOInfo->maOverrides[nLevel].nStartAt
1725                            )
1726                         {
1727                             bRestart = true;
1728                         }
1729                         else
1730                         {
1731                             bNewstart = true;
1732                             nStart = writer_cast<sal_uInt16>
1733                                 (pLFOInfo->maOverrides[nLevel].nStartAt);
1734                         }
1735                     }
1736                 }
1737 
1738                 pParentListInfo->bUsedInDoc = true;
1739             }
1740         }
1741     }
1742 
1743     if (pNode)
1744     {
1745         pNode->SetAttrListLevel(nLevel);
1746 
1747         if (bRestart || bNewstart) // #112466# (I think)
1748             pNode->SetListRestart(true);
1749         if (bNewstart)
1750             pNode->SetAttrListRestartValue(nStart);
1751     }
1752     return pRet;
1753 }
1754 
1755 
1756 //----------------------------------------------------------------------------
1757 //          SwWW8ImplReader:  anhaengen einer Liste an einen Style oder Absatz
1758 //----------------------------------------------------------------------------
SetTxtFmtCollAndListLevel(const SwPaM & rRg,SwWW8StyInf & rStyleInfo)1759 bool SwWW8ImplReader::SetTxtFmtCollAndListLevel(
1760     const SwPaM& rRg,
1761     SwWW8StyInf& rStyleInfo)
1762 {
1763     bool bRes = true;
1764     if( rStyleInfo.pFmt && rStyleInfo.bColl )
1765     {
1766         bRes = rDoc.SetTxtFmtColl(rRg, (SwTxtFmtColl*)rStyleInfo.pFmt) ? true : false;
1767         SwTxtNode* pTxtNode = pPaM->GetNode()->GetTxtNode();
1768         ASSERT( pTxtNode != NULL, "No Text-Node at PaM-Position" );
1769         if ( pTxtNode == NULL )
1770         {
1771             // make code robust
1772             return bRes;
1773         }
1774 
1775         const SwNumRule * pNumRule = pTxtNode->GetNumRule(); // #i27610#
1776 
1777         if( !IsInvalidOrToBeMergedTabCell()
1778             && ! (pNumRule && pNumRule->IsOutlineRule()) ) // #i27610#
1779         {
1780             pTxtNode->ResetAttr( RES_PARATR_NUMRULE );
1781         }
1782 
1783         if ( USHRT_MAX > rStyleInfo.nLFOIndex
1784              && WW8ListManager::nMaxLevel > rStyleInfo.nListLevel )
1785         {
1786             const bool bApplyListStyle = false;
1787             RegisterNumFmtOnTxtNode( rStyleInfo.nLFOIndex, rStyleInfo.nListLevel, bApplyListStyle );
1788         }
1789     }
1790     return bRes;
1791 }
1792 
UseListIndent(SwWW8StyInf & rStyle,const SwNumFmt & rFmt)1793 void UseListIndent(SwWW8StyInf &rStyle, const SwNumFmt &rFmt)
1794 {
1795     if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
1796     {
1797         const long nAbsLSpace = rFmt.GetAbsLSpace();
1798         const long nListFirstLineIndent = GetListFirstLineIndent(rFmt);
1799         SvxLRSpaceItem aLR(ItemGet<SvxLRSpaceItem>(*rStyle.pFmt, RES_LR_SPACE));
1800         aLR.SetTxtLeft(nAbsLSpace);
1801         aLR.SetTxtFirstLineOfst(writer_cast<short>(nListFirstLineIndent));
1802         rStyle.pFmt->SetFmtAttr(aLR);
1803         rStyle.bListReleventIndentSet = true;
1804     }
1805 }
1806 
SetStyleIndent(SwWW8StyInf & rStyle,const SwNumFmt & rFmt)1807 void SetStyleIndent(SwWW8StyInf &rStyle, const SwNumFmt &rFmt)
1808 {
1809     if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
1810     {
1811         SvxLRSpaceItem aLR(ItemGet<SvxLRSpaceItem>(*rStyle.pFmt, RES_LR_SPACE));
1812         if (rStyle.bListReleventIndentSet)
1813         {
1814             SyncIndentWithList( aLR, rFmt, false, false );
1815         }
1816         else
1817         {
1818             aLR.SetTxtLeft(0);
1819             aLR.SetTxtFirstLineOfst(0);
1820         }
1821         rStyle.pFmt->SetFmtAttr(aLR);
1822     }
1823 }
1824 
SetStylesList(sal_uInt16 nStyle,sal_uInt16 nActLFO,sal_uInt8 nActLevel)1825 void SwWW8ImplReader::SetStylesList(
1826     sal_uInt16 nStyle,
1827     sal_uInt16 nActLFO,
1828     sal_uInt8 nActLevel)
1829 {
1830     SwWW8StyInf &rStyleInf = pCollA[nStyle];
1831     if (rStyleInf.bValid)
1832     {
1833         ASSERT(pAktColl, "Cannot be called outside of style import");
1834         // Phase 1: Nummerierungsattribute beim Einlesen einer StyleDef
1835         if( pAktColl )
1836         {
1837             // jetzt nur die Parameter vermerken: die tatsaechliche Liste wird
1838             // spaeter drangehaengt, wenn die Listendefinitionen gelesen sind...
1839             if (
1840                  (USHRT_MAX > nActLFO) &&
1841                  (WW8ListManager::nMaxLevel > nActLevel)
1842                )
1843             {
1844                 rStyleInf.nLFOIndex = nActLFO;
1845                 rStyleInf.nListLevel = nActLevel;
1846 
1847                 if (
1848                     (USHRT_MAX > nActLFO) &&
1849                     (WW8ListManager::nMaxLevel > nActLevel)
1850                    )
1851                 {
1852                     std::vector<sal_uInt8> aParaSprms;
1853                     SwNumRule *pNmRule =
1854                         pLstManager->GetNumRuleForActivation(nActLFO,
1855                             nActLevel, aParaSprms);
1856                     if (pNmRule)
1857                         UseListIndent(rStyleInf, pNmRule->Get(nActLevel));
1858                 }
1859             }
1860         }
1861     }
1862 }
1863 
RegisterNumFmtOnStyle(sal_uInt16 nStyle)1864 void SwWW8ImplReader::RegisterNumFmtOnStyle( sal_uInt16 nStyle )
1865 {
1866     SwWW8StyInf &rStyleInf = pCollA[nStyle];
1867     if (rStyleInf.bValid && rStyleInf.pFmt)
1868     {
1869         // Save old pre-list modified indent, which are the word indent values
1870         rStyleInf.maWordLR =
1871             ItemGet<SvxLRSpaceItem>(*rStyleInf.pFmt, RES_LR_SPACE);
1872 
1873         // Phase 2: aktualisieren der StyleDef nach einlesen aller Listen
1874         SwNumRule* pNmRule = 0;
1875         const sal_uInt16 nLFO = rStyleInf.nLFOIndex;
1876         const sal_uInt8 nLevel = rStyleInf.nListLevel;
1877         if (
1878              (USHRT_MAX > nLFO) &&
1879              (WW8ListManager::nMaxLevel > nLevel)
1880            )
1881         {
1882             std::vector<sal_uInt8> aParaSprms;
1883             pNmRule =
1884                 pLstManager->GetNumRuleForActivation( nLFO, nLevel, aParaSprms );
1885 
1886             if ( pNmRule != NULL )
1887             {
1888                 if ( rStyleInf.IsWW8BuiltInHeadingStyle()
1889                      && rStyleInf.HasWW8OutlineLevel() )
1890                 {
1891                     rStyleInf.pOutlineNumrule = pNmRule;
1892                 }
1893                 else
1894                 {
1895                     rStyleInf.pFmt->SetFmtAttr( SwNumRuleItem( pNmRule->GetName() ) );
1896                     rStyleInf.bHasStyNumRule = true;
1897                 }
1898             }
1899         }
1900 
1901         if (pNmRule)
1902             SetStyleIndent(rStyleInf, pNmRule->Get(nLevel));
1903     }
1904 }
1905 
RegisterNumFmtOnTxtNode(sal_uInt16 nActLFO,sal_uInt8 nActLevel,const bool bSetAttr)1906 void SwWW8ImplReader::RegisterNumFmtOnTxtNode(
1907     sal_uInt16 nActLFO,
1908     sal_uInt8 nActLevel,
1909     const bool bSetAttr)
1910 {
1911     // beachte: die Methode haengt die NumRule an den Text Node, falls
1912     // bSetAttr (dann muessen natuerlich vorher die Listen gelesen sein)
1913     // stellt sie NUR den Level ein, im Vertrauen darauf, dass am STYLE eine
1914     // NumRule haengt - dies wird NICHT ueberprueft !!!
1915 
1916     if (pLstManager) // sind die Listendeklarationen gelesen?
1917     {
1918         std::vector<sal_uInt8> aParaSprms;
1919         SwTxtNode* pTxtNd = pPaM->GetNode()->GetTxtNode();
1920         ASSERT(pTxtNd, "Kein Text-Node an PaM-Position");
1921 
1922         const SwNumRule* pRule =
1923             bSetAttr
1924             ? pLstManager->GetNumRuleForActivation( nActLFO, nActLevel, aParaSprms, pTxtNd)
1925             : 0;
1926 
1927         if ( pRule != NULL || !bSetAttr)
1928         {
1929             if ( bSetAttr
1930                  && pTxtNd->GetNumRule() != pRule
1931                  && pTxtNd->GetNumRule() != rDoc.GetOutlineNumRule() )
1932             {
1933                 pTxtNd->SetAttr( SwNumRuleItem( pRule->GetName() ) );
1934             }
1935 
1936             pTxtNd->SetAttrListLevel(nActLevel);
1937             // - <IsCounted()> state of text node has to be adjusted accordingly.
1938             if ( /*nActLevel >= 0 &&*/ nActLevel < MAXLEVEL )
1939             {
1940                 pTxtNd->SetCountedInList( true );
1941             }
1942 
1943             // Direct application of the list level formatting no longer
1944             // needed for list levels of mode LABEL_ALIGNMENT
1945             bool bApplyListLevelIndentDirectlyAtPara( true );
1946             {
1947                 if ( pTxtNd->GetNumRule() && nActLevel < MAXLEVEL )
1948                 {
1949                     const SwNumFmt& rFmt = pTxtNd->GetNumRule()->Get( nActLevel );
1950                     if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1951                     {
1952                         bApplyListLevelIndentDirectlyAtPara = false;
1953                     }
1954                 }
1955             }
1956             if ( bApplyListLevelIndentDirectlyAtPara )
1957             {
1958                 SfxItemSet aListIndent(rDoc.GetAttrPool(), RES_LR_SPACE,
1959                         RES_LR_SPACE);
1960                 const SvxLRSpaceItem *pItem = (const SvxLRSpaceItem*)(
1961                     GetFmtAttr(RES_LR_SPACE));
1962                 ASSERT(pItem, "impossible");
1963                 if (pItem)
1964                     aListIndent.Put(*pItem);
1965 
1966                 /*
1967                  Take the original paragraph sprms attached to this list level
1968                  formatting and apply them to the paragraph. I'm convinced that
1969                  this is exactly what Word does.
1970                 */
1971                 if (short nLen = static_cast< short >(aParaSprms.size()))
1972                 {
1973                     SfxItemSet* pOldAktItemSet = pAktItemSet;
1974                     SetAktItemSet(&aListIndent);
1975 
1976                     sal_uInt8* pSprms1 = &aParaSprms[0];
1977                     while (0 < nLen)
1978                     {
1979                         sal_uInt16 nL1 = ImportSprm(pSprms1);
1980                         nLen = nLen - nL1;
1981                         pSprms1 += nL1;
1982                     }
1983 
1984                     SetAktItemSet(pOldAktItemSet);
1985                 }
1986 
1987                 const SvxLRSpaceItem *pLR =
1988                     HasItem<SvxLRSpaceItem>(aListIndent, RES_LR_SPACE);
1989                 ASSERT(pLR, "Impossible");
1990                 if (pLR)
1991                 {
1992                     pCtrlStck->NewAttr(*pPaM->GetPoint(), *pLR);
1993                     pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_LR_SPACE);
1994                 }
1995             }
1996         }
1997     }
1998 }
1999 
RegisterNumFmt(sal_uInt16 nActLFO,sal_uInt8 nActLevel)2000 void SwWW8ImplReader::RegisterNumFmt(sal_uInt16 nActLFO, sal_uInt8 nActLevel)
2001 {
2002     // sind wir erst beim Einlesen der StyleDef ?
2003     if (pAktColl)
2004         SetStylesList( nAktColl , nActLFO, nActLevel);
2005     else
2006         RegisterNumFmtOnTxtNode(nActLFO, nActLevel);
2007 }
2008 
Read_ListLevel(sal_uInt16,const sal_uInt8 * pData,short nLen)2009 void SwWW8ImplReader::Read_ListLevel(sal_uInt16, const sal_uInt8* pData,
2010     short nLen)
2011 {
2012     if (pPlcxMan && pPlcxMan->GetDoingDrawTextBox())
2013         return;
2014 
2015     if( nLen < 0 )
2016     {
2017         // aktuelle Liste ist hier zu Ende, was ist zu tun ???
2018         nListLevel = WW8ListManager::nMaxLevel;
2019         if (pStyles && !bVer67)
2020             pStyles->nWwNumLevel = 0;
2021     }
2022     else
2023     {
2024         // Sicherheitspruefung auf NIL Pointer
2025         if( !pData ) return;
2026         // die Streamdaten sind hier Null basiert, so wie wir es brauchen
2027         nListLevel = *pData;
2028 
2029         if (pStyles && !bVer67)
2030         {
2031             /*
2032             #94672#
2033             if this is the case, then if the numbering is actually stored in
2034             WinWord 6 format, and its likely that sprmPIlvl has been abused
2035             to set the ww6 list level information which we will need when we
2036             reach the true ww6 list def. So set it now
2037             */
2038             pStyles->nWwNumLevel = nListLevel;
2039         }
2040 
2041         if (WW8ListManager::nMaxLevel <= nListLevel )
2042         {
2043             // handle invalid list level value by reseting it
2044             nListLevel = WW8ListManager::nMaxLevel;
2045         }
2046         else if ( nLFOPosition < USHRT_MAX
2047                   && nListLevel < WW8ListManager::nMaxLevel )
2048         {
2049             RegisterNumFmt( nLFOPosition, nListLevel );
2050             // reset kept list attributes
2051             nLFOPosition = USHRT_MAX;
2052             nListLevel  = WW8ListManager::nMaxLevel;
2053         }
2054         else if ( pLstManager != NULL
2055                   && pAktColl != NULL )
2056         {
2057             const sal_uInt16 nPossibleLFOPosition =
2058                 pLstManager->GetPossibleLFOPosition( nAktColl, nListLevel );
2059             if ( nPossibleLFOPosition < USHRT_MAX )
2060             {
2061                 // temporary register Style without reseting kept list attributes
2062                 RegisterNumFmt( nPossibleLFOPosition, nListLevel );
2063             }
2064         }
2065     }
2066 }
2067 
Read_LFOPosition(sal_uInt16,const sal_uInt8 * pData,short nLen)2068 void SwWW8ImplReader::Read_LFOPosition(
2069     sal_uInt16,
2070     const sal_uInt8* pData,
2071     short nLen)
2072 {
2073     if (pPlcxMan && pPlcxMan->GetDoingDrawTextBox())
2074         return;
2075 
2076     if( nLen < 0 )
2077     {
2078         // aktueller Level ist hier zu Ende, was ist zu tun ???
2079         nLFOPosition = USHRT_MAX;
2080         nListLevel = WW8ListManager::nMaxLevel;
2081     }
2082     else
2083     {
2084         // Sicherheitspruefung auf NIL Pointer
2085         if( !pData )
2086             return;
2087         short nData = SVBT16ToShort( pData );
2088         if( 0 >= nData )
2089         {
2090             /*
2091             #94672# discussion
2092             If you have a paragraph in Word with left and/or hanging indent
2093             and remove its numbering, then the indentation appears to get
2094             reset, but not back to the base style, instead its goes to a blank
2095             setting.
2096             Unless its a broken ww6 list in 97 in which case more hackery is
2097             required, some more details about that in
2098             ww8par6.cxx#SwWW8ImplReader::Read_LR
2099             */
2100 
2101             if (pAktColl)
2102             {
2103                 pAktColl->SetFmtAttr(*GetDfltAttr( RES_PARATR_NUMRULE));
2104                 pAktColl->SetFmtAttr(SvxLRSpaceItem(RES_LR_SPACE)); // #94672#
2105             }
2106             else if (SwTxtNode* pTxtNode = pPaM->GetNode()->GetTxtNode())
2107             {
2108                 pTxtNode->ResetAttr( RES_PARATR_NUMRULE );
2109                 pTxtNode->SetCountedInList(false);
2110 
2111                 /*
2112                 #i24553#
2113                 Hmm, I can't remove outline numbering on a per txtnode basis,
2114                 but I can set some normal numbering, and that overrides outline
2115                 numbering, and then I can say when I come to say that I want no
2116                 number on the normal numbering rule, that should all work out
2117 
2118                 #115901#
2119                 No special outline number in textnode any more
2120                 */
2121                 if (pTxtNode->IsOutline())
2122                 {
2123                     // Assure that the numbering rule, which is retrieved at
2124                     // the paragraph is the outline numbering rule, instead of
2125                     // incorrectly setting the chosen outline rule.
2126                     // Note: The chosen outline rule doesn't have to correspond
2127                     //       to the outline rule
2128                     if ( pTxtNode->GetNumRule() != rDoc.GetOutlineNumRule() )
2129                     {
2130                         pTxtNode->SetAttr(
2131                             SwNumRuleItem( rDoc.GetOutlineNumRule()->GetName() ) );
2132                     }
2133                 }
2134 
2135                 //#94672#
2136                 pCtrlStck->NewAttr(*pPaM->GetPoint(), SvxLRSpaceItem(RES_LR_SPACE));
2137                 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_LR_SPACE);
2138             }
2139             nLFOPosition = USHRT_MAX;
2140         }
2141         else
2142         {
2143             nLFOPosition = (sal_uInt16)nData-1;
2144             /*
2145             #94672#
2146             If we are a ww8+ style with ww7- style lists then there is a
2147             bizarre broken Word bug where when the list is removed from a para
2148             the ww6 list first line indent still affects the first line
2149             indentation. Setting this flag will allow us to recover from this
2150             braindeadness
2151             */
2152             if ( pAktColl
2153                  && (nLFOPosition == 2047-1) )
2154             {
2155                 pCollA[nAktColl].bHasBrokenWW6List = true;
2156             }
2157 
2158             // die Streamdaten sind hier 1 basiert, wir ziehen EINS ab
2159             if (USHRT_MAX > nLFOPosition)
2160             {
2161                 if (nLFOPosition != 2047-1) // Normal ww8+ list behavior
2162                 {
2163                     if ( nListLevel == WW8ListManager::nMaxLevel )
2164                     {
2165                         nListLevel = 0;
2166                         if ( pAktColl != NULL )
2167                         {
2168                             // temporary register Style without reseting kept list attributes
2169                             RegisterNumFmt( nLFOPosition, nListLevel );
2170                         }
2171                     }
2172                     else if (WW8ListManager::nMaxLevel > nListLevel)
2173                     {
2174                         RegisterNumFmt(nLFOPosition, nListLevel);
2175                         // reset kept list attributes
2176                         nLFOPosition = USHRT_MAX;
2177                         nListLevel = WW8ListManager::nMaxLevel;
2178                     }
2179                 }
2180                 else if (pPlcxMan && pPlcxMan->HasParaSprm(0xC63E))
2181                 {
2182                     /*
2183                      #i8114# Horrific backwards compatible ww7- lists in ww8+ docs
2184                     */
2185                     Read_ANLevelNo(13 /*equiv ww7- sprm no*/, &nListLevel, 1);
2186                 }
2187             }
2188         }
2189     }
2190 }
2191 
2192 // -------------------------------------------------------------------
2193 // ------------------------- Reading Controls ------------------------
2194 // -------------------------------------------------------------------
2195 
ImportFormulaControl(WW8FormulaControl & aFormula,WW8_CP nStart,SwWw8ControlType nWhich)2196 bool SwWW8ImplReader::ImportFormulaControl(WW8FormulaControl &aFormula,
2197     WW8_CP nStart, SwWw8ControlType nWhich )
2198 {
2199     bool bRet=false;
2200     /*
2201      * Save the reader state and process the sprms for this anchor cp.
2202      * Doing so will set the nPicLocFc to the offset to find the hypertext
2203      * data in the data stream.
2204      */
2205     WW8_CP nEndCp = nStart+1; // Only interested in the single 0x01 character
2206 
2207     WW8ReaderSave aSave(this,nStart);
2208 
2209     WW8PLCFManResult aRes;
2210     nStart = pPlcxMan->Where();
2211     while(nStart <= nEndCp)
2212     {
2213         if ( pPlcxMan->Get(&aRes)
2214             && aRes.pMemPos && aRes.nSprmId )
2215         {
2216             //only interested in sprms which would set nPicLocFc
2217             if ( (68 == aRes.nSprmId) || (0x6A03 == aRes.nSprmId) )
2218             {
2219                 Read_PicLoc( aRes.nSprmId, aRes.pMemPos +
2220                     mpSprmParser->DistanceToData(aRes.nSprmId), 4);
2221                 break;
2222             }
2223         }
2224         (*pPlcxMan)++;
2225         nStart = pPlcxMan->Where();
2226     }
2227     sal_uLong nOffset = nPicLocFc;
2228     aSave.Restore(this);
2229 
2230     sal_uLong nOldPos = pDataStream->Tell();
2231     WW8_PIC aPic;
2232     pDataStream->Seek( nOffset);
2233     PicRead( pDataStream, &aPic, bVer67);
2234 
2235     if((aPic.lcb > 0x3A) && !pDataStream->GetError() )
2236     {
2237         aFormula.FormulaRead(nWhich,pDataStream);
2238         bRet = true;
2239     }
2240 
2241     /*
2242      There is a problem with aPic, the WW8_PIC is always used even though it
2243      is too big for the WW95 files, it needs to be modified to check the
2244      version C.
2245      */
2246     pDataStream->Seek( nOldPos );
2247     return(bRet);
2248 }
2249 
InsertFormula(WW8FormulaControl & rFormula)2250 sal_Bool SwMSConvertControls::InsertFormula(WW8FormulaControl &rFormula)
2251 {
2252     sal_Bool bRet = sal_False;
2253 
2254     const uno::Reference< lang::XMultiServiceFactory > & rServiceFactory =
2255         GetServiceFactory();
2256 
2257     if(!rServiceFactory.is())
2258         return sal_False;
2259 
2260     awt::Size aSz;
2261     uno::Reference< form::XFormComponent> xFComp;
2262 
2263     if (sal_True == (bRet = rFormula.Import(rServiceFactory, xFComp, aSz)))
2264     {
2265         uno::Reference <drawing::XShape> xShapeRef;
2266         if (sal_True == (bRet = InsertControl(xFComp, aSz, &xShapeRef, false)))
2267             GetShapes()->add(xShapeRef);
2268     }
2269     return bRet;
2270 }
2271 
FormulaRead(SwWw8ControlType nWhich,SvStream * pDataStream)2272 void WW8FormulaControl::FormulaRead(SwWw8ControlType nWhich,
2273     SvStream *pDataStream)
2274 {
2275     sal_uInt8 nField;
2276     sal_uInt8 nHeaderByte;
2277 
2278     int nType=0;
2279     *pDataStream >> nHeaderByte;
2280     if (nHeaderByte == 0xFF) // Guesswork time, difference between 97 and 95 ?
2281     {
2282         pDataStream->SeekRel(3);
2283         *pDataStream >> nHeaderByte;
2284         nType=1;
2285     }
2286     fUnknown = nHeaderByte & 0x3;
2287     fDropdownIndex = (nHeaderByte & 0x7C) >> 2;
2288     *pDataStream >> nField;
2289     fToolTip = nField & 0x01;
2290     fNoMark = (nField & 0x02)>>1;
2291     fUseSize = (nField & 0x04)>>2;
2292     fNumbersOnly= (nField & 0x08)>>3;
2293     fDateOnly = (nField & 0x10)>>4;
2294     fUnused = (nField & 0xE0)>>5;
2295     *pDataStream >> nSize;
2296 
2297     *pDataStream >> hpsCheckBox;
2298     if (nType == 0)
2299         pDataStream->SeekRel(2); // Guess
2300 
2301     rtl_TextEncoding eEnc = rRdr.eStructCharSet;
2302     sTitle = !nType ? WW8ReadPString(*pDataStream, eEnc, true)
2303                     : WW8Read_xstz(*pDataStream, 0, true);
2304 
2305     if (nWhich == WW8_CT_CHECKBOX)
2306     {
2307         *pDataStream >> nDefaultChecked;
2308         nChecked = nDefaultChecked;
2309 
2310         sal_uInt8 iRes = (nHeaderByte >> 2) & 0x1F;
2311         switch (iRes)
2312         {
2313             case 1: // checked
2314                 nChecked = true;
2315                 break;
2316             case 25: //undefined, Undefined checkboxes are treated as unchecked
2317             case 0: // unchecked
2318                 nChecked = false;
2319                 break;
2320             default:
2321                 ASSERT(sal_False, "unknown option, please report to cmc");
2322                 break;
2323         }
2324     }
2325     else if (nWhich == WW8_CT_DROPDOWN)
2326         *pDataStream >> nChecked;
2327     else
2328     {
2329         sDefault = !nType ? WW8ReadPString(*pDataStream, eEnc, true)
2330                           : WW8Read_xstz(*pDataStream, 0, true);
2331     }
2332 
2333     sFormatting = !nType ? WW8ReadPString(*pDataStream, eEnc, true)
2334                          : WW8Read_xstz(*pDataStream, 0, true);
2335 
2336     sHelp = !nType ? WW8ReadPString(*pDataStream, eEnc, true)
2337                    : WW8Read_xstz(*pDataStream, 0, true);
2338 
2339     if (nWhich == WW8_CT_DROPDOWN) // is this the case ?
2340         fToolTip = true;
2341 
2342     if( fToolTip )
2343     {
2344         sToolTip = !nType ? WW8ReadPString(*pDataStream, eEnc, true)
2345                           : WW8Read_xstz(*pDataStream, 0, true);
2346     }
2347 
2348     if (nWhich == WW8_CT_DROPDOWN)
2349     {
2350         bool bAllOk = true;
2351         pDataStream->SeekRel(4 * (nType ? 2 : 1));
2352         sal_uInt16 nDummy;
2353         *pDataStream >> nDummy;
2354         sal_uInt32 nNoStrings;
2355         if (!nType)
2356         {
2357             sal_uInt16 nWord95NoStrings;
2358             *pDataStream >> nWord95NoStrings;
2359             nNoStrings = nWord95NoStrings;
2360             *pDataStream >> nWord95NoStrings;
2361             if (nNoStrings != nWord95NoStrings)
2362                 bAllOk = false;
2363             nNoStrings = nWord95NoStrings;
2364             sal_uInt16 nDummy2;
2365             *pDataStream >> nDummy2;
2366             if (nDummy2 != 0)
2367                 bAllOk = false;
2368             *pDataStream >> nDummy2;
2369             if (nDummy2 != 0xA)
2370                 bAllOk = false;
2371             if (!bAllOk) // Not as expected, don't risk it at all.
2372                 nNoStrings = 0;
2373             for (sal_uInt16 nI = 0; nI < nNoStrings; ++nI)
2374                 pDataStream->SeekRel(2);
2375         }
2376         else
2377         {
2378             if (nDummy != 0xFFFF)
2379                 bAllOk = false;
2380             *pDataStream >> nNoStrings;
2381         }
2382         ASSERT(bAllOk,
2383             "Unknown formfield dropdown list structure. Report to cmc");
2384         if (!bAllOk) // Not as expected, don't risk it at all.
2385             nNoStrings = 0;
2386         maListEntries.reserve(nNoStrings);
2387         for (sal_uInt32 nI = 0; nI < nNoStrings; ++nI)
2388         {
2389             String sEntry = !nType ? WW8ReadPString(*pDataStream, eEnc, false)
2390                            : WW8Read_xstz(*pDataStream, 0, false);
2391             maListEntries.push_back(sEntry);
2392         }
2393     }
2394 }
2395 
WW8FormulaListBox(SwWW8ImplReader & rR)2396 WW8FormulaListBox::WW8FormulaListBox(SwWW8ImplReader &rR)
2397     : WW8FormulaControl( CREATE_CONST_ASC(SL::aListBox), rR)
2398 {
2399 }
2400 
2401 //Miserable hack to get a hardcoded guesstimate of the size of a list dropdown
2402 //box's first entry to set as the lists default size
MiserableDropDownFormHack(const String & rString,uno::Reference<beans::XPropertySet> & rPropSet)2403 awt::Size SwWW8ImplReader::MiserableDropDownFormHack(const String &rString,
2404     uno::Reference<beans::XPropertySet>& rPropSet)
2405 {
2406     awt::Size aRet;
2407     struct CtrlFontMapEntry
2408     {
2409         sal_uInt16 nWhichId;
2410         const sal_Char* pPropNm;
2411     };
2412     const CtrlFontMapEntry aMapTable[] =
2413     {
2414         { RES_CHRATR_COLOR,           "TextColor" },
2415         { RES_CHRATR_FONT,            "FontName" },
2416         { RES_CHRATR_FONTSIZE,        "FontHeight" },
2417         { RES_CHRATR_WEIGHT,          "FontWeight" },
2418         { RES_CHRATR_UNDERLINE,       "FontUnderline" },
2419         { RES_CHRATR_CROSSEDOUT,      "FontStrikeout" },
2420         { RES_CHRATR_POSTURE,         "FontSlant" },
2421         { 0,                          0 }
2422     };
2423 
2424     Font aFont;
2425     uno::Reference< beans::XPropertySetInfo > xPropSetInfo =
2426         rPropSet->getPropertySetInfo();
2427 
2428     uno::Any aTmp;
2429     for (const CtrlFontMapEntry* pMap = aMapTable; pMap->nWhichId; ++pMap)
2430     {
2431         bool bSet = true;
2432         const SfxPoolItem* pItem = GetFmtAttr( pMap->nWhichId );
2433         ASSERT(pItem, "Impossible");
2434         if (!pItem)
2435             continue;
2436 
2437         switch ( pMap->nWhichId )
2438         {
2439         case RES_CHRATR_COLOR:
2440             {
2441                 String pNm;
2442                 if (xPropSetInfo->hasPropertyByName(pNm = C2U("TextColor")))
2443                 {
2444                     aTmp <<= (sal_Int32)((SvxColorItem*)pItem)->GetValue().GetColor();
2445                     rPropSet->setPropertyValue(pNm, aTmp);
2446                 }
2447             }
2448             aFont.SetColor(((SvxColorItem*)pItem)->GetValue());
2449             break;
2450         case RES_CHRATR_FONT:
2451             {
2452                 const SvxFontItem *pFontItem = (SvxFontItem *)pItem;
2453                 String pNm;
2454                 if (xPropSetInfo->hasPropertyByName(pNm = C2U("FontStyleName")))
2455                 {
2456                     aTmp <<= rtl::OUString( pFontItem->GetStyleName());
2457                     rPropSet->setPropertyValue( pNm, aTmp );
2458                 }
2459                 if (xPropSetInfo->hasPropertyByName(pNm = C2U("FontFamily")))
2460                 {
2461                     aTmp <<= (sal_Int16)pFontItem->GetFamily();
2462                     rPropSet->setPropertyValue( pNm, aTmp );
2463                 }
2464                 if (xPropSetInfo->hasPropertyByName(pNm = C2U("FontCharset")))
2465                 {
2466                     aTmp <<= (sal_Int16)pFontItem->GetCharSet();
2467                     rPropSet->setPropertyValue( pNm, aTmp );
2468                 }
2469                 if (xPropSetInfo->hasPropertyByName(pNm = C2U("FontPitch")))
2470                 {
2471                     aTmp <<= (sal_Int16)pFontItem->GetPitch();
2472                     rPropSet->setPropertyValue( pNm, aTmp );
2473                 }
2474 
2475                 aTmp <<= rtl::OUString( pFontItem->GetFamilyName());
2476                 aFont.SetName( pFontItem->GetFamilyName() );
2477                 aFont.SetStyleName( pFontItem->GetStyleName() );
2478                 aFont.SetFamily( pFontItem->GetFamily() );
2479                 aFont.SetCharSet( pFontItem->GetCharSet() );
2480                 aFont.SetPitch( pFontItem->GetPitch() );
2481             }
2482             break;
2483 
2484         case RES_CHRATR_FONTSIZE:
2485             {
2486                 Size aSize( aFont.GetSize().Width(),
2487                             ((SvxFontHeightItem*)pItem)->GetHeight() );
2488                 aTmp <<= ((float)aSize.Height()) / 20.0;
2489 
2490                 aFont.SetSize(OutputDevice::LogicToLogic(aSize, MAP_TWIP,
2491                     MAP_100TH_MM));
2492             }
2493             break;
2494 
2495         case RES_CHRATR_WEIGHT:
2496             aTmp <<= (float)VCLUnoHelper::ConvertFontWeight(
2497                                         ((SvxWeightItem*)pItem)->GetWeight() );
2498             aFont.SetWeight( ((SvxWeightItem*)pItem)->GetWeight() );
2499             break;
2500 
2501         case RES_CHRATR_UNDERLINE:
2502             aTmp <<= (sal_Int16)(((SvxUnderlineItem*)pItem)->GetLineStyle());
2503             aFont.SetUnderline(((SvxUnderlineItem*)pItem)->GetLineStyle());
2504             break;
2505 
2506         case RES_CHRATR_CROSSEDOUT:
2507             aTmp <<= (sal_Int16)( ((SvxCrossedOutItem*)pItem)->GetStrikeout() );
2508             aFont.SetStrikeout( ((SvxCrossedOutItem*)pItem)->GetStrikeout() );
2509             break;
2510 
2511         case RES_CHRATR_POSTURE:
2512             aTmp <<= (sal_Int16)( ((SvxPostureItem*)pItem)->GetPosture() );
2513             aFont.SetItalic( ((SvxPostureItem*)pItem)->GetPosture() );
2514             break;
2515 
2516         default:
2517             bSet = false;
2518             break;
2519         }
2520 
2521         if (bSet && xPropSetInfo->hasPropertyByName(C2U(pMap->pPropNm)))
2522             rPropSet->setPropertyValue(C2U(pMap->pPropNm), aTmp);
2523     }
2524     // now calculate the size of the control
2525     OutputDevice* pOut = Application::GetDefaultDevice();
2526     ASSERT(pOut, "Impossible");
2527     if (pOut)
2528     {
2529         pOut->Push( PUSH_FONT | PUSH_MAPMODE );
2530         pOut->SetMapMode( MapMode( MAP_100TH_MM ));
2531         pOut->SetFont( aFont );
2532         aRet.Width  = pOut->GetTextWidth(rString);
2533         aRet.Width += 500; //plus size of button, total hack territory
2534         aRet.Height = pOut->GetTextHeight();
2535         pOut->Pop();
2536     }
2537     return aRet;
2538 }
2539 
Import(const uno::Reference<lang::XMultiServiceFactory> & rServiceFactory,uno::Reference<form::XFormComponent> & rFComp,awt::Size & rSz)2540 sal_Bool WW8FormulaListBox::Import(const uno::Reference <
2541     lang::XMultiServiceFactory> &rServiceFactory,
2542     uno::Reference <form::XFormComponent> &rFComp,awt::Size &rSz )
2543 {
2544     uno::Reference<uno::XInterface> xCreate = rServiceFactory->createInstance(
2545         C2U("com.sun.star.form.component.ComboBox"));
2546     if( !xCreate.is() )
2547         return sal_False;
2548 
2549     rFComp = uno::Reference<form::XFormComponent>(xCreate, uno::UNO_QUERY);
2550     if( !rFComp.is() )
2551         return sal_False;
2552 
2553     uno::Reference<beans::XPropertySet> xPropSet(xCreate, uno::UNO_QUERY);
2554 
2555     uno::Any aTmp;
2556     if (sTitle.Len())
2557         aTmp <<= rtl::OUString(sTitle);
2558     else
2559         aTmp <<= rtl::OUString(sName);
2560     xPropSet->setPropertyValue(C2U("Name"), aTmp );
2561 
2562     if (sToolTip.Len())
2563     {
2564         aTmp <<= rtl::OUString(sToolTip);
2565         xPropSet->setPropertyValue(C2U("HelpText"), aTmp );
2566     }
2567 
2568     sal_Bool bDropDown(sal_True);
2569     xPropSet->setPropertyValue(C2U("Dropdown"), cppu::bool2any(bDropDown));
2570 
2571     if (!maListEntries.empty())
2572     {
2573         sal_uInt32 nLen = maListEntries.size();
2574         uno::Sequence< ::rtl::OUString > aListSource(nLen);
2575         for (sal_uInt32 nI = 0; nI < nLen; ++nI)
2576             aListSource[nI] = rtl::OUString(maListEntries[nI]);
2577         aTmp <<= aListSource;
2578         xPropSet->setPropertyValue(C2U("StringItemList"), aTmp );
2579 
2580         if (fDropdownIndex < nLen)
2581         {
2582             aTmp <<= aListSource[fDropdownIndex];
2583         }
2584         else
2585         {
2586             aTmp <<= aListSource[0];
2587         }
2588 
2589         xPropSet->setPropertyValue(C2U("DefaultText"), aTmp );
2590 
2591         rSz = rRdr.MiserableDropDownFormHack(maListEntries[0], xPropSet);
2592     }
2593     else
2594     {
2595         static const sal_Unicode aBlank[] =
2596         {
2597             0x2002,0x2002,0x2002,0x2002,0x2002
2598         };
2599         rSz = rRdr.MiserableDropDownFormHack(String(aBlank), xPropSet);
2600     }
2601 
2602     return sal_True;
2603 }
2604 
WW8FormulaCheckBox(SwWW8ImplReader & rR)2605 WW8FormulaCheckBox::WW8FormulaCheckBox(SwWW8ImplReader &rR)
2606     : WW8FormulaControl( CREATE_CONST_ASC(SL::aCheckBox), rR)
2607 {
2608 }
2609 
lcl_AddToPropertyContainer(uno::Reference<beans::XPropertySet> xPropSet,const rtl::OUString & rPropertyName,const rtl::OUString & rValue)2610 static void lcl_AddToPropertyContainer
2611 (uno::Reference<beans::XPropertySet> xPropSet,
2612  const rtl::OUString & rPropertyName, const rtl::OUString & rValue)
2613 {
2614     uno::Reference<beans::XPropertySetInfo> xPropSetInfo =
2615         xPropSet->getPropertySetInfo();
2616     if (xPropSetInfo.is() &&
2617         ! xPropSetInfo->hasPropertyByName(rPropertyName))
2618     {
2619         uno::Reference<beans::XPropertyContainer>
2620             xPropContainer(xPropSet, uno::UNO_QUERY);
2621         uno::Any aAny(C2U(""));
2622         xPropContainer->addProperty
2623             (rPropertyName,
2624              static_cast<sal_Int16>(beans::PropertyAttribute::BOUND |
2625                                     beans::PropertyAttribute::REMOVABLE),
2626              aAny);
2627     }
2628 
2629     uno::Any aAnyValue(rValue);
2630     xPropSet->setPropertyValue(rPropertyName, aAnyValue );
2631 }
2632 
Import(const uno::Reference<lang::XMultiServiceFactory> & rServiceFactory,uno::Reference<form::XFormComponent> & rFComp,awt::Size & rSz)2633 sal_Bool WW8FormulaCheckBox::Import(const uno::Reference <
2634     lang::XMultiServiceFactory> &rServiceFactory,
2635     uno::Reference <form::XFormComponent> &rFComp,awt::Size &rSz )
2636 {
2637     uno::Reference< uno::XInterface > xCreate = rServiceFactory->createInstance(
2638         C2U("com.sun.star.form.component.CheckBox"));
2639     if( !xCreate.is() )
2640         return sal_False;
2641 
2642     rFComp = uno::Reference< form::XFormComponent >( xCreate, uno::UNO_QUERY );
2643     if( !rFComp.is() )
2644         return sal_False;
2645 
2646     uno::Reference< beans::XPropertySet > xPropSet( xCreate, uno::UNO_QUERY );
2647 
2648     rSz.Width = 16 * hpsCheckBox;
2649     rSz.Height = 16 * hpsCheckBox;
2650 
2651     uno::Any aTmp;
2652     if (sTitle.Len())
2653         aTmp <<= rtl::OUString(sTitle);
2654     else
2655         aTmp <<= rtl::OUString(sName);
2656     xPropSet->setPropertyValue(C2U("Name"), aTmp );
2657 
2658     aTmp <<= (sal_Int16)nChecked;
2659     xPropSet->setPropertyValue(C2U("DefaultState"), aTmp);
2660 
2661     if( sToolTip.Len() )
2662         lcl_AddToPropertyContainer(xPropSet, C2U("HelpText"), sToolTip);
2663 
2664     if( sHelp.Len() )
2665         lcl_AddToPropertyContainer(xPropSet, C2U("HelpF1Text"), sHelp);
2666 
2667     return sal_True;
2668 
2669 }
2670 
WW8FormulaEditBox(SwWW8ImplReader & rR)2671 WW8FormulaEditBox::WW8FormulaEditBox(SwWW8ImplReader &rR)
2672     : WW8FormulaControl( CREATE_CONST_ASC(SL::aTextField) ,rR)
2673 {
2674 }
2675 
InsertControl(const uno::Reference<form::XFormComponent> & rFComp,const awt::Size & rSize,uno::Reference<drawing::XShape> * pShape,sal_Bool bFloatingCtrl)2676 sal_Bool SwMSConvertControls::InsertControl(
2677     const uno::Reference< form::XFormComponent > & rFComp,
2678     const awt::Size& rSize, uno::Reference< drawing::XShape > *pShape,
2679     sal_Bool bFloatingCtrl)
2680 {
2681     const uno::Reference< container::XIndexContainer > &rComps = GetFormComps();
2682     uno::Any aTmp( &rFComp, ::getCppuType((const uno::Reference<
2683         form::XFormComponent >*)0) );
2684     rComps->insertByIndex( rComps->getCount(), aTmp );
2685 
2686     const uno::Reference< lang::XMultiServiceFactory > &rServiceFactory =
2687         GetServiceFactory();
2688     if( !rServiceFactory.is() )
2689         return sal_False;
2690 
2691     uno::Reference< uno::XInterface > xCreate = rServiceFactory->createInstance(
2692         C2U("com.sun.star.drawing.ControlShape"));
2693     if( !xCreate.is() )
2694         return sal_False;
2695 
2696     uno::Reference< drawing::XShape > xShape =
2697         uno::Reference< drawing::XShape >(xCreate, uno::UNO_QUERY);
2698 
2699     DBG_ASSERT(xShape.is(), "XShape nicht erhalten");
2700     xShape->setSize(rSize);
2701 
2702     uno::Reference< beans::XPropertySet > xShapePropSet(
2703         xCreate, uno::UNO_QUERY );
2704 
2705     //I lay a small bet that this will change to
2706     //sal_Int16 nTemp=TextContentAnchorType::AS_CHARACTER;
2707     sal_Int16 nTemp;
2708     if (bFloatingCtrl)
2709         nTemp= text::TextContentAnchorType_AT_PARAGRAPH;
2710     else
2711         nTemp= text::TextContentAnchorType_AS_CHARACTER;
2712 
2713     aTmp <<= nTemp;
2714     xShapePropSet->setPropertyValue(C2U("AnchorType"), aTmp );
2715 
2716     nTemp= text::VertOrientation::TOP;
2717     aTmp <<= nTemp;
2718     xShapePropSet->setPropertyValue(C2U("VertOrient"), aTmp );
2719 
2720     uno::Reference< text::XText > xDummyTxtRef;
2721     uno::Reference< text::XTextRange > xTxtRg =
2722         new SwXTextRange( *pPaM, xDummyTxtRef );
2723 
2724     aTmp.setValue(&xTxtRg,::getCppuType((
2725         uno::Reference< text::XTextRange >*)0));
2726     xShapePropSet->setPropertyValue(C2U("TextRange"), aTmp );
2727 
2728     // Das Control-Model am Control-Shape setzen
2729     uno::Reference< drawing::XControlShape > xControlShape( xShape,
2730         uno::UNO_QUERY );
2731     uno::Reference< awt::XControlModel > xControlModel( rFComp,
2732         uno::UNO_QUERY );
2733     xControlShape->setControl( xControlModel );
2734 
2735     if (pShape)
2736         *pShape = xShape;
2737 
2738     return sal_True;
2739 }
2740 
2741 /* vim: set noet sw=4 ts=4: */
2742