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