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