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