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