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