xref: /aoo4110/main/xmloff/source/text/txtlists.cxx (revision b1cdbd2c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "precompiled_xmloff.hxx"
25 
26 #include <txtlists.hxx>
27 
28 #include <tools/debug.hxx>
29 #include <tools/date.hxx>
30 #include <tools/time.hxx>
31 
32 #include <xmloff/txtimp.hxx>
33 #include <xmloff/xmlimp.hxx>
34 #include <xmloff/xmlnumi.hxx>
35 
36 #include <com/sun/star/style/XStyle.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include "XMLTextListItemContext.hxx"
39 #include "XMLTextListBlockContext.hxx"
40 #include "txtparai.hxx"
41 
42 
43 using namespace ::com::sun::star;
44 
45 
XMLTextListsHelper()46 XMLTextListsHelper::XMLTextListsHelper()
47    :  mpProcessedLists( 0 ),
48       msLastProcessedListId(),
49       msListStyleOfLastProcessedList(),
50       // --> OD 2008-08-15 #i92811#
51       mpMapListIdToListStyleDefaultListId( 0 ),
52       // <--
53       mpContinuingLists( 0 ),
54       mpListStack( 0 )
55 {
56 }
57 
~XMLTextListsHelper()58 XMLTextListsHelper::~XMLTextListsHelper()
59 {
60     if ( mpProcessedLists )
61     {
62         mpProcessedLists->clear();
63         delete mpProcessedLists;
64     }
65     // --> OD 2008-08-15 #i92811#
66     if ( mpMapListIdToListStyleDefaultListId )
67     {
68         mpMapListIdToListStyleDefaultListId->clear();
69         delete mpMapListIdToListStyleDefaultListId;
70     }
71     // <--
72     if ( mpContinuingLists )
73     {
74         mpContinuingLists->clear();
75         delete mpContinuingLists;
76     }
77     if ( mpListStack )
78     {
79         mpListStack->clear();
80         delete mpListStack;
81     }
82 }
83 
PushListContext(XMLTextListBlockContext * i_pListBlock)84 void XMLTextListsHelper::PushListContext(
85     XMLTextListBlockContext *i_pListBlock)
86 {
87 //    fprintf(stderr, "PushListContext\n");
88     mListStack.push(::boost::make_tuple(i_pListBlock,
89         static_cast<XMLTextListItemContext*>(0),
90         static_cast<XMLNumberedParaContext*>(0)));
91 }
92 
PushListContext(XMLNumberedParaContext * i_pNumberedParagraph)93 void XMLTextListsHelper::PushListContext(
94     XMLNumberedParaContext *i_pNumberedParagraph)
95 {
96 //    fprintf(stderr, "PushListContext(NP)\n");
97     mListStack.push(::boost::make_tuple(
98         static_cast<XMLTextListBlockContext*>(0),
99         static_cast<XMLTextListItemContext*>(0), i_pNumberedParagraph));
100 }
101 
PopListContext()102 void XMLTextListsHelper::PopListContext()
103 {
104     OSL_ENSURE(mListStack.size(),
105         "internal error: PopListContext: mListStack empty");
106 //    fprintf(stderr, "PopListContext\n");
107     if ( !mListStack.empty())
108         mListStack.pop();
109 }
110 
ListContextTop(XMLTextListBlockContext * & o_pListBlockContext,XMLTextListItemContext * & o_pListItemContext,XMLNumberedParaContext * & o_pNumberedParagraphContext)111 void XMLTextListsHelper::ListContextTop(
112     XMLTextListBlockContext*& o_pListBlockContext,
113     XMLTextListItemContext*& o_pListItemContext,
114     XMLNumberedParaContext*& o_pNumberedParagraphContext )
115 {
116     if ( !mListStack.empty() ) {
117         o_pListBlockContext =
118             static_cast<XMLTextListBlockContext*>(&mListStack.top().get<0>());
119         o_pListItemContext  =
120             static_cast<XMLTextListItemContext *>(&mListStack.top().get<1>());
121         o_pNumberedParagraphContext =
122             static_cast<XMLNumberedParaContext *>(&mListStack.top().get<2>());
123     }
124 }
125 
SetListItem(XMLTextListItemContext * i_pListItem)126 void XMLTextListsHelper::SetListItem( XMLTextListItemContext *i_pListItem )
127 {
128     // may be cleared by ListBlockContext for upper list...
129     if (i_pListItem) {
130         OSL_ENSURE(mListStack.size(),
131             "internal error: SetListItem: mListStack empty");
132         OSL_ENSURE(mListStack.top().get<0>(),
133             "internal error: SetListItem: mListStack has no ListBlock");
134         OSL_ENSURE(!mListStack.top().get<1>(),
135             "error: SetListItem: list item already exists");
136     }
137     if ( !mListStack.empty() ) {
138         mListStack.top().get<1>() = i_pListItem;
139     }
140 }
141 
142 // --> OD 2008-08-15 #i92811# - handling for parameter <sListStyleDefaultListId>
KeepListAsProcessed(::rtl::OUString sListId,::rtl::OUString sListStyleName,::rtl::OUString sContinueListId,::rtl::OUString sListStyleDefaultListId)143 void XMLTextListsHelper::KeepListAsProcessed( ::rtl::OUString sListId,
144                                               ::rtl::OUString sListStyleName,
145                                               ::rtl::OUString sContinueListId,
146                                               ::rtl::OUString sListStyleDefaultListId )
147 {
148     if ( IsListProcessed( sListId ) )
149     {
150         DBG_ASSERT( false,
151                     "<XMLTextListsHelper::KeepListAsProcessed(..)> - list id already added" );
152         return;
153     }
154 
155     if ( mpProcessedLists == 0 )
156     {
157         mpProcessedLists = new tMapForLists();
158     }
159 
160     ::std::pair< ::rtl::OUString, ::rtl::OUString >
161                                 aListData( sListStyleName, sContinueListId );
162     (*mpProcessedLists)[ sListId ] = aListData;
163 
164     msLastProcessedListId = sListId;
165     msListStyleOfLastProcessedList = sListStyleName;
166 
167     // --> OD 2008-08-15 #i92811#
168     if ( sListStyleDefaultListId.getLength() != 0 )
169     {
170         if ( mpMapListIdToListStyleDefaultListId == 0 )
171         {
172             mpMapListIdToListStyleDefaultListId = new tMapForLists();
173         }
174 
175         if ( mpMapListIdToListStyleDefaultListId->find( sListStyleName ) ==
176                                 mpMapListIdToListStyleDefaultListId->end() )
177         {
178             ::std::pair< ::rtl::OUString, ::rtl::OUString >
179                                 aListIdMapData( sListId, sListStyleDefaultListId );
180             (*mpMapListIdToListStyleDefaultListId)[ sListStyleName ] =
181                                                                 aListIdMapData;
182         }
183     }
184     // <--
185 }
186 
IsListProcessed(const::rtl::OUString sListId) const187 sal_Bool XMLTextListsHelper::IsListProcessed( const ::rtl::OUString sListId ) const
188 {
189     if ( mpProcessedLists == 0 )
190     {
191         return sal_False;
192     }
193 
194     return mpProcessedLists->find( sListId ) != mpProcessedLists->end();
195 }
196 
GetListStyleOfProcessedList(const::rtl::OUString sListId) const197 ::rtl::OUString XMLTextListsHelper::GetListStyleOfProcessedList(
198                                             const ::rtl::OUString sListId ) const
199 {
200     if ( mpProcessedLists != 0 )
201     {
202         tMapForLists::const_iterator aIter = mpProcessedLists->find( sListId );
203         if ( aIter != mpProcessedLists->end() )
204         {
205             return (*aIter).second.first;
206         }
207     }
208 
209     return ::rtl::OUString();
210 }
211 
GetContinueListIdOfProcessedList(const::rtl::OUString sListId) const212 ::rtl::OUString XMLTextListsHelper::GetContinueListIdOfProcessedList(
213                                             const ::rtl::OUString sListId ) const
214 {
215     if ( mpProcessedLists != 0 )
216     {
217         tMapForLists::const_iterator aIter = mpProcessedLists->find( sListId );
218         if ( aIter != mpProcessedLists->end() )
219         {
220             return (*aIter).second.second;
221         }
222     }
223 
224     return ::rtl::OUString();
225 }
226 
GetLastProcessedListId() const227 const ::rtl::OUString& XMLTextListsHelper::GetLastProcessedListId() const
228 {
229     return msLastProcessedListId;
230 }
231 
GetListStyleOfLastProcessedList() const232 const ::rtl::OUString& XMLTextListsHelper::GetListStyleOfLastProcessedList() const
233 {
234     return msListStyleOfLastProcessedList;
235 }
236 
GenerateNewListId() const237 ::rtl::OUString XMLTextListsHelper::GenerateNewListId() const
238 {
239     // --> OD 2008-08-06 #i92478#
240     ::rtl::OUString sTmpStr( ::rtl::OUString::createFromAscii( "list" ) );
241     // <--
242     sal_Int64 n = Time().GetTime();
243     n += Date().GetDate();
244     n += rand();
245     // --> OD 2008-08-06 #i92478#
246     sTmpStr += ::rtl::OUString::valueOf( n );
247     // <--
248 
249     long nHitCount = 0;
250     ::rtl::OUString sNewListId( sTmpStr );
251     if ( mpProcessedLists != 0 )
252     {
253         while ( mpProcessedLists->find( sNewListId ) != mpProcessedLists->end() )
254         {
255             ++nHitCount;
256             sNewListId = sTmpStr;
257             sNewListId += ::rtl::OUString::valueOf( nHitCount );
258         }
259     }
260 
261     return sNewListId;
262 }
263 
264 // --> OD 2008-08-15 #i92811#
265 // provide list id for a certain list block for import
GetListIdForListBlock(XMLTextListBlockContext & rListBlock)266 ::rtl::OUString XMLTextListsHelper::GetListIdForListBlock( XMLTextListBlockContext& rListBlock )
267 {
268     ::rtl::OUString sListBlockListId( rListBlock.GetContinueListId() );
269     if ( sListBlockListId.getLength() == 0 )
270     {
271         sListBlockListId = rListBlock.GetListId();
272     }
273 
274     if ( mpMapListIdToListStyleDefaultListId != 0 )
275     {
276         if ( sListBlockListId.getLength() != 0 )
277         {
278             const ::rtl::OUString sListStyleName =
279                                 GetListStyleOfProcessedList( sListBlockListId );
280 
281             tMapForLists::const_iterator aIter =
282                     mpMapListIdToListStyleDefaultListId->find( sListStyleName );
283             if ( aIter != mpMapListIdToListStyleDefaultListId->end() )
284             {
285                 if ( (*aIter).second.first == sListBlockListId )
286                 {
287                     sListBlockListId = (*aIter).second.second;
288                 }
289             }
290         }
291     }
292 
293     return sListBlockListId;
294 }
295 // <--
296 
StoreLastContinuingList(::rtl::OUString sListId,::rtl::OUString sContinuingListId)297 void XMLTextListsHelper::StoreLastContinuingList( ::rtl::OUString sListId,
298                                                   ::rtl::OUString sContinuingListId )
299 {
300     if ( mpContinuingLists == 0 )
301     {
302         mpContinuingLists = new tMapForContinuingLists();
303     }
304 
305     (*mpContinuingLists)[ sListId ] = sContinuingListId;
306 }
307 
GetLastContinuingListId(::rtl::OUString sListId) const308 ::rtl::OUString XMLTextListsHelper::GetLastContinuingListId(
309                                                 ::rtl::OUString sListId ) const
310 {
311     if ( mpContinuingLists != 0)
312     {
313         tMapForContinuingLists::const_iterator aIter =
314                                                 mpContinuingLists->find( sListId );
315         if ( aIter != mpContinuingLists->end() )
316         {
317             return (*aIter).second;
318         }
319     }
320 
321     return sListId;
322 }
323 
PushListOnStack(::rtl::OUString sListId,::rtl::OUString sListStyleName)324 void XMLTextListsHelper::PushListOnStack( ::rtl::OUString sListId,
325                                           ::rtl::OUString sListStyleName )
326 {
327     if ( mpListStack == 0 )
328     {
329         mpListStack = new tStackForLists();
330     }
331     ::std::pair< ::rtl::OUString, ::rtl::OUString >
332                                 aListData( sListId, sListStyleName );
333     mpListStack->push_back( aListData );
334 }
PopListFromStack()335 void XMLTextListsHelper::PopListFromStack()
336 {
337     if ( mpListStack != 0 &&
338          mpListStack->size() > 0 )
339     {
340         mpListStack->pop_back();
341     }
342 }
343 
EqualsToTopListStyleOnStack(const::rtl::OUString sListId) const344 sal_Bool XMLTextListsHelper::EqualsToTopListStyleOnStack( const ::rtl::OUString sListId ) const
345 {
346     return mpListStack != 0
347            ? sListId == mpListStack->back().second
348            : sal_False;
349 }
350 
351 ::rtl::OUString
GetNumberedParagraphListId(const sal_uInt16 i_Level,const::rtl::OUString i_StyleName)352 XMLTextListsHelper::GetNumberedParagraphListId(
353     const sal_uInt16 i_Level,
354     const ::rtl::OUString i_StyleName)
355 {
356     if (!i_StyleName.getLength()) {
357         OSL_ENSURE(false, "invalid numbered-paragraph: no style-name");
358     }
359     if (i_StyleName.getLength()
360         && (i_Level < mLastNumberedParagraphs.size())
361         && (mLastNumberedParagraphs[i_Level].first == i_StyleName) )
362     {
363         OSL_ENSURE(mLastNumberedParagraphs[i_Level].second.getLength(),
364             "internal error: numbered-paragraph style-name but no list-id?");
365         return mLastNumberedParagraphs[i_Level].second;
366     } else {
367         return GenerateNewListId();
368     }
369 }
370 
371 static void
ClampLevel(uno::Reference<container::XIndexReplace> const & i_xNumRules,sal_Int16 & io_rLevel)372 ClampLevel(uno::Reference<container::XIndexReplace> const& i_xNumRules,
373     sal_Int16 & io_rLevel)
374 {
375     OSL_ENSURE(i_xNumRules.is(), "internal error: ClampLevel: NumRules null");
376     if (i_xNumRules.is()) {
377         const sal_Int32 nLevelCount( i_xNumRules->getCount() );
378         if ( io_rLevel >= nLevelCount ) {
379             io_rLevel = sal::static_int_cast< sal_Int16 >(nLevelCount-1);
380         }
381     }
382 }
383 
384 uno::Reference<container::XIndexReplace>
EnsureNumberedParagraph(SvXMLImport & i_rImport,const::rtl::OUString i_ListId,sal_Int16 & io_rLevel,const::rtl::OUString i_StyleName)385 XMLTextListsHelper::EnsureNumberedParagraph(
386     SvXMLImport & i_rImport,
387     const ::rtl::OUString i_ListId,
388     sal_Int16 & io_rLevel, const ::rtl::OUString i_StyleName)
389 {
390     OSL_ENSURE(i_ListId.getLength(), "inavlid ListId");
391     OSL_ENSURE(io_rLevel >= 0, "inavlid Level");
392     NumParaList_t & rNPList( mNPLists[i_ListId] );
393     const ::rtl::OUString none; // default
394     if ( rNPList.empty() && (0 != io_rLevel)) {
395         // create default list style for top level
396         sal_Int16 lev(0);
397         rNPList.push_back(::std::make_pair(none,
398             MakeNumRule(i_rImport, 0, none, none, lev) ));
399     }
400     // create num rule first because this might clamp the level...
401     uno::Reference<container::XIndexReplace> xNumRules;
402     if ((0 == io_rLevel) || rNPList.empty() || i_StyleName.getLength()) {
403         // no parent to inherit from, or explicit style given => new numrules!
404         // index of parent: level - 1, but maybe that does not exist
405         const size_t parent( std::min(static_cast<size_t>(io_rLevel),
406             rNPList.size()) - 1 );
407         xNumRules = MakeNumRule(i_rImport,
408             io_rLevel > 0 ? rNPList[parent].second : 0,
409             io_rLevel > 0 ? rNPList[parent].first  : none,
410             i_StyleName, io_rLevel);
411     } else {
412         // no style given, but has a parent => reuse parent numrules!
413         ClampLevel(rNPList.back().second, io_rLevel);
414     }
415     if (static_cast<sal_uInt16>(io_rLevel) + 1U > rNPList.size()) {
416         // new level: need to enlarge
417         for (size_t i = rNPList.size();
418                 i < static_cast<size_t>(io_rLevel); ++i) {
419             rNPList.push_back(rNPList.back());
420         }
421         rNPList.push_back(xNumRules.is()
422             ? ::std::make_pair(i_StyleName, xNumRules)
423             : rNPList.back());
424     } else {
425         // old level: no need to enlarge; possibly shrink
426         if (xNumRules.is()) {
427             rNPList[io_rLevel] = std::make_pair(i_StyleName, xNumRules);
428         }
429         if (static_cast<sal_uInt16>(io_rLevel) + 1U < rNPList.size()) {
430             rNPList.erase(rNPList.begin() + io_rLevel + 1, rNPList.end());
431         }
432     }
433     // remember the list id
434     if (mLastNumberedParagraphs.size() <= static_cast<size_t>(io_rLevel)) {
435         mLastNumberedParagraphs.resize(io_rLevel+1);
436     }
437     mLastNumberedParagraphs[io_rLevel] = std::make_pair(i_StyleName, i_ListId);
438     return rNPList.back().second;
439 }
440 
441 /** extracted from the XMLTextListBlockContext constructor */
442 uno::Reference<container::XIndexReplace>
MakeNumRule(SvXMLImport & i_rImport,const uno::Reference<container::XIndexReplace> & i_rNumRule,const::rtl::OUString i_ParentStyleName,const::rtl::OUString i_StyleName,sal_Int16 & io_rLevel,sal_Bool * o_pRestartNumbering,sal_Bool * io_pSetDefaults)443 XMLTextListsHelper::MakeNumRule(
444     SvXMLImport & i_rImport,
445     const uno::Reference<container::XIndexReplace>& i_rNumRule,
446     const ::rtl::OUString i_ParentStyleName,
447     const ::rtl::OUString i_StyleName,
448     sal_Int16 & io_rLevel,
449     sal_Bool* o_pRestartNumbering,
450     sal_Bool* io_pSetDefaults)
451 {
452     static ::rtl::OUString s_NumberingRules(
453         RTL_CONSTASCII_USTRINGPARAM("NumberingRules"));
454     uno::Reference<container::XIndexReplace> xNumRules(i_rNumRule);
455     if ( i_StyleName.getLength() &&
456          i_StyleName != i_ParentStyleName )
457     {
458         const ::rtl::OUString sDisplayStyleName(
459             i_rImport.GetStyleDisplayName( XML_STYLE_FAMILY_TEXT_LIST,
460                                              i_StyleName) );
461         const uno::Reference < container::XNameContainer >& rNumStyles(
462                             i_rImport.GetTextImport()->GetNumberingStyles() );
463         if( rNumStyles.is() && rNumStyles->hasByName( sDisplayStyleName ) )
464         {
465             uno::Reference < style::XStyle > xStyle;
466             uno::Any any = rNumStyles->getByName( sDisplayStyleName );
467             any >>= xStyle;
468 
469             // --> OD 2008-05-07 #refactorlists# - no longer needed
470 //            // If the style has not been used, the restart numbering has
471 //            // to be set never.
472 //            if ( mbRestartNumbering && !xStyle->isInUse() )
473 //            {
474 //                mbRestartNumbering = sal_False;
475 //            }
476             // <--
477 
478             uno::Reference< beans::XPropertySet > xPropSet( xStyle,
479                 uno::UNO_QUERY );
480             any = xPropSet->getPropertyValue(s_NumberingRules);
481             any >>= xNumRules;
482         }
483         else
484         {
485             const SvxXMLListStyleContext *pListStyle(
486                 i_rImport.GetTextImport()->FindAutoListStyle( i_StyleName ) );
487             if( pListStyle )
488             {
489                 xNumRules = pListStyle->GetNumRules();
490                 // --> OD 2008-05-07 #refactorlists# - no longer needed
491 //                sal_Bool bUsed = mxNumRules.is();
492                 // <--
493                 if( !xNumRules.is() )
494                 {
495                     pListStyle->CreateAndInsertAuto();
496                     xNumRules = pListStyle->GetNumRules();
497                 }
498                 // --> OD 2008-05-07 #refactorlists# - no longer needed
499 //                if( mbRestartNumbering && !bUsed )
500 //                    mbRestartNumbering = sal_False;
501                 // <--
502             }
503         }
504     }
505 
506     sal_Bool bSetDefaults(io_pSetDefaults ? *io_pSetDefaults : sal_False);
507     if ( !xNumRules.is() )
508 	{
509 		// If no style name has been specified for this style and for any
510 		// parent or if no num rule with the specified name exists,
511 		// create a new one.
512 
513         xNumRules =
514 			SvxXMLListStyleContext::CreateNumRule( i_rImport.GetModel() );
515         DBG_ASSERT( xNumRules.is(), "got no numbering rule" );
516         if ( !xNumRules.is() )
517 			return xNumRules;
518 
519 		// Because it is a new num rule, numbering must not be restarted.
520         if (o_pRestartNumbering) *o_pRestartNumbering = sal_False;
521         bSetDefaults = sal_True;
522         if (io_pSetDefaults) *io_pSetDefaults = bSetDefaults;
523 	}
524 
525     ClampLevel(xNumRules, io_rLevel);
526 
527     if ( bSetDefaults )
528 	{
529 		// Because there is no list style sheet for this style, a default
530 		// format must be set for any level of this num rule.
531         SvxXMLListStyleContext::SetDefaultStyle( xNumRules, io_rLevel,
532             sal_False );
533 	}
534 
535     return xNumRules;
536 }
537 
538