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