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