xref: /AOO41X/main/editeng/source/editeng/impedit5.cxx (revision 5b4f8e55c8441c2fa499a3bc2ea7cc23256cdf4e)
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_uInt16 nPara) const52 SfxStyleSheet* ImpEditEngine::GetStyleSheet( sal_uInt16 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_uInt16 nStartPara = aEditDoc.GetPos( aSel.Min().GetNode() );
63     sal_uInt16 nEndPara = aEditDoc.GetPos( aSel.Max().GetNode() );
64 
65     sal_Bool _bUpdate = GetUpdateMode();
66     SetUpdateMode( sal_False );
67 
68     for ( sal_uInt16 n = nStartPara; n <= nEndPara; n++ )
69         SetStyleSheet( n, pStyle );
70 
71     SetUpdateMode( _bUpdate, 0 );
72 }
73 
SetStyleSheet(sal_uInt16 nPara,SfxStyleSheet * pStyle)74 void ImpEditEngine::SetStyleSheet( sal_uInt16 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_uInt16 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_uInt16 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_uInt16 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
207     sal_uInt16 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_uInt16 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_uInt16 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
351     sal_uInt16 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
352 
353     // ueber die Absaetze iterieren...
354     for ( sal_uInt16 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_uInt16 nPara,sal_uInt16 nStart,sal_uInt16 nEnd,sal_uInt8 nFlags) const437 SfxItemSet ImpEditEngine::GetAttribs( sal_uInt16 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_uInt16 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
538     sal_uInt16 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_uInt16 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_uInt16 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
642     sal_uInt16 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_uInt16 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_uInt16 nPara,sal_uInt16 nWhich,sal_Bool bRemoveFeatures)705 void ImpEditEngine::RemoveCharAttribs( sal_uInt16 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_uInt16 nPara,const SfxItemSet & rSet)734 void ImpEditEngine::SetParaAttribs( sal_uInt16 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_uInt16 nPara) const774 const SfxItemSet& ImpEditEngine::GetParaAttribs( sal_uInt16 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_uInt16 nPara,sal_uInt16 nWhich) const781 sal_Bool ImpEditEngine::HasParaAttrib( sal_uInt16 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_uInt16 nPara,sal_uInt16 nWhich) const789 const SfxPoolItem& ImpEditEngine::GetParaAttrib( sal_uInt16 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_uInt16 nPara,EECharAttribArray & rLst) const797 void ImpEditEngine::GetCharAttribs( sal_uInt16 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