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 <vcl/wrkwin.hxx>
28 #include <vcl/dialog.hxx>
29 #include <vcl/msgbox.hxx>
30 #include <vcl/svapp.hxx>
31
32 #include <impedit.hxx>
33 #include <editeng/editview.hxx>
34 #include <editeng/editeng.hxx>
35 #include <edtspell.hxx>
36 #include <editeng/flditem.hxx>
37 #include <editeng/fontitem.hxx>
38 #include <svl/intitem.hxx>
39 #include <svl/eitem.hxx>
40 #include <editeng/unolingu.hxx>
41 #include <linguistic/lngprops.hxx>
42 #include <com/sun/star/beans/XPropertySet.hpp>
43
44 using ::rtl::OUString;
45 using namespace com::sun::star::uno;
46 using namespace com::sun::star::beans;
47 using namespace com::sun::star::linguistic2;
48
49
EditSpellWrapper(Window * _pWin,Reference<XSpellChecker1> & xChecker,sal_Bool bIsStart,sal_Bool bIsAllRight,EditView * pView)50 EditSpellWrapper::EditSpellWrapper( Window* _pWin,
51 Reference< XSpellChecker1 > &xChecker,
52 sal_Bool bIsStart, sal_Bool bIsAllRight, EditView* pView ) :
53 SvxSpellWrapper( _pWin, xChecker, bIsStart, bIsAllRight )
54 {
55 DBG_ASSERT( pView, "Es muss eine View uebergeben werden!" );
56 // IgnoreList behalten, ReplaceList loeschen...
57 if (SvxGetChangeAllList().is())
58 SvxGetChangeAllList()->clear();
59 pEditView = pView;
60 }
61
SpellStart(SvxSpellArea eArea)62 void __EXPORT EditSpellWrapper::SpellStart( SvxSpellArea eArea )
63 {
64 ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
65 SpellInfo* pSpellInfo = pImpEE->GetSpellInfo();
66
67 if ( eArea == SVX_SPELL_BODY_START )
68 {
69 // Wird gerufen, wenn
70 // a) Spell-Forwad ist am Ende angekomment und soll von vorne beginnen
71 // IsEndDone() liefert auch sal_True, wenn Rueckwaerts-Spelling am Ende gestartet wird!
72 if ( IsEndDone() )
73 {
74 pSpellInfo->bSpellToEnd = sal_False;
75 pSpellInfo->aSpellTo = pSpellInfo->aSpellStart;
76 pEditView->GetImpEditView()->SetEditSelection(
77 pImpEE->GetEditDoc().GetStartPaM() );
78 }
79 else
80 {
81 pSpellInfo->bSpellToEnd = sal_True;
82 pSpellInfo->aSpellTo = pImpEE->CreateEPaM(
83 pImpEE->GetEditDoc().GetStartPaM() );
84 }
85 }
86 else if ( eArea == SVX_SPELL_BODY_END )
87 {
88 // Wird gerufen, wenn
89 // a) Spell-Forwad wird gestartet
90 // IsStartDone() liefert auch sal_True, wenn Vorwaerts-Spelling am Anfang gestartet wird!
91 if ( !IsStartDone() )
92 {
93 pSpellInfo->bSpellToEnd = sal_True;
94 pSpellInfo->aSpellTo = pImpEE->CreateEPaM(
95 pImpEE->GetEditDoc().GetEndPaM() );
96 }
97 else
98 {
99 pSpellInfo->bSpellToEnd = sal_False;
100 pSpellInfo->aSpellTo = pSpellInfo->aSpellStart;
101 pEditView->GetImpEditView()->SetEditSelection(
102 pImpEE->GetEditDoc().GetEndPaM() );
103 }
104 }
105 else if ( eArea == SVX_SPELL_BODY )
106 {
107 ; // Wird ueber SpellNextDocument von App gehandelt
108
109 // pSpellInfo->bSpellToEnd = sal_True;
110 // pSpellInfo->aSpellTo = pImpEE->CreateEPaM( pImpEE->GetEditDoc().GetEndPaM() );
111 }
112 else
113 {
114 DBG_ERROR( "SpellStart: Unknown Area!" );
115 }
116 }
117
SpellContinue()118 sal_Bool EditSpellWrapper::SpellContinue()
119 {
120 SetLast( pEditView->GetImpEditEngine()->ImpSpell( pEditView ) );
121 return GetLast().is();
122 }
123
SpellEnd()124 void __EXPORT EditSpellWrapper::SpellEnd()
125 {
126 // Base class will show language errors...
127 SvxSpellWrapper::SpellEnd();
128 }
129
HasOtherCnt()130 sal_Bool __EXPORT EditSpellWrapper::HasOtherCnt()
131 {
132 return sal_False;
133 }
134
SpellMore()135 sal_Bool __EXPORT EditSpellWrapper::SpellMore()
136 {
137 ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
138 SpellInfo* pSpellInfo = pImpEE->GetSpellInfo();
139 sal_Bool bMore = sal_False;
140 if ( pSpellInfo->bMultipleDoc )
141 {
142 bMore = pImpEE->GetEditEnginePtr()->SpellNextDocument();
143 SetCurTextObj( pImpEE->GetEditEnginePtr()->GetCurTextObj() );
144 if ( bMore )
145 {
146 // Der Text wurde in diese Engine getreten, bei Rueckwaerts
147 // muss die Selektion hinten sein.
148 Reference< XPropertySet > xProp( SvxGetLinguPropertySet() );
149 pEditView->GetImpEditView()->SetEditSelection(
150 pImpEE->GetEditDoc().GetStartPaM() );
151 }
152 }
153 return bMore;
154 }
155
ScrollArea()156 void __EXPORT EditSpellWrapper::ScrollArea()
157 {
158 // Keine weitere Aktion noetig...
159 // Es sei denn, der Bereich soll in die Mitte gescrollt werden,
160 // und nicht irgendwo stehen.
161 }
162
ReplaceAll(const String & rNewText,sal_Int16)163 void __EXPORT EditSpellWrapper::ReplaceAll( const String &rNewText,
164 sal_Int16 )
165 {
166 // Wird gerufen, wenn Wort in ReplaceList des SpellCheckers
167 pEditView->InsertText( rNewText );
168 CheckSpellTo();
169 }
170
ChangeWord(const String & rNewWord,const sal_uInt16)171 void __EXPORT EditSpellWrapper::ChangeWord( const String& rNewWord,
172 const sal_uInt16 )
173 {
174 // Wird gerufen, wenn Wort Button Change
175 // bzw. intern von mir bei ChangeAll
176
177 // Wenn Punkt hinterm Wort, wird dieser nicht mitgegeben.
178 // Falls '"' => PreStripped.
179 String aNewWord( rNewWord );
180 pEditView->InsertText( aNewWord );
181 CheckSpellTo();
182 }
183
ChangeThesWord(const String & rNewWord)184 void __EXPORT EditSpellWrapper::ChangeThesWord( const String& rNewWord )
185 {
186 pEditView->InsertText( rNewWord );
187 CheckSpellTo();
188 }
189
AutoCorrect(const String &,const String &)190 void __EXPORT EditSpellWrapper::AutoCorrect( const String&, const String& )
191 {
192 }
193
CheckSpellTo()194 void EditSpellWrapper::CheckSpellTo()
195 {
196 ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
197 SpellInfo* pSpellInfo = pImpEE->GetSpellInfo();
198 EditPaM aPaM( pEditView->GetImpEditView()->GetEditSelection().Max() );
199 EPaM aEPaM = pImpEE->CreateEPaM( aPaM );
200 if ( aEPaM.nPara == pSpellInfo->aSpellTo.nPara )
201 {
202 // prueffen, ob SpellToEnd noch gueltiger Index, falls in dem Absatz
203 // ersetzt wurde.
204 if ( pSpellInfo->aSpellTo.nIndex > aPaM.GetNode()->Len() )
205 pSpellInfo->aSpellTo.nIndex = aPaM.GetNode()->Len();
206 }
207 }
208
209 //////////////////////////////////////////////////////////////////////
210
211 SV_IMPL_VARARR( WrongRanges, WrongRange );
212
WrongList()213 WrongList::WrongList()
214 {
215 nInvalidStart = 0;
216 nInvalidEnd = 0xFFFF;
217 }
218
~WrongList()219 WrongList::~WrongList()
220 {
221 }
222
MarkInvalid(sal_uInt16 nS,sal_uInt16 nE)223 void WrongList::MarkInvalid( sal_uInt16 nS, sal_uInt16 nE )
224 {
225 if ( ( nInvalidStart == NOT_INVALID ) || ( nInvalidStart > nS ) )
226 nInvalidStart = nS;
227 if ( nInvalidEnd < nE )
228 nInvalidEnd = nE;
229 }
230
TextInserted(sal_uInt16 nPos,sal_uInt16 nNew,sal_Bool bPosIsSep)231 void WrongList::TextInserted( sal_uInt16 nPos, sal_uInt16 nNew, sal_Bool bPosIsSep )
232 {
233 if ( !IsInvalid() )
234 {
235 nInvalidStart = nPos;
236 nInvalidEnd = nPos+nNew;
237 }
238 else
239 {
240 if ( nInvalidStart > nPos )
241 nInvalidStart = nPos;
242 if ( nInvalidEnd >= nPos )
243 nInvalidEnd = nInvalidEnd + nNew;
244 else
245 nInvalidEnd = nPos+nNew;
246 }
247
248 for ( sal_uInt16 n = 0; n < Count(); n++ )
249 {
250 WrongRange& rWrong = GetObject( n );
251 sal_Bool bRefIsValid = sal_True;
252 if ( rWrong.nEnd >= nPos )
253 {
254 // Alle Wrongs hinter der Einfuegeposition verschieben...
255 if ( rWrong.nStart > nPos )
256 {
257 rWrong.nStart = rWrong.nStart + nNew;
258 rWrong.nEnd = rWrong.nEnd + nNew;
259 }
260 // 1: Startet davor, geht bis nPos...
261 else if ( rWrong.nEnd == nPos )
262 {
263 // Sollte bei einem Blank unterbunden werden!
264 if ( !bPosIsSep )
265 rWrong.nEnd = rWrong.nEnd + nNew;
266 }
267 // 2: Startet davor, geht hinter Pos...
268 else if ( ( rWrong.nStart < nPos ) && ( rWrong.nEnd > nPos ) )
269 {
270 rWrong.nEnd = rWrong.nEnd + nNew;
271 // Bei einem Trenner das Wrong entfernen und neu pruefen
272 if ( bPosIsSep )
273 {
274 // Wrong aufteilen...
275 WrongRange aNewWrong( rWrong.nStart, nPos );
276 rWrong.nStart = nPos+1;
277 Insert( aNewWrong, n );
278 bRefIsValid = sal_False; // Referenz nach Insert nicht mehr gueltig, der andere wurde davor an dessen Position eingefuegt
279 n++; // Diesen nicht nochmal...
280 }
281 }
282 // 3: Attribut startet auf Pos...
283 else if ( rWrong.nStart == nPos )
284 {
285 rWrong.nEnd = rWrong.nEnd + nNew;
286 if ( bPosIsSep )
287 rWrong.nStart++;
288 }
289 }
290 DBG_ASSERT( !bRefIsValid || ( rWrong.nStart < rWrong.nEnd ),
291 "TextInserted, WrongRange: Start >= End?!" );
292 }
293
294 DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" );
295 }
296
TextDeleted(sal_uInt16 nPos,sal_uInt16 nDeleted)297 void WrongList::TextDeleted( sal_uInt16 nPos, sal_uInt16 nDeleted )
298 {
299 sal_uInt16 nEndChanges = nPos+nDeleted;
300 if ( !IsInvalid() )
301 {
302 sal_uInt16 nNewInvalidStart = nPos ? nPos - 1 : 0;
303 nInvalidStart = nNewInvalidStart;
304 nInvalidEnd = nNewInvalidStart + 1;
305 }
306 else
307 {
308 if ( nInvalidStart > nPos )
309 nInvalidStart = nPos;
310 if ( nInvalidEnd > nPos )
311 {
312 if ( nInvalidEnd > nEndChanges )
313 nInvalidEnd = nInvalidEnd - nDeleted;
314 else
315 nInvalidEnd = nPos+1;
316 }
317 }
318
319 for ( sal_uInt16 n = 0; n < Count(); n++ )
320 {
321 WrongRange& rWrong = GetObject( n );
322 sal_Bool bDelWrong = sal_False;
323 if ( rWrong.nEnd >= nPos )
324 {
325 // Alles Wrongs hinter der Einfuegeposition verschieben...
326 if ( rWrong.nStart >= nEndChanges )
327 {
328 rWrong.nStart = rWrong.nStart - nDeleted;
329 rWrong.nEnd = rWrong.nEnd - nDeleted;
330 }
331 // 1. Innenliegende Wrongs loeschen...
332 else if ( ( rWrong.nStart >= nPos ) && ( rWrong.nEnd <= nEndChanges ) )
333 {
334 bDelWrong = sal_True;
335 }
336 // 2. Wrong beginnt davor, endet drinnen oder dahinter...
337 else if ( ( rWrong.nStart <= nPos ) && ( rWrong.nEnd > nPos ) )
338 {
339 if ( rWrong.nEnd <= nEndChanges ) // endet drinnen
340 rWrong.nEnd = nPos;
341 else
342 rWrong.nEnd = rWrong.nEnd - nDeleted; // endet dahinter
343 }
344 // 3. Wrong beginnt drinnen, endet dahinter...
345 else if ( ( rWrong.nStart >= nPos ) && ( rWrong.nEnd > nEndChanges ) )
346 {
347 rWrong.nStart = nEndChanges;
348 rWrong.nStart = rWrong.nStart - nDeleted;
349 rWrong.nEnd = rWrong.nEnd - nDeleted;
350 }
351 }
352 DBG_ASSERT( rWrong.nStart < rWrong.nEnd,
353 "TextInserted, WrongRange: Start >= End?!" );
354 if ( bDelWrong )
355 {
356 Remove( n, 1 );
357 n--;
358 }
359 }
360
361 DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" );
362 }
363
NextWrong(sal_uInt16 & rnStart,sal_uInt16 & rnEnd) const364 sal_Bool WrongList::NextWrong( sal_uInt16& rnStart, sal_uInt16& rnEnd ) const
365 {
366 /*
367 rnStart enthaelt die Startposition, wird ggf. auf Wrong-Start korrigiert
368 rnEnd braucht nicht inizialisiert sein.
369 */
370 for ( sal_uInt16 n = 0; n < Count(); n++ )
371 {
372 WrongRange& rWrong = GetObject( n );
373 if ( rWrong.nEnd > rnStart )
374 {
375 rnStart = rWrong.nStart;
376 rnEnd = rWrong.nEnd;
377 return sal_True;
378 }
379 }
380 return sal_False;
381 }
382
HasWrong(sal_uInt16 nStart,sal_uInt16 nEnd) const383 sal_Bool WrongList::HasWrong( sal_uInt16 nStart, sal_uInt16 nEnd ) const
384 {
385 for ( sal_uInt16 n = 0; n < Count(); n++ )
386 {
387 WrongRange& rWrong = GetObject( n );
388 if ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd == nEnd ) )
389 return sal_True;
390 else if ( rWrong.nStart >= nStart )
391 break;
392 }
393 return sal_False;
394 }
395
HasAnyWrong(sal_uInt16 nStart,sal_uInt16 nEnd) const396 sal_Bool WrongList::HasAnyWrong( sal_uInt16 nStart, sal_uInt16 nEnd ) const
397 {
398 for ( sal_uInt16 n = 0; n < Count(); n++ )
399 {
400 WrongRange& rWrong = GetObject( n );
401 if ( ( rWrong.nEnd >= nStart ) && ( rWrong.nStart < nEnd ) )
402 return sal_True;
403 else if ( rWrong.nStart >= nEnd )
404 break;
405 }
406 return sal_False;
407 }
408
ClearWrongs(sal_uInt16 nStart,sal_uInt16 nEnd,const ContentNode * pNode)409 void WrongList::ClearWrongs( sal_uInt16 nStart, sal_uInt16 nEnd,
410 const ContentNode* pNode )
411 {
412 for ( sal_uInt16 n = 0; n < Count(); n++ )
413 {
414 WrongRange& rWrong = GetObject( n );
415 if ( ( rWrong.nEnd > nStart ) && ( rWrong.nStart < nEnd ) )
416 {
417 if ( rWrong.nEnd > nEnd ) // // Laeuft raus
418 {
419 rWrong.nStart = nEnd;
420 // Blanks?
421 while ( ( rWrong.nStart < pNode->Len() ) &&
422 ( ( pNode->GetChar( rWrong.nStart ) == ' ' ) ||
423 ( pNode->IsFeature( rWrong.nStart ) ) ) )
424 {
425 rWrong.nStart++;
426 }
427 }
428 else
429 {
430 Remove( n, 1 );
431 n--;
432 }
433 }
434 }
435
436 DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" );
437 }
438
InsertWrong(sal_uInt16 nStart,sal_uInt16 nEnd,sal_Bool bClearRange)439 void WrongList::InsertWrong( sal_uInt16 nStart, sal_uInt16 nEnd,
440 sal_Bool bClearRange )
441 {
442 sal_uInt16 nPos = Count();
443 for ( sal_uInt16 n = 0; n < Count(); n++ )
444 {
445 WrongRange& rWrong = GetObject( n );
446 if ( rWrong.nStart >= nStart )
447 {
448 nPos = n;
449 if ( bClearRange )
450 {
451 // Es kann eigentlich nur Passieren, dass der Wrong genau
452 // hier beginnt und weiter rauslauft, aber nicht, dass hier
453 // mehrere im Bereich liegen...
454 // Genau im Bereich darf keiner liegen, sonst darf diese Methode
455 // garnicht erst gerufen werden!
456 DBG_ASSERT( ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd > nEnd ) )
457 || ( rWrong.nStart > nEnd ), "InsertWrong: RangeMismatch!" );
458 if ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd > nEnd ) )
459 rWrong.nStart = nEnd+1;
460 }
461 break;
462 }
463 }
464 Insert( WrongRange( nStart, nEnd ), nPos );
465
466 DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" );
467 }
468
MarkWrongsInvalid()469 void WrongList::MarkWrongsInvalid()
470 {
471 if ( Count() )
472 MarkInvalid( GetObject( 0 ).nStart, GetObject( Count()-1 ).nEnd );
473 }
474
Clone() const475 WrongList* WrongList::Clone() const
476 {
477 WrongList* pNew = new WrongList;
478 for ( sal_uInt16 n = 0; n < Count(); n++ )
479 {
480 WrongRange& rWrong = GetObject( n );
481 pNew->Insert( rWrong, pNew->Count() );
482 }
483
484 return pNew;
485 }
486
487 // #i102062#
operator ==(const WrongList & rCompare) const488 bool WrongList::operator==(const WrongList& rCompare) const
489 {
490 // cleck direct members
491 if(GetInvalidStart() != rCompare.GetInvalidStart()
492 || GetInvalidEnd() != rCompare.GetInvalidEnd()
493 || Count() != rCompare.Count())
494 {
495 return false;
496 }
497
498 for(sal_uInt16 a(0); a < Count(); a++)
499 {
500 const WrongRange& rCandA(GetObject(a));
501 const WrongRange& rCandB(rCompare.GetObject(a));
502
503 if(rCandA.nStart != rCandB.nStart
504 || rCandA.nEnd != rCandB.nEnd)
505 {
506 return false;
507 }
508 }
509
510 return true;
511 }
512
513 #ifdef DBG_UTIL
DbgIsBuggy() const514 sal_Bool WrongList::DbgIsBuggy() const
515 {
516 // Pruefen, ob sich Bereiche ueberlappen
517 sal_Bool bError = sal_False;
518 for ( sal_uInt16 _nA = 0; !bError && ( _nA < Count() ); _nA++ )
519 {
520 WrongRange& rWrong = GetObject( _nA );
521 for ( sal_uInt16 nB = _nA+1; !bError && ( nB < Count() ); nB++ )
522 {
523 WrongRange& rNextWrong = GetObject( nB );
524 // 1) Start davor, End hinterm anderen Start
525 if ( ( rWrong.nStart <= rNextWrong.nStart )
526 && ( rWrong.nEnd >= rNextWrong.nStart ) )
527 bError = sal_True;
528 // 2) Start hinter anderen Start, aber noch vorm anderen End
529 else if ( ( rWrong.nStart >= rNextWrong.nStart)
530 && ( rWrong.nStart <= rNextWrong.nEnd ) )
531 bError = sal_True;
532 }
533 }
534 return bError;
535 }
536 #endif
537
538 //////////////////////////////////////////////////////////////////////
539
EdtAutoCorrDoc(ImpEditEngine * pE,ContentNode * pN,sal_uInt16 nCrsr,xub_Unicode cIns)540 EdtAutoCorrDoc::EdtAutoCorrDoc( ImpEditEngine* pE, ContentNode* pN,
541 sal_uInt16 nCrsr, xub_Unicode cIns )
542 {
543 pImpEE = pE;
544 pCurNode = pN;
545 nCursor = nCrsr;
546
547 bUndoAction = sal_False;
548 bAllowUndoAction = cIns ? sal_True : sal_False;
549 }
550
~EdtAutoCorrDoc()551 EdtAutoCorrDoc::~EdtAutoCorrDoc()
552 {
553 if ( bUndoAction )
554 pImpEE->UndoActionEnd( EDITUNDO_INSERT );
555 }
556
Delete(sal_uInt16 nStt,sal_uInt16 nEnd)557 sal_Bool EdtAutoCorrDoc::Delete( sal_uInt16 nStt, sal_uInt16 nEnd )
558 {
559 EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) );
560 pImpEE->ImpDeleteSelection( aSel );
561 DBG_ASSERT( nCursor >= nEnd, "Cursor mitten im Geschehen ?!" );
562 nCursor -= ( nEnd-nStt );
563 bAllowUndoAction = sal_False;
564 return sal_True;
565 }
566
Insert(sal_uInt16 nPos,const String & rTxt)567 sal_Bool EdtAutoCorrDoc::Insert( sal_uInt16 nPos, const String& rTxt )
568 {
569 EditSelection aSel = EditPaM( pCurNode, nPos );
570 pImpEE->ImpInsertText( aSel, rTxt );
571 DBG_ASSERT( nCursor >= nPos, "Cursor mitten im Geschehen ?!" );
572 nCursor = nCursor + rTxt.Len();
573
574 if ( bAllowUndoAction && ( rTxt.Len() == 1 ) )
575 ImplStartUndoAction();
576 bAllowUndoAction = sal_False;
577
578 return sal_True;
579 }
580
Replace(sal_uInt16 nPos,const String & rTxt)581 sal_Bool EdtAutoCorrDoc::Replace( sal_uInt16 nPos, const String& rTxt )
582 {
583 return ReplaceRange( nPos, rTxt.Len(), rTxt );
584 }
585
ReplaceRange(xub_StrLen nPos,xub_StrLen nSourceLength,const String & rTxt)586 sal_Bool EdtAutoCorrDoc::ReplaceRange( xub_StrLen nPos, xub_StrLen nSourceLength, const String& rTxt )
587 {
588 // Eigentlich ein Replace einfuehren => Entspr. UNDO
589 sal_uInt16 nEnd = nPos+nSourceLength;
590 if ( nEnd > pCurNode->Len() )
591 nEnd = pCurNode->Len();
592
593 // #i5925# First insert new text behind to be deleted text, for keeping attributes.
594 pImpEE->ImpInsertText( EditSelection( EditPaM( pCurNode, nEnd ) ), rTxt );
595 pImpEE->ImpDeleteSelection( EditSelection( EditPaM( pCurNode, nPos ), EditPaM( pCurNode, nEnd ) ) );
596
597 if ( nPos == nCursor )
598 nCursor = nCursor + rTxt.Len();
599
600 if ( bAllowUndoAction && ( rTxt.Len() == 1 ) )
601 ImplStartUndoAction();
602
603 bAllowUndoAction = sal_False;
604
605 return sal_True;
606 }
607
SetAttr(sal_uInt16 nStt,sal_uInt16 nEnd,sal_uInt16 nSlotId,SfxPoolItem & rItem)608 sal_Bool EdtAutoCorrDoc::SetAttr( sal_uInt16 nStt, sal_uInt16 nEnd,
609 sal_uInt16 nSlotId, SfxPoolItem& rItem )
610 {
611 SfxItemPool* pPool = &pImpEE->GetEditDoc().GetItemPool();
612 while ( pPool->GetSecondaryPool() &&
613 !pPool->GetName().EqualsAscii( "EditEngineItemPool" ) )
614 {
615 pPool = pPool->GetSecondaryPool();
616
617 }
618 sal_uInt16 nWhich = pPool->GetWhich( nSlotId );
619 if ( nWhich )
620 {
621 rItem.SetWhich( nWhich );
622
623 SfxItemSet aSet( pImpEE->GetEmptyItemSet() );
624 aSet.Put( rItem );
625
626 EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) );
627 aSel.Max().SetIndex( nEnd ); // ???
628 pImpEE->SetAttribs( aSel, aSet, ATTRSPECIAL_EDGE );
629 bAllowUndoAction = sal_False;
630 }
631 return sal_True;
632 }
633
SetINetAttr(sal_uInt16 nStt,sal_uInt16 nEnd,const String & rURL)634 sal_Bool EdtAutoCorrDoc::SetINetAttr( sal_uInt16 nStt, sal_uInt16 nEnd,
635 const String& rURL )
636 {
637 // Aus dem Text ein Feldbefehl machen...
638 EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) );
639 String aText = pImpEE->GetSelected( aSel );
640 aSel = pImpEE->ImpDeleteSelection( aSel );
641 DBG_ASSERT( nCursor >= nEnd, "Cursor mitten im Geschehen ?!" );
642 nCursor -= ( nEnd-nStt );
643 SvxFieldItem aField( SvxURLField( rURL, aText, SVXURLFORMAT_REPR ),
644 EE_FEATURE_FIELD );
645 pImpEE->InsertField( aSel, aField );
646 nCursor++;
647 pImpEE->UpdateFields();
648 bAllowUndoAction = sal_False;
649 return sal_True;
650 }
651
HasSymbolChars(sal_uInt16 nStt,sal_uInt16 nEnd)652 sal_Bool EdtAutoCorrDoc::HasSymbolChars( sal_uInt16 nStt, sal_uInt16 nEnd )
653 {
654 sal_uInt16 nScriptType = pImpEE->GetScriptType( EditPaM( pCurNode, nStt ) );
655 sal_uInt16 nScriptFontInfoItemId = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType );
656
657 CharAttribArray& rAttribs = pCurNode->GetCharAttribs().GetAttribs();
658 sal_uInt16 nAttrs = rAttribs.Count();
659 for ( sal_uInt16 n = 0; n < nAttrs; n++ )
660 {
661 EditCharAttrib* pAttr = rAttribs.GetObject( n );
662 if ( pAttr->GetStart() >= nEnd )
663 return sal_False;
664
665 if ( ( pAttr->Which() == nScriptFontInfoItemId ) &&
666 ( ((SvxFontItem*)pAttr->GetItem())->GetCharSet() == RTL_TEXTENCODING_SYMBOL ) )
667 {
668 // Pruefen, ob das Attribt im Bereich liegt...
669 if ( pAttr->GetEnd() >= nStt )
670 return sal_True;
671 }
672 }
673 return sal_False;
674 }
675
GetPrevPara(sal_Bool)676 const String* EdtAutoCorrDoc::GetPrevPara( sal_Bool )
677 {
678 // Vorherigen Absatz zurueck geben, damit ermittel werden kann,
679 // ob es sich beim aktuellen Wort um einen Satzanfang handelt.
680
681 bAllowUndoAction = sal_False; // Jetzt nicht mehr...
682
683 ContentList& rNodes = pImpEE->GetEditDoc();
684 sal_uInt32 nPos = rNodes.GetPos( pCurNode );
685
686 // Sonderbehandlung: Bullet => Absatzanfang => einfach NULL returnen...
687 const SfxBoolItem& rBulletState = (const SfxBoolItem&)
688 pImpEE->GetParaAttrib( nPos, EE_PARA_BULLETSTATE );
689 sal_Bool bBullet = rBulletState.GetValue() ? sal_True : sal_False;
690 if ( !bBullet && ( pImpEE->aStatus.GetControlWord() & EE_CNTRL_OUTLINER ) )
691 {
692 // Der Outliner hat im Gliederungsmodus auf Ebene 0 immer ein Bullet.
693 const SfxInt16Item& rLevel = (const SfxInt16Item&)
694 pImpEE->GetParaAttrib( nPos, EE_PARA_OUTLLEVEL );
695 if ( rLevel.GetValue() == 0 )
696 bBullet = sal_True;
697 }
698 if ( bBullet )
699 return NULL;
700
701 for ( sal_uInt32 n = nPos; n; )
702 {
703 n--;
704 ContentNode* pNode = rNodes[n];
705 if ( pNode->Len() )
706 return pNode;
707 }
708 return NULL;
709
710 }
711
ChgAutoCorrWord(sal_uInt16 & rSttPos,sal_uInt16 nEndPos,SvxAutoCorrect & rACorrect,const String ** ppPara)712 sal_Bool EdtAutoCorrDoc::ChgAutoCorrWord( sal_uInt16& rSttPos,
713 sal_uInt16 nEndPos, SvxAutoCorrect& rACorrect,
714 const String** ppPara )
715 {
716 // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort
717 // Kuerzel im Auto
718
719 bAllowUndoAction = sal_False; // Jetzt nicht mehr...
720
721 String aShort( pCurNode->Copy( rSttPos, nEndPos - rSttPos ) );
722 sal_Bool bRet = sal_False;
723
724 if( !aShort.Len() )
725 return bRet;
726
727 LanguageType eLang = pImpEE->GetLanguage( EditPaM( pCurNode, rSttPos+1 ) );
728 const SvxAutocorrWord* pFnd = rACorrect.SearchWordsInList( *pCurNode, rSttPos, nEndPos, *this, eLang );
729 if( pFnd && pFnd->IsTextOnly() )
730 {
731 // dann mal ersetzen
732 EditSelection aSel( EditPaM( pCurNode, rSttPos ),
733 EditPaM( pCurNode, nEndPos ) );
734 aSel = pImpEE->ImpDeleteSelection( aSel );
735 DBG_ASSERT( nCursor >= nEndPos, "Cursor mitten im Geschehen ?!" );
736 nCursor -= ( nEndPos-rSttPos );
737 pImpEE->ImpInsertText( aSel, pFnd->GetLong() );
738 nCursor = nCursor + pFnd->GetLong().Len();
739 if( ppPara )
740 *ppPara = pCurNode;
741 bRet = sal_True;
742 }
743
744 return bRet;
745 }
746
GetLanguage(sal_uInt16 nPos,sal_Bool) const747 LanguageType EdtAutoCorrDoc::GetLanguage( sal_uInt16 nPos, sal_Bool ) const
748 {
749 return pImpEE->GetLanguage( EditPaM( pCurNode, nPos+1 ) );
750 }
751
ImplStartUndoAction()752 void EdtAutoCorrDoc::ImplStartUndoAction()
753 {
754 sal_uInt32 nPara = pImpEE->GetEditDoc().GetPos( pCurNode );
755 ESelection aSel( nPara, nCursor, nPara, nCursor );
756 pImpEE->UndoActionStart( EDITUNDO_INSERT, aSel );
757 bUndoAction = sal_True;
758 bAllowUndoAction = sal_False;
759 }
760
761