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 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_sw.hxx" 24 25 #include "hintids.hxx" 26 #include <svl/whiter.hxx> 27 #include <tools/shl.hxx> 28 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_ 29 #include <com/sun/star/i18n/ScriptType.hdl> 30 #endif 31 #include <swmodule.hxx> 32 #include <redline.hxx> // SwRedline 33 #include <txtatr.hxx> // SwTxt ... 34 #include <docary.hxx> // SwRedlineTbl 35 #include <itratr.hxx> // SwAttrIter 36 #include <ndtxt.hxx> // SwTxtNode 37 #include <doc.hxx> // SwDoc 38 #include <rootfrm.hxx> 39 #include <breakit.hxx> 40 #include <vcl/keycodes.hxx> 41 #include <vcl/cmdevt.hxx> 42 #include <vcl/settings.hxx> 43 #include <txtfrm.hxx> // SwTxtFrm 44 #ifndef _APP_HXX //autogen 45 #include <vcl/svapp.hxx> 46 #endif 47 #include <redlnitr.hxx> 48 #include <extinput.hxx> 49 #include <sfx2/printer.hxx> 50 #include <vcl/window.hxx> 51 52 using namespace ::com::sun::star; 53 54 /************************************************************************* 55 * SwAttrIter::CtorInitAttrIter() 56 *************************************************************************/ 57 void SwAttrIter::CtorInitAttrIter( SwTxtNode& rTxtNode, SwScriptInfo& rScrInf, SwTxtFrm* pFrm ) 58 { 59 // Beim HTML-Import kann es vorkommen, dass kein Layout existiert. 60 SwRootFrm* pRootFrm = rTxtNode.getIDocumentLayoutAccess()->GetCurrentLayout(); 61 pShell = pRootFrm ? pRootFrm->GetCurrShell() : 0; //swmod 080218 62 63 pScriptInfo = &rScrInf; 64 65 // attributes set at the whole paragraph 66 pAttrSet = rTxtNode.GetpSwAttrSet(); 67 // attribute array 68 pHints = rTxtNode.GetpSwpHints(); 69 70 // Build a font matching the default paragraph style: 71 SwFontAccess aFontAccess( &rTxtNode.GetAnyFmtColl(), pShell ); 72 delete pFnt; 73 pFnt = new SwFont( *aFontAccess.Get()->GetFont() ); 74 75 // set font to vertical if frame layout is vertical 76 sal_Bool bVertLayout = sal_False; 77 sal_Bool bRTL = sal_False; 78 if ( pFrm ) 79 { 80 if ( pFrm->IsVertical() ) 81 { 82 bVertLayout = sal_True; 83 pFnt->SetVertical( pFnt->GetOrientation(), sal_True ); 84 } 85 bRTL = pFrm->IsRightToLeft(); 86 } 87 88 // Initialize the default attribute of the attribute handler 89 // based on the attribute array cached together with the font. 90 // If any further attributes for the paragraph are given in pAttrSet 91 // consider them during construction of the default array, and apply 92 // them to the font 93 aAttrHandler.Init( aFontAccess.Get()->GetDefault(), pAttrSet, 94 *rTxtNode.getIDocumentSettingAccess(), pShell, *pFnt, bVertLayout ); 95 96 aMagicNo[SW_LATIN] = aMagicNo[SW_CJK] = aMagicNo[SW_CTL] = NULL; 97 98 // determine script changes if not already done for current paragraph 99 ASSERT( pScriptInfo, "No script info available"); 100 if ( pScriptInfo->GetInvalidity() != STRING_LEN ) 101 pScriptInfo->InitScriptInfo( rTxtNode, bRTL ); 102 103 if ( pBreakIt->GetBreakIter().is() ) 104 { 105 pFnt->SetActual( SwScriptInfo::WhichFont( 0, 0, pScriptInfo ) ); 106 107 xub_StrLen nChg = 0; 108 sal_uInt16 nCnt = 0; 109 110 do 111 { 112 nChg = pScriptInfo->GetScriptChg( nCnt ); 113 sal_uInt16 nScript = pScriptInfo->GetScriptType( nCnt++ ); 114 sal_uInt8 nTmp = 4; 115 switch ( nScript ) { 116 case i18n::ScriptType::ASIAN : 117 if( !aMagicNo[SW_CJK] ) nTmp = SW_CJK; break; 118 case i18n::ScriptType::COMPLEX : 119 if( !aMagicNo[SW_CTL] ) nTmp = SW_CTL; break; 120 default: 121 if( !aMagicNo[SW_LATIN ] ) nTmp = SW_LATIN; 122 } 123 if( nTmp < 4 ) 124 { 125 pFnt->ChkMagic( pShell, nTmp ); 126 pFnt->GetMagic( aMagicNo[ nTmp ], aFntIdx[ nTmp ], nTmp ); 127 } 128 } while( nChg < rTxtNode.GetTxt().Len() ); 129 } 130 else 131 { 132 pFnt->ChkMagic( pShell, SW_LATIN ); 133 pFnt->GetMagic( aMagicNo[ SW_LATIN ], aFntIdx[ SW_LATIN ], SW_LATIN ); 134 } 135 136 nStartIndex = nEndIndex = nPos = nChgCnt = 0; 137 nPropFont = 0; 138 SwDoc* pDoc = rTxtNode.GetDoc(); 139 const IDocumentRedlineAccess* pIDRA = rTxtNode.getIDocumentRedlineAccess(); 140 141 const SwExtTextInput* pExtInp = pDoc->GetExtTextInput( rTxtNode ); 142 const bool bShow = IDocumentRedlineAccess::IsShowChanges( pIDRA->GetRedlineMode() ); 143 if( pExtInp || bShow ) 144 { 145 MSHORT nRedlPos = pIDRA->GetRedlinePos( rTxtNode, USHRT_MAX ); 146 if( pExtInp || MSHRT_MAX != nRedlPos ) 147 { 148 const SvUShorts* pArr = 0; 149 xub_StrLen nInputStt = 0; 150 if( pExtInp ) 151 { 152 pArr = &pExtInp->GetAttrs(); 153 nInputStt = pExtInp->Start()->nContent.GetIndex(); 154 Seek( 0 ); 155 } 156 157 pRedln = new SwRedlineItr( rTxtNode, *pFnt, aAttrHandler, nRedlPos, 158 bShow, pArr, nInputStt ); 159 160 if( pRedln->IsOn() ) 161 ++nChgCnt; 162 } 163 } 164 } 165 166 /************************************************************************* 167 * SwRedlineItr - Der Redline-Iterator 168 * 169 * Folgende Informationen/Zustände gibt es im RedlineIterator: 170 * 171 * nFirst ist der erste Index der RedlineTbl, der mit dem Absatz überlappt. 172 * 173 * nAct ist der zur Zeit aktive ( wenn bOn gesetzt ist ) oder der nächste 174 * in Frage kommende Index. 175 * nStart und nEnd geben die Grenzen des Objekts innerhalb des Absatzes an. 176 * 177 * Wenn bOn gesetzt ist, ist der Font entsprechend manipuliert worden. 178 * 179 * Wenn nAct auf MSHRT_MAX gesetzt wurde ( durch Reset() ), so ist zur Zeit 180 * kein Redline aktiv, nStart und nEnd sind invalid. 181 *************************************************************************/ 182 183 SwRedlineItr::SwRedlineItr( const SwTxtNode& rTxtNd, SwFont& rFnt, 184 SwAttrHandler& rAH, MSHORT nRed, sal_Bool bShw, const SvUShorts *pArr, 185 xub_StrLen nExtStart ) 186 : rDoc( *rTxtNd.GetDoc() ), rNd( rTxtNd ), rAttrHandler( rAH ), pSet( 0 ), 187 nNdIdx( rTxtNd.GetIndex() ), nFirst( nRed ), 188 nAct( MSHRT_MAX ), bOn( sal_False ), bShow( bShw ) 189 { 190 if( pArr ) 191 pExt = new SwExtend( *pArr, nExtStart ); 192 else 193 pExt = NULL; 194 Seek( rFnt, 0, STRING_LEN ); 195 } 196 197 SwRedlineItr::~SwRedlineItr() 198 { 199 Clear( NULL ); 200 delete pSet; 201 delete pExt; 202 } 203 204 // Der Return-Wert von SwRedlineItr::Seek gibt an, ob der aktuelle Font 205 // verändert wurde durch Verlassen (-1) oder Betreten eines Bereichs (+1) 206 207 short SwRedlineItr::_Seek( SwFont& rFnt, xub_StrLen nNew, xub_StrLen nOld ) 208 { 209 short nRet = 0; 210 if( ExtOn() ) 211 return 0; // Abkürzung: wenn wir innerhalb eines ExtendTextInputs sind 212 // kann es keine anderen Attributwechsel (auch nicht durch Redlining) geben 213 if( bShow ) 214 { 215 if( bOn ) 216 { 217 if( nNew >= nEnd ) 218 { 219 --nRet; 220 _Clear( &rFnt ); // Wir gehen hinter den aktuellen Bereich 221 ++nAct; // und prüfen gleich den nächsten 222 } 223 else if( nNew < nStart ) 224 { 225 --nRet; 226 _Clear( &rFnt ); // Wir gehen vor den aktuellen Bereich 227 if( nAct > nFirst ) 228 nAct = nFirst; // Die Prüfung muss von vorne beginnen 229 else 230 return nRet + EnterExtend( rFnt, nNew ); // Es gibt keinen vor uns. 231 } 232 else 233 return nRet + EnterExtend( rFnt, nNew ); // Wir sind im gleichen Bereich geblieben. 234 } 235 if( MSHRT_MAX == nAct || nOld > nNew ) 236 nAct = nFirst; 237 238 nStart = STRING_LEN; 239 nEnd = STRING_LEN; 240 241 for( ; nAct < rDoc.GetRedlineTbl().Count() ; ++nAct ) 242 { 243 rDoc.GetRedlineTbl()[ nAct ]->CalcStartEnd( nNdIdx, nStart, nEnd ); 244 245 if( nNew < nEnd ) 246 { 247 if( nNew >= nStart ) // der einzig mögliche Kandidat 248 { 249 bOn = sal_True; 250 const SwRedline *pRed = rDoc.GetRedlineTbl()[ nAct ]; 251 252 if (pSet) 253 pSet->ClearItem(); 254 else 255 { 256 SwAttrPool& rPool = 257 const_cast<SwDoc&>(rDoc).GetAttrPool(); 258 pSet = new SfxItemSet(rPool, RES_CHRATR_BEGIN, RES_CHRATR_END-1); 259 } 260 261 if( 1 < pRed->GetStackCount() ) 262 FillHints( pRed->GetAuthor( 1 ), pRed->GetType( 1 ) ); 263 FillHints( pRed->GetAuthor(), pRed->GetType() ); 264 265 SfxWhichIter aIter( *pSet ); 266 MSHORT nWhich = aIter.FirstWhich(); 267 while( nWhich ) 268 { 269 const SfxPoolItem* pItem; 270 if( ( nWhich < RES_CHRATR_END ) && 271 ( SFX_ITEM_SET == pSet->GetItemState( nWhich, sal_True, &pItem ) ) ) 272 { 273 SwTxtAttr* pAttr = MakeRedlineTxtAttr( 274 const_cast<SwDoc&>(rDoc), 275 *const_cast<SfxPoolItem*>(pItem) ); 276 pAttr->SetPriorityAttr( sal_True ); 277 aHints.C40_INSERT( SwTxtAttr, pAttr, aHints.Count()); 278 rAttrHandler.PushAndChg( *pAttr, rFnt ); 279 if( RES_CHRATR_COLOR == nWhich ) 280 rFnt.SetNoCol( sal_True ); 281 } 282 nWhich = aIter.NextWhich(); 283 } 284 285 ++nRet; 286 } 287 break; 288 } 289 nStart = STRING_LEN; 290 nEnd = STRING_LEN; 291 } 292 } 293 return nRet + EnterExtend( rFnt, nNew ); 294 } 295 296 void SwRedlineItr::FillHints( MSHORT nAuthor, RedlineType_t eType ) 297 { 298 switch ( eType ) 299 { 300 case nsRedlineType_t::REDLINE_INSERT: 301 SW_MOD()->GetInsertAuthorAttr(nAuthor, *pSet); 302 break; 303 case nsRedlineType_t::REDLINE_DELETE: 304 SW_MOD()->GetDeletedAuthorAttr(nAuthor, *pSet); 305 break; 306 case nsRedlineType_t::REDLINE_FORMAT: 307 case nsRedlineType_t::REDLINE_FMTCOLL: 308 SW_MOD()->GetFormatAuthorAttr(nAuthor, *pSet); 309 break; 310 default: 311 break; 312 } 313 } 314 315 void SwRedlineItr::ChangeTxtAttr( SwFont* pFnt, SwTxtAttr &rHt, sal_Bool bChg ) 316 { 317 ASSERT( IsOn(), "SwRedlineItr::ChangeTxtAttr: Off?" ); 318 319 if( !bShow && !pExt ) 320 return; 321 322 if( bChg ) 323 { 324 if ( pExt && pExt->IsOn() ) 325 rAttrHandler.PushAndChg( rHt, *pExt->GetFont() ); 326 else 327 rAttrHandler.PushAndChg( rHt, *pFnt ); 328 } 329 else 330 { 331 ASSERT( ! pExt || ! pExt->IsOn(), "Pop of attribute during opened extension" ) 332 rAttrHandler.PopAndChg( rHt, *pFnt ); 333 } 334 } 335 336 void SwRedlineItr::_Clear( SwFont* pFnt ) 337 { 338 ASSERT( bOn, "SwRedlineItr::Clear: Off?" ); 339 bOn = sal_False; 340 while( aHints.Count() ) 341 { 342 SwTxtAttr *pPos = aHints[ 0 ]; 343 aHints.Remove(0); 344 if( pFnt ) 345 rAttrHandler.PopAndChg( *pPos, *pFnt ); 346 else 347 rAttrHandler.Pop( *pPos ); 348 SwTxtAttr::Destroy(pPos, const_cast<SwDoc&>(rDoc).GetAttrPool() ); 349 } 350 if( pFnt ) 351 pFnt->SetNoCol( sal_False ); 352 } 353 354 xub_StrLen SwRedlineItr::_GetNextRedln( xub_StrLen nNext ) 355 { 356 nNext = NextExtend( nNext ); 357 if( !bShow || MSHRT_MAX == nFirst ) 358 return nNext; 359 if( MSHRT_MAX == nAct ) 360 { 361 nAct = nFirst; 362 rDoc.GetRedlineTbl()[ nAct ]->CalcStartEnd( nNdIdx, nStart, nEnd ); 363 } 364 if( bOn || !nStart ) 365 { 366 if( nEnd < nNext ) 367 nNext = nEnd; 368 } 369 else if( nStart < nNext ) 370 nNext = nStart; 371 return nNext; 372 } 373 374 sal_Bool SwRedlineItr::_ChkSpecialUnderline() const 375 { 376 // Wenn die Unterstreichung oder das Escapement vom Redlining kommt, 377 // wenden wir immer das SpecialUnderlining, d.h. die Unterstreichung 378 // unter der Grundlinie an. 379 for( MSHORT i = 0; i < aHints.Count(); ++i ) 380 { 381 MSHORT nWhich = aHints[i]->Which(); 382 if( RES_CHRATR_UNDERLINE == nWhich || 383 RES_CHRATR_ESCAPEMENT == nWhich ) 384 return sal_True; 385 } 386 return sal_False; 387 } 388 389 sal_Bool SwRedlineItr::CheckLine( xub_StrLen nChkStart, xub_StrLen nChkEnd ) 390 { 391 if( nFirst == MSHRT_MAX ) 392 return sal_False; 393 if( nChkEnd == nChkStart ) // Leerzeilen gucken ein Zeichen weiter. 394 ++nChkEnd; 395 xub_StrLen nOldStart = nStart; 396 xub_StrLen nOldEnd = nEnd; 397 xub_StrLen nOldAct = nAct; 398 sal_Bool bRet = sal_False; 399 400 for( nAct = nFirst; nAct < rDoc.GetRedlineTbl().Count() ; ++nAct ) 401 { 402 rDoc.GetRedlineTbl()[ nAct ]->CalcStartEnd( nNdIdx, nStart, nEnd ); 403 if( nChkEnd < nStart ) 404 break; 405 if( nChkStart <= nEnd && ( nChkEnd > nStart || STRING_LEN == nEnd ) ) 406 { 407 bRet = sal_True; 408 break; 409 } 410 } 411 412 nStart = nOldStart; 413 nEnd = nOldEnd; 414 nAct = nOldAct; 415 return bRet; 416 } 417 418 void SwExtend::ActualizeFont( SwFont &rFnt, MSHORT nAttr ) 419 { 420 if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE ) 421 rFnt.SetUnderline( UNDERLINE_SINGLE ); 422 else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE ) 423 rFnt.SetUnderline( UNDERLINE_BOLD ); 424 else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE ) 425 rFnt.SetUnderline( UNDERLINE_DOTTED ); 426 else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE ) 427 rFnt.SetUnderline( UNDERLINE_DOTTED ); 428 429 if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT ) 430 rFnt.SetColor( Color( COL_RED ) ); 431 432 if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT ) 433 { 434 const StyleSettings& rStyleSettings = GetpApp()->GetSettings().GetStyleSettings(); 435 rFnt.SetColor( rStyleSettings.GetHighlightTextColor() ); 436 rFnt.SetBackColor( new Color( rStyleSettings.GetHighlightColor() ) ); 437 } 438 if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE ) 439 rFnt.SetGreyWave( sal_True ); 440 } 441 442 short SwExtend::Enter( SwFont& rFnt, xub_StrLen nNew ) 443 { 444 ASSERT( !Inside(), "SwExtend: Enter without Leave" ); 445 ASSERT( !pFnt, "SwExtend: Enter with Font" ); 446 nPos = nNew; 447 if( Inside() ) 448 { 449 pFnt = new SwFont( rFnt ); 450 ActualizeFont( rFnt, rArr[ nPos - nStart ] ); 451 return 1; 452 } 453 return 0; 454 } 455 456 sal_Bool SwExtend::_Leave( SwFont& rFnt, xub_StrLen nNew ) 457 { 458 ASSERT( Inside(), "SwExtend: Leave without Enter" ); 459 MSHORT nOldAttr = rArr[ nPos - nStart ]; 460 nPos = nNew; 461 if( Inside() ) 462 { // Wir sind innerhalb des ExtendText-Bereichs geblieben 463 MSHORT nAttr = rArr[ nPos - nStart ]; 464 if( nOldAttr != nAttr ) // Gibt es einen (inneren) Attributwechsel? 465 { 466 rFnt = *pFnt; 467 ActualizeFont( rFnt, nAttr ); 468 } 469 } 470 else 471 { 472 rFnt = *pFnt; 473 delete pFnt; 474 pFnt = NULL; 475 return sal_True; 476 } 477 return sal_False; 478 } 479 480 xub_StrLen SwExtend::Next( xub_StrLen nNext ) 481 { 482 if( nPos < nStart ) 483 { 484 if( nNext > nStart ) 485 nNext = nStart; 486 } 487 else if( nPos < nEnd ) 488 { 489 MSHORT nIdx = nPos - nStart; 490 MSHORT nAttr = rArr[ nIdx ]; 491 while( ++nIdx < rArr.Count() && nAttr == rArr[ nIdx ] ) 492 ; // nothing 493 nIdx = nIdx + nStart; 494 if( nNext > nIdx ) 495 nNext = nIdx; 496 } 497 return nNext; 498 } 499 500 /* vim: set noet sw=4 ts=4: */ 501