xref: /trunk/main/sw/source/core/text/redlnitr.cxx (revision 6fd66686)
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  *************************************************************************/
CtorInitAttrIter(SwTxtNode & rTxtNode,SwScriptInfo & rScrInf,SwTxtFrm * pFrm)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 
SwRedlineItr(const SwTxtNode & rTxtNd,SwFont & rFnt,SwAttrHandler & rAH,MSHORT nRed,sal_Bool bShw,const SvUShorts * pArr,xub_StrLen nExtStart)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 
~SwRedlineItr()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 
_Seek(SwFont & rFnt,xub_StrLen nNew,xub_StrLen nOld)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 
FillHints(MSHORT nAuthor,RedlineType_t eType)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 
ChangeTxtAttr(SwFont * pFnt,SwTxtAttr & rHt,sal_Bool bChg)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 
_Clear(SwFont * pFnt)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 
_GetNextRedln(xub_StrLen nNext)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 
_ChkSpecialUnderline() const374 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 
CheckLine(xub_StrLen nChkStart,xub_StrLen nChkEnd)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 
ActualizeFont(SwFont & rFnt,MSHORT nAttr)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 
Enter(SwFont & rFnt,xub_StrLen nNew)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 
_Leave(SwFont & rFnt,xub_StrLen nNew)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 
Next(xub_StrLen nNext)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