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