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 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 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 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 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 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 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 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> 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 187 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 197 ::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 212 ::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 227 const ::rtl::OUString& XMLTextListsHelper::GetLastProcessedListId() const 228 { 229 return msLastProcessedListId; 230 } 231 232 const ::rtl::OUString& XMLTextListsHelper::GetListStyleOfLastProcessedList() const 233 { 234 return msListStyleOfLastProcessedList; 235 } 236 237 ::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 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 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 308 ::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 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 } 335 void XMLTextListsHelper::PopListFromStack() 336 { 337 if ( mpListStack != 0 && 338 mpListStack->size() > 0 ) 339 { 340 mpListStack->pop_back(); 341 } 342 } 343 344 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 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 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> 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> 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