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