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