xref: /trunk/main/editeng/source/editeng/impedit5.cxx (revision bb99baf4)
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_editeng.hxx"
26 
27 #include <eeng_pch.hxx>
28 
29 #include <impedit.hxx>
30 #include <editeng/editeng.hxx>
31 #include <editdbg.hxx>
32 
33 #include <svl/smplhint.hxx>
34 
35 
36 #include <editeng/lrspitem.hxx>
37 
SetStyleSheetPool(SfxStyleSheetPool * pSPool)38 void ImpEditEngine::SetStyleSheetPool( SfxStyleSheetPool* pSPool )
39 {
40 	if ( pStylePool != pSPool )
41 	{
42 //		if ( pStylePool )
43 //			EndListening( *pStylePool, sal_True );
44 
45 		pStylePool = pSPool;
46 
47 //		if ( pStylePool )
48 //			StartListening( *pStylePool, sal_True );
49 	}
50 }
51 
GetStyleSheet(sal_uInt32 nPara) const52 SfxStyleSheet* ImpEditEngine::GetStyleSheet( sal_uInt32 nPara ) const
53 {
54 	ContentNode* pNode = aEditDoc.SaveGetObject( nPara );
55 	return pNode ? pNode->GetContentAttribs().GetStyleSheet() : NULL;
56 }
57 
SetStyleSheet(EditSelection aSel,SfxStyleSheet * pStyle)58 void ImpEditEngine::SetStyleSheet( EditSelection aSel, SfxStyleSheet* pStyle )
59 {
60 	aSel.Adjust( aEditDoc );
61 
62 	sal_uInt32 nStartPara = aEditDoc.GetPos( aSel.Min().GetNode() );
63 	sal_uInt32 nEndPara = aEditDoc.GetPos( aSel.Max().GetNode() );
64 
65 	sal_Bool _bUpdate = GetUpdateMode();
66 	SetUpdateMode( sal_False );
67 
68 	for ( sal_uInt32 n = nStartPara; n <= nEndPara; n++ )
69 		SetStyleSheet( n, pStyle );
70 
71 	SetUpdateMode( _bUpdate, 0 );
72 }
73 
SetStyleSheet(sal_uInt32 nPara,SfxStyleSheet * pStyle)74 void ImpEditEngine::SetStyleSheet( sal_uInt32 nPara, SfxStyleSheet* pStyle )
75 {
76 	DBG_ASSERT( GetStyleSheetPool() || !pStyle, "SetStyleSheet: No StyleSheetPool registered!" );
77 	ContentNode* pNode = aEditDoc.SaveGetObject( nPara );
78 	SfxStyleSheet* pCurStyle = pNode->GetStyleSheet();
79 	if ( pStyle != pCurStyle )
80 	{
81 		if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() )
82 		{
83 			XubString aPrevStyleName;
84 			if ( pCurStyle )
85 				aPrevStyleName = pCurStyle->GetName();
86 
87             XubString aNewStyleName;
88 			if ( pStyle )
89 				aNewStyleName = pStyle->GetName();
90 
91 			InsertUndo(
92 				new EditUndoSetStyleSheet( this, aEditDoc.GetPos( pNode ),
93 						aPrevStyleName, pCurStyle ? pCurStyle->GetFamily() : SFX_STYLE_FAMILY_PARA,
94                         aNewStyleName, pStyle ? pStyle->GetFamily() : SFX_STYLE_FAMILY_PARA,
95 						pNode->GetContentAttribs().GetItems() ) );
96 		}
97 		if ( pCurStyle )
98 			EndListening( *pCurStyle, sal_False );
99 		pNode->SetStyleSheet( pStyle, aStatus.UseCharAttribs() );
100 		if ( pStyle )
101 			StartListening( *pStyle, sal_False );
102 		ParaAttribsChanged( pNode );
103 	}
104 	FormatAndUpdate();
105 }
106 
UpdateParagraphsWithStyleSheet(SfxStyleSheet * pStyle)107 void ImpEditEngine::UpdateParagraphsWithStyleSheet( SfxStyleSheet* pStyle )
108 {
109 	SvxFont aFontFromStyle;
110 	CreateFont( aFontFromStyle, pStyle->GetItemSet() );
111 
112 	sal_Bool bUsed = sal_False;
113 	for ( sal_uInt32 nNode = 0; nNode < aEditDoc.Count(); nNode++ )
114 	{
115 		ContentNode* pNode = aEditDoc.GetObject( nNode );
116 		if ( pNode->GetStyleSheet() == pStyle )
117 		{
118 			bUsed = sal_True;
119 			if ( aStatus.UseCharAttribs() )
120 				pNode->SetStyleSheet( pStyle, aFontFromStyle );
121 			else
122 				pNode->SetStyleSheet( pStyle, sal_False );
123 
124 			ParaAttribsChanged( pNode );
125 		}
126 	}
127 	if ( bUsed )
128 	{
129 		GetEditEnginePtr()->StyleSheetChanged( pStyle );
130 		FormatAndUpdate();
131 	}
132 }
133 
RemoveStyleFromParagraphs(SfxStyleSheet * pStyle)134 void ImpEditEngine::RemoveStyleFromParagraphs( SfxStyleSheet* pStyle )
135 {
136 	for ( sal_uInt32 nNode = 0; nNode < aEditDoc.Count(); nNode++ )
137 	{
138 		ContentNode* pNode = aEditDoc.GetObject(nNode);
139 		if ( pNode->GetStyleSheet() == pStyle )
140 		{
141 			pNode->SetStyleSheet( NULL );
142 			ParaAttribsChanged( pNode );
143 		}
144 	}
145 	FormatAndUpdate();
146 }
147 
Notify(SfxBroadcaster & rBC,const SfxHint & rHint)148 void ImpEditEngine::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
149 {
150 	// Damit nicht beim Destruieren unnoetig formatiert wird:
151 	if ( !bDowning )
152 	{
153 		DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 );
154 
155 		SfxStyleSheet* pStyle = NULL;
156 		sal_uLong nId = 0;
157 
158 		if ( rHint.ISA( SfxStyleSheetHint ) )
159 		{
160 			const SfxStyleSheetHint& rH = (const SfxStyleSheetHint&) rHint;
161 			DBG_ASSERT( rH.GetStyleSheet()->ISA( SfxStyleSheet ), "Kein SfxStyleSheet!" );
162 			pStyle = (SfxStyleSheet*) rH.GetStyleSheet();
163 			nId = rH.GetHint();
164 		}
165 		else if ( ( rHint.Type() == TYPE(SfxSimpleHint ) ) && ( rBC.ISA( SfxStyleSheet ) ) )
166 		{
167 			pStyle = (SfxStyleSheet*)&rBC;
168 			nId = ((SfxSimpleHint&)rHint).GetId();
169 		}
170 
171 		if ( pStyle )
172 		{
173 			if ( ( nId == SFX_HINT_DYING ) ||
174 				 ( nId == SFX_STYLESHEET_INDESTRUCTION ) ||
175 				 ( nId == SFX_STYLESHEET_ERASED ) )
176 			{
177 				RemoveStyleFromParagraphs( pStyle );
178 			}
179 			else if ( ( nId == SFX_HINT_DATACHANGED ) ||
180 					  ( nId == SFX_STYLESHEET_MODIFIED ) )
181 			{
182 				UpdateParagraphsWithStyleSheet( pStyle );
183 
184 				// Alle Absaetze mit EditStyles, die das geaenderte Style
185 				// irgendwie als Parent haben, muessen formatiert werden.
186 				// sal_uLong nStyles = pMyStylePool->GetStyles().Count();
187 				// for ( sal_uLong nStyle = 0; nStyle < nStyles; nStyle++ )
188 				// {
189 				// 	EditStyleSheet* pES = (EditStyleSheet*)pMyStylePool->GetStyles().GetObject( nStyle );
190 				// 	DBG_ASSERT( pES, "NULL-Pointer im StyleSheetPool!" );
191 				// 	if ( pES->IsUsed() && pES->HasStyleAsAnyParent( *pStyle ) )
192 				// 		UpdateParagraphsWithStyleSheet( pES );
193 				// }
194 			}
195 		}
196 	}
197 }
198 
CreateAttribUndo(EditSelection aSel,const SfxItemSet & rSet)199 EditUndoSetAttribs* ImpEditEngine::CreateAttribUndo( EditSelection aSel, const SfxItemSet& rSet )
200 {
201 	DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "CreateAttribUndo: Fehlerhafte Selektion" );
202 	aSel.Adjust( aEditDoc );
203 
204 	ESelection aESel( CreateESel( aSel ) );
205 
206 	sal_uInt32 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
207 	sal_uInt32 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
208 
209 	DBG_ASSERT( nStartNode <= nEndNode, "CreateAttribUndo: Start > End ?!" );
210 
211 	EditUndoSetAttribs* pUndo = NULL;
212 	if ( rSet.GetPool() != &aEditDoc.GetItemPool() )
213 	{
214 		SfxItemSet aTmpSet( GetEmptyItemSet() );
215 		aTmpSet.Put( rSet );
216 		pUndo = new EditUndoSetAttribs( this, aESel, aTmpSet );
217 	}
218 	else
219 	{
220 		pUndo = new EditUndoSetAttribs( this, aESel, rSet );
221 	}
222 
223 	SfxItemPool* pPool = pUndo->GetNewAttribs().GetPool();
224 
225 	for ( sal_uInt32 nPara = nStartNode; nPara <= nEndNode; nPara++ )
226 	{
227 		ContentNode* pNode = aEditDoc.GetObject( nPara );
228 		DBG_ASSERT( aEditDoc.SaveGetObject( nPara ), "Node nicht gefunden: CreateAttribUndo" );
229 		ContentAttribsInfo* pInf = new ContentAttribsInfo( pNode->GetContentAttribs().GetItems() );
230 		pUndo->GetContentInfos().Insert( pInf, pUndo->GetContentInfos().Count() );
231 
232 		for ( sal_uInt16 nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ )
233 		{
234 			EditCharAttribPtr pAttr = pNode->GetCharAttribs().GetAttribs()[ nAttr ];
235 			if ( pAttr->GetLen() )
236 			{
237 				EditCharAttribPtr pNew = MakeCharAttrib( *pPool, *pAttr->GetItem(), pAttr->GetStart(), pAttr->GetEnd() );
238 				pInf->GetPrevCharAttribs().Insert( pNew, pInf->GetPrevCharAttribs().Count() );
239 			}
240 		}
241 	}
242 	return pUndo;
243 }
244 
UndoActionStart(sal_uInt16 nId,const ESelection & aSel)245 void ImpEditEngine::UndoActionStart( sal_uInt16 nId, const ESelection& aSel )
246 {
247 	if ( IsUndoEnabled() && !IsInUndo() )
248 	{
249 		GetUndoManager().EnterListAction( GetEditEnginePtr()->GetUndoComment( nId ), XubString(), nId );
250 		DBG_ASSERT( !pUndoMarkSelection, "UndoAction SelectionMarker?" );
251 		pUndoMarkSelection = new ESelection( aSel );
252 	}
253 }
254 
UndoActionStart(sal_uInt16 nId)255 void ImpEditEngine::UndoActionStart( sal_uInt16 nId )
256 {
257 	if ( IsUndoEnabled() && !IsInUndo() )
258 	{
259 		GetUndoManager().EnterListAction( GetEditEnginePtr()->GetUndoComment( nId ), XubString(), nId );
260 		DBG_ASSERT( !pUndoMarkSelection, "UndoAction SelectionMarker?" );
261 	}
262 }
263 
UndoActionEnd(sal_uInt16)264 void ImpEditEngine::UndoActionEnd( sal_uInt16 )
265 {
266 	if ( IsUndoEnabled() && !IsInUndo() )
267 	{
268 		GetUndoManager().LeaveListAction();
269 		delete pUndoMarkSelection;
270 		pUndoMarkSelection = NULL;
271 	}
272 }
273 
InsertUndo(EditUndo * pUndo,sal_Bool bTryMerge)274 void ImpEditEngine::InsertUndo( EditUndo* pUndo, sal_Bool bTryMerge )
275 {
276 	DBG_ASSERT( !IsInUndo(), "InsertUndo im Undomodus!" );
277 	if ( pUndoMarkSelection )
278 	{
279 		EditUndoMarkSelection* pU = new EditUndoMarkSelection( this, *pUndoMarkSelection );
280 		GetUndoManager().AddUndoAction( pU, sal_False );
281 		delete pUndoMarkSelection;
282 		pUndoMarkSelection = NULL;
283 	}
284 	GetUndoManager().AddUndoAction( pUndo, bTryMerge );
285 
286 	mbLastTryMerge = bTryMerge;
287 }
288 
ResetUndoManager()289 void ImpEditEngine::ResetUndoManager()
290 {
291 	if ( HasUndoManager() )
292 		GetUndoManager().Clear();
293 }
294 
EnableUndo(sal_Bool bEnable)295 void ImpEditEngine::EnableUndo( sal_Bool bEnable )
296 {
297 	// Beim Umschalten des Modus Liste loeschen:
298 	if ( bEnable != IsUndoEnabled() )
299 		ResetUndoManager();
300 
301 	bUndoEnabled = bEnable;
302 }
303 
Undo(EditView * pView)304 sal_Bool ImpEditEngine::Undo( EditView* pView )
305 {
306 	if ( HasUndoManager() && GetUndoManager().GetUndoActionCount() )
307 	{
308 		SetActiveView( pView );
309 		GetUndoManager().Undo();
310 		return sal_True;
311 	}
312 	return sal_False;
313 }
314 
Redo(EditView * pView)315 sal_Bool ImpEditEngine::Redo( EditView* pView )
316 {
317 	if ( HasUndoManager() && GetUndoManager().GetRedoActionCount() )
318 	{
319 		SetActiveView( pView );
320 		GetUndoManager().Redo();
321 		return sal_True;
322 	}
323 	return sal_False;
324 }
325 
Repeat(EditView *)326 sal_Bool ImpEditEngine::Repeat( EditView* /* pView */ )
327 {
328 	if ( HasUndoManager() && GetUndoManager().GetRepeatActionCount() )
329 	{
330 		DBG_WARNING( "Repeat nicht implementiert!" );
331 		return sal_True;
332 	}
333 	return sal_False;
334 }
335 
GetAttribs(EditSelection aSel,sal_Bool bOnlyHardAttrib)336 SfxItemSet ImpEditEngine::GetAttribs( EditSelection aSel, sal_Bool bOnlyHardAttrib )
337 {
338 	DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 );
339 
340 	aSel.Adjust( aEditDoc );
341 
342 #if OSL_DEBUG_LEVEL > 1
343 //    if ( ( aSel.Min().GetNode() == aSel.Max().GetNode() ) && ( bOnlyHardAttrib == EditEngineAttribs_All ) )
344 //        return GetAttribs( aEditDoc.GetPos( aSel.Min().GetNode() ), aSel.Min().GetIndex(), aSel.Max().GetIndex(), GETATTRIBS_ALL );
345 #endif
346 
347 
348 	SfxItemSet aCurSet( GetEmptyItemSet() );
349 
350 	sal_uInt32 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
351 	sal_uInt32 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
352 
353 	// ueber die Absaetze iterieren...
354 	for ( sal_uInt32 nNode = nStartNode; nNode <= nEndNode; nNode++	)
355 	{
356 		ContentNode* pNode = aEditDoc.GetObject( nNode );
357 		DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: GetAttrib" );
358 
359 		xub_StrLen nStartPos = 0;
360 		xub_StrLen nEndPos = pNode->Len();
361 		if ( nNode == nStartNode )
362 			nStartPos = aSel.Min().GetIndex();
363 		if ( nNode == nEndNode ) // kann auch == nStart sein!
364 			nEndPos = aSel.Max().GetIndex();
365 
366 		// Problem: Vorlagen....
367 		// => Andersrum:
368 		// 1) Harte Zeichenattribute, wie gehabt...
369 		// 2) Nur wenn OFF, Style and Absatzattr. pruefen...
370 
371 		// Erst die ganz harte Formatierung...
372 		aEditDoc.FindAttribs( pNode, nStartPos, nEndPos, aCurSet );
373 
374 		if( bOnlyHardAttrib != EditEngineAttribs_OnlyHard )
375 		{
376 			// Und dann Absatzformatierung und Vorlage...
377 			// SfxStyleSheet* pStyle = pNode->GetStyleSheet();
378 			for ( sal_uInt16 nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++)
379 			{
380 				if ( aCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
381 				{
382 					if ( bOnlyHardAttrib == EditEngineAttribs_All )
383 					{
384 						const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItem( nWhich );
385 						aCurSet.Put( rItem );
386 					}
387 					else if ( pNode->GetContentAttribs().GetItems().GetItemState( nWhich ) == SFX_ITEM_ON )
388 					{
389 						const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItems().Get( nWhich );
390 						aCurSet.Put( rItem );
391 					}
392 				}
393 				else if ( aCurSet.GetItemState( nWhich ) == SFX_ITEM_ON )
394 				{
395 					const SfxPoolItem* pItem = NULL;
396 					if ( bOnlyHardAttrib == EditEngineAttribs_All )
397 					{
398 						pItem = &pNode->GetContentAttribs().GetItem( nWhich );
399 					}
400 					else if ( pNode->GetContentAttribs().GetItems().GetItemState( nWhich ) == SFX_ITEM_ON )
401 					{
402 						pItem = &pNode->GetContentAttribs().GetItems().Get( nWhich );
403 					}
404 					// pItem can only be NULL when bOnlyHardAttrib...
405 					if ( !pItem || ( *pItem != aCurSet.Get( nWhich ) ) )
406 					{
407 						// Problem: Wenn Absatzvorlage mit z.B. Font,
408 						// aber Font hart und anders und komplett in Selektion
409 						// Falsch, wenn invalidiert....
410 						// => Lieber nicht invalidieren, UMSTELLEN!
411 						// Besser waere, Absatzweise ein ItemSet zu fuellen
412 						// und dieses mit dem gesmten vergleichen.
413 	//						aCurSet.InvalidateItem( nWhich );
414 						if ( nWhich <= EE_PARA_END )
415 							aCurSet.InvalidateItem( nWhich );
416 					}
417 				}
418 			}
419 		}
420 	}
421 
422 	// Leere Slots mit Defaults fuellen...
423     if ( bOnlyHardAttrib == EditEngineAttribs_All )
424     {
425 	    for ( sal_uInt16 nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++ )
426 	    {
427 		    if ( aCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
428 		    {
429 			    aCurSet.Put( aEditDoc.GetItemPool().GetDefaultItem( nWhich ) );
430 		    }
431 	    }
432     }
433 	return aCurSet;
434 }
435 
436 
GetAttribs(sal_uInt32 nPara,sal_uInt16 nStart,sal_uInt16 nEnd,sal_uInt8 nFlags) const437 SfxItemSet ImpEditEngine::GetAttribs( sal_uInt32 nPara, sal_uInt16 nStart, sal_uInt16 nEnd, sal_uInt8 nFlags ) const
438 {
439     // MT: #94002# Optimized function with less Puts(), which cause unnecessary cloning from default items.
440     // If this works, change GetAttribs( EditSelection ) to use this for each paragraph and merge the results!
441 
442     DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 );
443 
444     ContentNode* pNode = aEditDoc.SaveGetObject( nPara );
445     DBG_ASSERT( pNode, "GetAttribs - unknown paragraph!" );
446     DBG_ASSERT( nStart <= nEnd, "getAttribs: Start > End not supported!" );
447 
448     SfxItemSet aAttribs( ((ImpEditEngine*)this)->GetEmptyItemSet() );
449 
450     if ( pNode )
451     {
452         if ( nEnd > pNode->Len() )
453             nEnd = pNode->Len();
454 
455         if ( nStart > nEnd )
456             nStart = nEnd;
457 
458         // StyleSheet / Parattribs...
459 
460         if ( pNode->GetStyleSheet() && ( nFlags & GETATTRIBS_STYLESHEET ) )
461             aAttribs.Set( pNode->GetStyleSheet()->GetItemSet(), sal_True );
462 
463         if ( nFlags & GETATTRIBS_PARAATTRIBS )
464             aAttribs.Put( pNode->GetContentAttribs().GetItems() );
465 
466         // CharAttribs...
467 
468         if ( nFlags & GETATTRIBS_CHARATTRIBS )
469         {
470             // Make testing easier...
471             pNode->GetCharAttribs().OptimizeRanges( ((ImpEditEngine*)this)->GetEditDoc().GetItemPool() );
472 
473             const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs();
474             for ( sal_uInt16 nAttr = 0; nAttr < rAttrs.Count(); nAttr++ )
475             {
476                 EditCharAttrib* pAttr = rAttrs.GetObject( nAttr );
477 
478                 if ( nStart == nEnd )
479                 {
480                     sal_uInt16 nCursorPos = nStart;
481                     if ( ( pAttr->GetStart() <= nCursorPos ) && ( pAttr->GetEnd() >= nCursorPos ) )
482                     {
483                         // To be used the attribute has to start BEFORE the position, or it must be a
484                         // new empty attr AT the position, or we are on position 0.
485                         if ( ( pAttr->GetStart() < nCursorPos ) || pAttr->IsEmpty() || !nCursorPos )
486                         {
487                             // maybe this attrib ends here and a new attrib with 0 Len may follow and be valid here,
488                             // but that s no problem, the empty item will come later and win.
489                             aAttribs.Put( *pAttr->GetItem() );
490                         }
491                     }
492                 }
493                 else
494                 {
495                     // Check every attribute covering the area, partial or full.
496                     if ( ( pAttr->GetStart() < nEnd ) && ( pAttr->GetEnd() > nStart ) )
497                     {
498                         if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) )
499                         {
500                             // full coverage
501                             aAttribs.Put( *pAttr->GetItem() );
502                         }
503                         else
504                         {
505                             // OptimizeRagnge() assures that not the same attr can follow for full coverage
506                             // only partial, check with current, when using para/styhe, otherwise invalid.
507                             if ( !( nFlags & (GETATTRIBS_PARAATTRIBS|GETATTRIBS_STYLESHEET) ) ||
508                                 ( *pAttr->GetItem() != aAttribs.Get( pAttr->Which() ) ) )
509                             {
510                                 aAttribs.InvalidateItem( pAttr->Which() );
511                             }
512                         }
513                     }
514                 }
515 
516                 if ( pAttr->GetStart() > nEnd )
517                 {
518                     break;
519                 }
520             }
521         }
522 	}
523 
524 	return aAttribs;
525 }
526 
527 
SetAttribs(EditSelection aSel,const SfxItemSet & rSet,sal_uInt8 nSpecial)528 void ImpEditEngine::SetAttribs( EditSelection aSel, const SfxItemSet& rSet, sal_uInt8 nSpecial )
529 {
530 	aSel.Adjust( aEditDoc );
531 
532 	// Wenn keine Selektion => die Attribute aufs Wort anwenden.
533 	// ( Der RTF-Perser sollte die Methode eigentlich nie ohne Range rufen )
534 	if ( ( nSpecial == ATTRSPECIAL_WHOLEWORD ) && !aSel.HasRange() )
535 		aSel = SelectWord( aSel, ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_False );
536 
537 	sal_uInt32 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
538 	sal_uInt32 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
539 
540 	if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() )
541 	{
542 		EditUndoSetAttribs* pUndo = CreateAttribUndo( aSel, rSet );
543 		pUndo->SetSpecial( nSpecial );
544 		InsertUndo( pUndo );
545 	}
546 
547 	sal_Bool bCheckLanguage = sal_False;
548 	if ( GetStatus().DoOnlineSpelling() )
549 	{
550 		bCheckLanguage = ( rSet.GetItemState( EE_CHAR_LANGUAGE ) == SFX_ITEM_ON ) ||
551 						 ( rSet.GetItemState( EE_CHAR_LANGUAGE_CJK ) == SFX_ITEM_ON ) ||
552 						 ( rSet.GetItemState( EE_CHAR_LANGUAGE_CTL ) == SFX_ITEM_ON );
553 	}
554 
555 	// ueber die Absaetze iterieren...
556 	for ( sal_uInt32 nNode = nStartNode; nNode <= nEndNode; nNode++	)
557 	{
558 		sal_Bool bParaAttribFound = sal_False;
559 		sal_Bool bCharAttribFound = sal_False;
560 
561 		ContentNode* pNode = aEditDoc.GetObject( nNode );
562 		ParaPortion* pPortion = GetParaPortions().GetObject( nNode );
563 
564 		DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: SetAttribs" );
565 		DBG_ASSERT( GetParaPortions().GetObject( nNode ), "Portion nicht gefunden: SetAttribs" );
566 
567 		xub_StrLen nStartPos = 0;
568 		xub_StrLen nEndPos = pNode->Len();
569 		if ( nNode == nStartNode )
570 			nStartPos = aSel.Min().GetIndex();
571 		if ( nNode == nEndNode ) // kann auch == nStart sein!
572 			nEndPos = aSel.Max().GetIndex();
573 
574 		// ueber die Items iterieren...
575 #ifdef EDITDEBUG
576 //		FILE* fp = fopen( "d:\\debug.log", "a" );
577 //		if ( fp )
578 //		{
579 //			fprintf( fp, "\n\n=> Zeichen-Attribute: Absatz %i, %i-%i\n", nNode, nStartPos, nEndPos );
580 //			DbgOutItemSet( fp, rSet, sal_True, sal_False );
581 //			fclose( fp );
582 //		}
583 #endif
584 
585 		for ( sal_uInt16 nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++)
586 		{
587 			if ( rSet.GetItemState( nWhich ) == SFX_ITEM_ON )
588 			{
589 				const SfxPoolItem& rItem = rSet.Get( nWhich );
590 				if ( nWhich <= EE_PARA_END )
591 				{
592 					pNode->GetContentAttribs().GetItems().Put( rItem );
593 					bParaAttribFound = sal_True;
594 				}
595 				else
596 				{
597 					aEditDoc.InsertAttrib( pNode, nStartPos, nEndPos, rItem );
598 					bCharAttribFound = sal_True;
599 					if ( nSpecial == ATTRSPECIAL_EDGE )
600 					{
601 						CharAttribArray& rAttribs = pNode->GetCharAttribs().GetAttribs();
602 						sal_uInt16 nAttrs = rAttribs.Count();
603 						for ( sal_uInt16 n = 0; n < nAttrs; n++ )
604 						{
605 							EditCharAttrib* pAttr = rAttribs.GetObject( n );
606 							if ( pAttr->GetStart() > nEndPos )
607 								break;
608 
609 							if ( ( pAttr->GetEnd() == nEndPos ) && ( pAttr->Which() == nWhich ) )
610 							{
611 								pAttr->SetEdge( sal_True );
612 								break;
613 							}
614 						}
615 					}
616 				}
617 			}
618 		}
619 
620 		if ( bParaAttribFound )
621 		{
622 			ParaAttribsChanged( pPortion->GetNode() );
623 		}
624 		else if ( bCharAttribFound )
625 		{
626 			bFormatted = sal_False;
627 			if ( !pNode->Len() || ( nStartPos != nEndPos  ) )
628 			{
629 				pPortion->MarkSelectionInvalid( nStartPos, nEndPos-nStartPos );
630 				if ( bCheckLanguage )
631 					pNode->GetWrongList()->MarkInvalid( nStartPos, nEndPos );
632 			}
633 		}
634 	}
635 }
636 
RemoveCharAttribs(EditSelection aSel,sal_Bool bRemoveParaAttribs,sal_uInt16 nWhich)637 void ImpEditEngine::RemoveCharAttribs( EditSelection aSel, sal_Bool bRemoveParaAttribs, sal_uInt16 nWhich )
638 {
639 	aSel.Adjust( aEditDoc );
640 
641 	sal_uInt32 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
642 	sal_uInt32 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
643 
644 	const SfxItemSet* _pEmptyItemSet = bRemoveParaAttribs ? &GetEmptyItemSet() : 0;
645 
646 	if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() )
647 	{
648 		// Eventuel spezielles Undo, oder ItemSet*
649 		EditUndoSetAttribs* pUndo = CreateAttribUndo( aSel, GetEmptyItemSet() );
650 		pUndo->SetRemoveAttribs( sal_True );
651 		pUndo->SetRemoveParaAttribs( bRemoveParaAttribs );
652 		pUndo->SetRemoveWhich( nWhich );
653 		InsertUndo( pUndo );
654 	}
655 
656 	// ueber die Absaetze iterieren...
657 	for ( sal_uInt32 nNode = nStartNode; nNode <= nEndNode; nNode++	)
658 	{
659 		ContentNode* pNode = aEditDoc.GetObject( nNode );
660 		ParaPortion* pPortion = GetParaPortions().GetObject( nNode );
661 
662 		DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: SetAttribs" );
663 		DBG_ASSERT( GetParaPortions().SaveGetObject( nNode ), "Portion nicht gefunden: SetAttribs" );
664 
665 		xub_StrLen nStartPos = 0;
666 		xub_StrLen nEndPos = pNode->Len();
667 		if ( nNode == nStartNode )
668 			nStartPos = aSel.Min().GetIndex();
669 		if ( nNode == nEndNode ) // kann auch == nStart sein!
670 			nEndPos = aSel.Max().GetIndex();
671 
672 		// Optimieren: Wenn ganzer Absatz, dann RemoveCharAttribs( nPara )?!
673 		sal_Bool bChanged = aEditDoc.RemoveAttribs( pNode, nStartPos, nEndPos, nWhich );
674 		if ( bRemoveParaAttribs )
675         {
676 			SetParaAttribs( nNode, *_pEmptyItemSet );	// Invalidiert
677         }
678 		else
679 		{
680 			// Bei 'Format-Standard' sollen auch die Zeichenattribute verschwinden,
681 			// die von der DrawingEngine als Absatzattribute eingestellt wurden.
682 			// Diese koennen sowieso nicht vom Anwender eingestellt worden sein.
683 
684             // #106871# Not when nWhich
685             // Would have been better to offer a separate method for format/standard...
686             if ( !nWhich )
687             {
688 			    SfxItemSet aAttribs( GetParaAttribs( nNode ) );
689 			    for ( sal_uInt16 nW = EE_CHAR_START; nW <= EE_CHAR_END; nW++ )
690 				    aAttribs.ClearItem( nW );
691 			    SetParaAttribs( nNode, aAttribs );
692             }
693 		}
694 
695 		if ( bChanged && !bRemoveParaAttribs )
696 		{
697 			bFormatted = sal_False;
698 			pPortion->MarkSelectionInvalid( nStartPos, nEndPos-nStartPos );
699 		}
700 	}
701 }
702 
703 typedef EditCharAttrib* EditCharAttribPtr;
704 
RemoveCharAttribs(sal_uInt32 nPara,sal_uInt16 nWhich,sal_Bool bRemoveFeatures)705 void ImpEditEngine::RemoveCharAttribs( sal_uInt32 nPara, sal_uInt16 nWhich, sal_Bool bRemoveFeatures )
706 {
707 	ContentNode* pNode = aEditDoc.SaveGetObject( nPara );
708 	ParaPortion* pPortion = GetParaPortions().SaveGetObject( nPara );
709 
710 	DBG_ASSERT( pNode, "Node nicht gefunden: RemoveCharAttribs" );
711 	DBG_ASSERT( pPortion, "Portion nicht gefunden: RemoveCharAttribs" );
712 
713 	if ( !pNode )
714 		return;
715 
716 	sal_uInt16 nAttr = 0;
717 	EditCharAttribPtr pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
718 	while ( pAttr )
719 	{
720 		if ( ( !pAttr->IsFeature() || bRemoveFeatures ) &&
721 			 ( !nWhich || ( pAttr->GetItem()->Which() == nWhich ) ) )
722 		{
723 			pNode->GetCharAttribs().GetAttribs().Remove( nAttr );
724 			delete pAttr;
725 			nAttr--;
726 		}
727 		nAttr++;
728 		pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
729 	}
730 
731 	pPortion->MarkSelectionInvalid( 0, pNode->Len() );
732 }
733 
SetParaAttribs(sal_uInt32 nPara,const SfxItemSet & rSet)734 void ImpEditEngine::SetParaAttribs( sal_uInt32 nPara, const SfxItemSet& rSet )
735 {
736 	ContentNode* pNode = aEditDoc.SaveGetObject( nPara );
737 
738 	if ( !pNode )
739 		return;
740 
741 #ifdef EDITDEBUG
742 //		FILE* fp = fopen( "d:\\debug.log", "a" );
743 //		if ( fp )
744 //		{
745 //			fprintf( fp, "\n\n=> Absatz-Attribute: Absatz %i\n", nPara );
746 //			DbgOutItemSet( fp, rSet, sal_True, sal_False );
747 //			fclose( fp );
748 //		}
749 #endif
750 
751 	if ( !( pNode->GetContentAttribs().GetItems() == rSet ) )
752 	{
753 		if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() )
754 		{
755 			if ( rSet.GetPool() != &aEditDoc.GetItemPool() )
756 			{
757 				SfxItemSet aTmpSet( GetEmptyItemSet() );
758 				aTmpSet.Put( rSet );
759 				InsertUndo( new EditUndoSetParaAttribs( this, nPara, pNode->GetContentAttribs().GetItems(), aTmpSet ) );
760 			}
761 			else
762 			{
763 				InsertUndo( new EditUndoSetParaAttribs( this, nPara, pNode->GetContentAttribs().GetItems(), rSet ) );
764 			}
765 		}
766 		pNode->GetContentAttribs().GetItems().Set( rSet );
767 		if ( aStatus.UseCharAttribs() )
768 			pNode->CreateDefFont();
769 
770 		ParaAttribsChanged( pNode );
771 	}
772 }
773 
GetParaAttribs(sal_uInt32 nPara) const774 const SfxItemSet& ImpEditEngine::GetParaAttribs( sal_uInt32 nPara ) const
775 {
776 	ContentNode* pNode = aEditDoc.GetObject( nPara );
777 	DBG_ASSERT( pNode, "Node nicht gefunden: GetParaAttribs" );
778 	return pNode->GetContentAttribs().GetItems();
779 }
780 
HasParaAttrib(sal_uInt32 nPara,sal_uInt16 nWhich) const781 sal_Bool ImpEditEngine::HasParaAttrib( sal_uInt32 nPara, sal_uInt16 nWhich ) const
782 {
783 	ContentNode* pNode = aEditDoc.GetObject( nPara );
784 	DBG_ASSERT( pNode, "Node nicht gefunden: HasParaAttrib" );
785 
786 	return pNode->GetContentAttribs().HasItem( nWhich );
787 }
788 
GetParaAttrib(sal_uInt32 nPara,sal_uInt16 nWhich) const789 const SfxPoolItem& ImpEditEngine::GetParaAttrib( sal_uInt32 nPara, sal_uInt16 nWhich ) const
790 {
791 	ContentNode* pNode = aEditDoc.GetObject( nPara );
792 	DBG_ASSERT( pNode, "Node nicht gefunden: GetParaAttrib" );
793 
794     return pNode->GetContentAttribs().GetItem( nWhich );
795 }
796 
GetCharAttribs(sal_uInt32 nPara,EECharAttribArray & rLst) const797 void ImpEditEngine::GetCharAttribs( sal_uInt32 nPara, EECharAttribArray& rLst ) const
798 {
799 	rLst.Remove( 0, rLst.Count() );
800 	ContentNode* pNode = aEditDoc.GetObject( nPara );
801 	if ( pNode )
802 	{
803 		for ( sal_uInt16 nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ )
804 		{
805 			EditCharAttribPtr pAttr = pNode->GetCharAttribs().GetAttribs()[ nAttr ];
806 			EECharAttrib aEEAttr;
807 			aEEAttr.pAttr = pAttr->GetItem();
808 			aEEAttr.nPara = nPara;
809 			aEEAttr.nStart = pAttr->GetStart();
810 			aEEAttr.nEnd = pAttr->GetEnd();
811 			rLst.Insert( aEEAttr, rLst.Count() );
812 		}
813 	}
814 }
815 
ParaAttribsToCharAttribs(ContentNode * pNode)816 void ImpEditEngine::ParaAttribsToCharAttribs( ContentNode* pNode )
817 {
818 	pNode->GetCharAttribs().DeleteEmptyAttribs( GetEditDoc().GetItemPool() );
819 	xub_StrLen nEndPos = pNode->Len();
820 	for ( sal_uInt16 nWhich = EE_CHAR_START; nWhich <= EE_CHAR_END; nWhich++ )
821 	{
822 		if ( pNode->GetContentAttribs().HasItem( nWhich ) )
823 		{
824 			const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItem( nWhich );
825 			// Die Luecken auffuellen:
826 			sal_uInt16 nLastEnd = 0;
827 			EditCharAttrib* pAttr = pNode->GetCharAttribs().FindNextAttrib( nWhich, nLastEnd );
828 			while ( pAttr )
829 			{
830                 nLastEnd = pAttr->GetEnd();
831 				if ( pAttr->GetStart() > nLastEnd )
832 					aEditDoc.InsertAttrib( pNode, nLastEnd, pAttr->GetStart(), rItem );
833 				// #112831# Last Attr might go from 0xffff to 0x0000
834 				pAttr = nLastEnd ? pNode->GetCharAttribs().FindNextAttrib( nWhich, nLastEnd ) : NULL;
835 			}
836 
837 			// Und den Rest:
838 			if ( nLastEnd < nEndPos )
839 				aEditDoc.InsertAttrib( pNode, nLastEnd, nEndPos, rItem );
840 		}
841 	}
842 	bFormatted = sal_False;
843 	// Portion braucht hier nicht invalidiert werden, geschieht woanders.
844 }
845 
IdleFormattter()846 IdleFormattter::IdleFormattter()
847 {
848 	pView = 0;
849 	nRestarts = 0;
850 }
851 
~IdleFormattter()852 IdleFormattter::~IdleFormattter()
853 {
854 	pView = 0;
855 }
856 
DoIdleFormat(EditView * pV)857 void IdleFormattter::DoIdleFormat( EditView* pV )
858 {
859 	pView = pV;
860 
861 	if ( IsActive() )
862 		nRestarts++;
863 
864 	if ( nRestarts > 4 )
865 		ForceTimeout();
866 	else
867 		Start();
868 }
869 
ForceTimeout()870 void IdleFormattter::ForceTimeout()
871 {
872 	if ( IsActive() )
873 	{
874 		Stop();
875 		((Link&)GetTimeoutHdl()).Call( this );
876 	}
877 }
878 
ImplIMEInfos(const EditPaM & rPos,const String & rOldTextAfterStartPos)879 ImplIMEInfos::ImplIMEInfos( const EditPaM& rPos, const String& rOldTextAfterStartPos )
880  : aOldTextAfterStartPos( rOldTextAfterStartPos )
881 {
882 	aPos = rPos;
883 	nLen = 0;
884 	bCursor = sal_True;
885 	pAttribs = NULL;
886 	bWasCursorOverwrite = sal_False;
887 }
888 
~ImplIMEInfos()889 ImplIMEInfos::~ImplIMEInfos()
890 {
891 	delete[] pAttribs;
892 }
893 
CopyAttribs(const sal_uInt16 * pA,sal_uInt16 nL)894 void ImplIMEInfos::CopyAttribs( const sal_uInt16* pA, sal_uInt16 nL )
895 {
896 	nLen = nL;
897 	delete pAttribs;
898 	pAttribs = new sal_uInt16[ nL ];
899 	memcpy( pAttribs, pA, nL*sizeof(sal_uInt16) );
900 }
901 
DestroyAttribs()902 void ImplIMEInfos::DestroyAttribs()
903 {
904 	delete[] pAttribs;
905 	pAttribs = NULL;
906     nLen = 0;
907 }
908