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 *************************************************************************/
CtorInitAttrIter(SwTxtNode & rTxtNode,SwScriptInfo & rScrInf,SwTxtFrm * pFrm)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
SwRedlineItr(const SwTxtNode & rTxtNd,SwFont & rFnt,SwAttrHandler & rAH,MSHORT nRed,sal_Bool bShw,const SvUShorts * pArr,xub_StrLen nExtStart)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
~SwRedlineItr()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
_Seek(SwFont & rFnt,xub_StrLen nNew,xub_StrLen nOld)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
FillHints(MSHORT nAuthor,RedlineType_t eType)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
ChangeTxtAttr(SwFont * pFnt,SwTxtAttr & rHt,sal_Bool bChg)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
_Clear(SwFont * pFnt)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
_GetNextRedln(xub_StrLen nNext)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
_ChkSpecialUnderline() const377 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
CheckLine(xub_StrLen nChkStart,xub_StrLen nChkEnd)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
ActualizeFont(SwFont & rFnt,MSHORT nAttr)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
Enter(SwFont & rFnt,xub_StrLen nNew)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
_Leave(SwFont & rFnt,xub_StrLen nNew)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
Next(xub_StrLen nNext)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