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