xref: /trunk/main/sw/source/core/text/redlnitr.cxx (revision 31bbceb0f9d64c0c2c3b22a794a1666c1f33396e)
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