Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <vcl/wrkwin.hxx>
22 : #include <vcl/dialog.hxx>
23 : #include <vcl/msgbox.hxx>
24 : #include <vcl/svapp.hxx>
25 :
26 : #include <impedit.hxx>
27 : #include <editeng/editview.hxx>
28 : #include <editeng/editeng.hxx>
29 : #include <edtspell.hxx>
30 : #include <editeng/flditem.hxx>
31 : #include <editeng/fontitem.hxx>
32 : #include <svl/intitem.hxx>
33 : #include <svl/eitem.hxx>
34 : #include <editeng/unolingu.hxx>
35 : #include <linguistic/lngprops.hxx>
36 : #include <com/sun/star/beans/XPropertySet.hpp>
37 :
38 : using ::rtl::OUString;
39 : using namespace com::sun::star::uno;
40 : using namespace com::sun::star::beans;
41 : using namespace com::sun::star::linguistic2;
42 :
43 :
44 6 : EditSpellWrapper::EditSpellWrapper( Window* _pWin,
45 : Reference< XSpellChecker1 > &xChecker,
46 : sal_Bool bIsStart, sal_Bool bIsAllRight, EditView* pView ) :
47 6 : SvxSpellWrapper( _pWin, xChecker, bIsStart, bIsAllRight )
48 : {
49 : SAL_WARN_IF( !pView, "editeng", "One view has to be abandoned!" );
50 : // Keep IgnoreList, delete ReplaceList...
51 6 : if (SvxGetChangeAllList().is())
52 6 : SvxGetChangeAllList()->clear();
53 6 : pEditView = pView;
54 6 : }
55 :
56 6 : void EditSpellWrapper::SpellStart( SvxSpellArea eArea )
57 : {
58 6 : EditEngine* pEE = pEditView->GetEditEngine();
59 6 : ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
60 6 : SpellInfo* pSpellInfo = pImpEE->GetSpellInfo();
61 :
62 6 : if ( eArea == SVX_SPELL_BODY_START )
63 : {
64 : // Is called when
65 : // a) Spell-Forward has arrived at the end and should restart at the top
66 : // IsEndDone() returns also sal_True, when backward-spelling is started at the end!
67 0 : if ( IsEndDone() )
68 : {
69 0 : pSpellInfo->bSpellToEnd = sal_False;
70 0 : pSpellInfo->aSpellTo = pSpellInfo->aSpellStart;
71 : pEditView->GetImpEditView()->SetEditSelection(
72 0 : pEE->GetEditDoc().GetStartPaM() );
73 : }
74 : else
75 : {
76 0 : pSpellInfo->bSpellToEnd = sal_True;
77 : pSpellInfo->aSpellTo = pImpEE->CreateEPaM(
78 0 : pEE->GetEditDoc().GetStartPaM() );
79 : }
80 : }
81 6 : else if ( eArea == SVX_SPELL_BODY_END )
82 : {
83 : // Is called when
84 : // a) Spell-Forward is launched
85 : // IsStartDone() return also sal_True, when forward-spelling is started at the beginning!
86 6 : if ( !IsStartDone() )
87 : {
88 0 : pSpellInfo->bSpellToEnd = sal_True;
89 : pSpellInfo->aSpellTo = pImpEE->CreateEPaM(
90 0 : pEE->GetEditDoc().GetEndPaM() );
91 : }
92 : else
93 : {
94 6 : pSpellInfo->bSpellToEnd = sal_False;
95 6 : pSpellInfo->aSpellTo = pSpellInfo->aSpellStart;
96 : pEditView->GetImpEditView()->SetEditSelection(
97 6 : pEE->GetEditDoc().GetEndPaM() );
98 : }
99 : }
100 : else if ( eArea == SVX_SPELL_BODY )
101 : {
102 : ; // Is handled by the App through SpellNextDocument
103 : }
104 : else
105 : {
106 : OSL_FAIL( "SpellStart: Unknown Area!" );
107 : }
108 6 : }
109 :
110 6 : sal_Bool EditSpellWrapper::SpellContinue()
111 : {
112 6 : SetLast( pEditView->GetImpEditEngine()->ImpSpell( pEditView ) );
113 6 : return GetLast().is();
114 : }
115 :
116 6 : void EditSpellWrapper::SpellEnd()
117 : {
118 : // Base class will show language errors...
119 6 : SvxSpellWrapper::SpellEnd();
120 6 : }
121 :
122 6 : sal_Bool EditSpellWrapper::HasOtherCnt()
123 : {
124 6 : return sal_False;
125 : }
126 :
127 6 : sal_Bool EditSpellWrapper::SpellMore()
128 : {
129 6 : EditEngine* pEE = pEditView->GetEditEngine();
130 6 : ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
131 6 : SpellInfo* pSpellInfo = pImpEE->GetSpellInfo();
132 6 : sal_Bool bMore = sal_False;
133 6 : if ( pSpellInfo->bMultipleDoc )
134 : {
135 0 : bMore = pEE->SpellNextDocument();
136 0 : if ( bMore )
137 : {
138 : // The text has been entered into the engine, when backwords then
139 : // it must be behind the selection.
140 0 : Reference< XPropertySet > xProp( SvxGetLinguPropertySet() );
141 : pEditView->GetImpEditView()->SetEditSelection(
142 0 : pEE->GetEditDoc().GetStartPaM() );
143 : }
144 : }
145 6 : return bMore;
146 : }
147 :
148 0 : void EditSpellWrapper::ScrollArea()
149 : {
150 : // No further action needed ...
151 : // Except for, that the area is to be scrolled in the center, and not stand
152 : // still anywhere.
153 0 : }
154 :
155 0 : void EditSpellWrapper::ReplaceAll( const String &rNewText,
156 : sal_Int16 )
157 : {
158 : // Is called when the word is in ReplaceList of the spell checker
159 0 : pEditView->InsertText( rNewText );
160 0 : CheckSpellTo();
161 0 : }
162 :
163 0 : void EditSpellWrapper::ChangeWord( const String& rNewWord,
164 : const sal_uInt16 )
165 : {
166 : // Will be called when Word Button Change
167 : // or internally by me ChangeAll
168 :
169 : // If there is a dot Punkt after the word, this dot will be stripped away.
170 : // If '"' => PreStripped.
171 0 : String aNewWord( rNewWord );
172 0 : pEditView->InsertText( aNewWord );
173 0 : CheckSpellTo();
174 0 : }
175 :
176 0 : void EditSpellWrapper::ChangeThesWord( const String& rNewWord )
177 : {
178 0 : pEditView->InsertText( rNewWord );
179 0 : CheckSpellTo();
180 0 : }
181 :
182 0 : void EditSpellWrapper::AutoCorrect( const String&, const String& )
183 : {
184 0 : }
185 :
186 0 : void EditSpellWrapper::CheckSpellTo()
187 : {
188 0 : ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
189 0 : SpellInfo* pSpellInfo = pImpEE->GetSpellInfo();
190 0 : EditPaM aPaM( pEditView->GetImpEditView()->GetEditSelection().Max() );
191 0 : EPaM aEPaM = pImpEE->CreateEPaM( aPaM );
192 0 : if ( aEPaM.nPara == pSpellInfo->aSpellTo.nPara )
193 : {
194 : // Check if SpellToEnd still has a valid Index, if replace has been
195 : // performed in the paragraph.
196 0 : if ( pSpellInfo->aSpellTo.nIndex > aPaM.GetNode()->Len() )
197 0 : pSpellInfo->aSpellTo.nIndex = aPaM.GetNode()->Len();
198 : }
199 0 : }
200 :
201 : //////////////////////////////////////////////////////////////////////
202 :
203 : #define NOT_INVALID 0xFFFF
204 :
205 17963 : WrongList::WrongList() : nInvalidStart(0), nInvalidEnd(0xFFFF) {}
206 :
207 19960 : WrongList::WrongList(const WrongList& r) :
208 : maRanges(r.maRanges),
209 : nInvalidStart(r.nInvalidStart),
210 19960 : nInvalidEnd(r.nInvalidEnd) {}
211 :
212 37887 : WrongList::~WrongList() {}
213 :
214 6466 : bool WrongList::IsInvalid() const
215 : {
216 6466 : return nInvalidStart != NOT_INVALID;
217 : }
218 :
219 267 : void WrongList::SetValid()
220 : {
221 267 : nInvalidStart = NOT_INVALID;
222 267 : nInvalidEnd = 0;
223 267 : }
224 :
225 1685 : void WrongList::MarkInvalid( sal_uInt16 nS, sal_uInt16 nE )
226 : {
227 1685 : if ( ( nInvalidStart == NOT_INVALID ) || ( nInvalidStart > nS ) )
228 253 : nInvalidStart = nS;
229 1685 : if ( nInvalidEnd < nE )
230 764 : nInvalidEnd = nE;
231 1685 : }
232 :
233 6422 : void WrongList::TextInserted( sal_uInt16 nPos, sal_uInt16 nNew, sal_Bool bPosIsSep )
234 : {
235 6422 : if ( !IsInvalid() )
236 : {
237 0 : nInvalidStart = nPos;
238 0 : nInvalidEnd = nPos+nNew;
239 : }
240 : else
241 : {
242 6422 : if ( nInvalidStart > nPos )
243 0 : nInvalidStart = nPos;
244 6422 : if ( nInvalidEnd >= nPos )
245 6422 : nInvalidEnd = nInvalidEnd + nNew;
246 : else
247 0 : nInvalidEnd = nPos+nNew;
248 : }
249 :
250 6422 : for (size_t i = 0, n = maRanges.size(); i < n; ++i)
251 : {
252 0 : WrongRange& rWrong = maRanges[i];
253 0 : bool bRefIsValid = true;
254 0 : if (rWrong.nEnd >= nPos)
255 : {
256 : // Move all Wrongs after the insert position...
257 0 : if (rWrong.nStart > nPos)
258 : {
259 0 : rWrong.nStart += nNew;
260 0 : rWrong.nEnd += nNew;
261 : }
262 : // 1: Starts before and goes until nPos...
263 0 : else if (rWrong.nEnd == nPos)
264 : {
265 : // Should be halted at a blank!
266 0 : if ( !bPosIsSep )
267 0 : rWrong.nEnd += nNew;
268 : }
269 : // 2: Starts before and goes until after nPos...
270 0 : else if ((rWrong.nStart < nPos) && (rWrong.nEnd > nPos))
271 : {
272 0 : rWrong.nEnd += nNew;
273 : // When a separator remove and re-examine the Wrong
274 0 : if ( bPosIsSep )
275 : {
276 : // Split Wrong...
277 0 : WrongRange aNewWrong(rWrong.nStart, nPos);
278 0 : rWrong.nStart = nPos + 1;
279 0 : maRanges.insert(maRanges.begin() + i, aNewWrong);
280 : // Reference no longer valid after Insert, the other
281 : // was inserted in front of this position
282 0 : bRefIsValid = false;
283 0 : ++i; // Not this again...
284 0 : }
285 : }
286 : // 3: Attribute starts at position ..
287 0 : else if (rWrong.nStart == nPos)
288 : {
289 0 : rWrong.nEnd += nNew;
290 0 : if ( bPosIsSep )
291 0 : ++(rWrong.nStart);
292 : }
293 : }
294 : SAL_WARN_IF(bRefIsValid && rWrong.nStart >= rWrong.nEnd, "editeng",
295 : "TextInserted, WrongRange: Start >= End?!");
296 : (void)bRefIsValid;
297 : }
298 :
299 : SAL_WARN_IF(DbgIsBuggy(), "editeng", "InsertWrong: WrongList broken!");
300 6422 : }
301 :
302 35 : void WrongList::TextDeleted( sal_uInt16 nPos, sal_uInt16 nDeleted )
303 : {
304 35 : sal_uInt16 nEndChanges = nPos+nDeleted;
305 35 : if ( !IsInvalid() )
306 : {
307 0 : sal_uInt16 nNewInvalidStart = nPos ? nPos - 1 : 0;
308 0 : nInvalidStart = nNewInvalidStart;
309 0 : nInvalidEnd = nNewInvalidStart + 1;
310 : }
311 : else
312 : {
313 35 : if ( nInvalidStart > nPos )
314 0 : nInvalidStart = nPos;
315 35 : if ( nInvalidEnd > nPos )
316 : {
317 0 : if ( nInvalidEnd > nEndChanges )
318 0 : nInvalidEnd = nInvalidEnd - nDeleted;
319 : else
320 0 : nInvalidEnd = nPos+1;
321 : }
322 : }
323 :
324 70 : for (WrongList::iterator i = begin(); i != end(); )
325 : {
326 0 : sal_Bool bDelWrong = sal_False;
327 0 : if (i->nEnd >= nPos)
328 : {
329 : // Move all Wrongs after the insert position...
330 0 : if (i->nStart >= nEndChanges)
331 : {
332 0 : i->nStart -= nDeleted;
333 0 : i->nEnd -= nDeleted;
334 : }
335 : // 1. Delete Internal Wrongs ...
336 0 : else if (i->nStart >= nPos && i->nEnd <= nEndChanges)
337 : {
338 0 : bDelWrong = sal_True;
339 : }
340 : // 2. Wrong begins before, ends inside or behind it ...
341 0 : else if (i->nStart <= nPos && i->nEnd > nPos)
342 : {
343 0 : if (i->nEnd <= nEndChanges) // ends inside
344 0 : i->nEnd = nPos;
345 : else
346 0 : i->nEnd -= nDeleted; // ends after
347 : }
348 : // 3. Wrong begins inside, ending after ...
349 0 : else if (i->nStart >= nPos && i->nEnd > nEndChanges)
350 : {
351 0 : i->nStart = nEndChanges - nDeleted;
352 0 : i->nEnd -= nDeleted;
353 : }
354 : }
355 : SAL_WARN_IF(i->nStart >= i->nEnd, "editeng",
356 : "TextDeleted, WrongRange: Start >= End?!");
357 0 : if ( bDelWrong )
358 : {
359 0 : i = maRanges.erase(i);
360 : }
361 : else
362 : {
363 0 : ++i;
364 : }
365 : }
366 :
367 : SAL_WARN_IF(DbgIsBuggy(), "editeng", "TextDeleted: WrongList broken!");
368 35 : }
369 :
370 0 : sal_Bool WrongList::NextWrong( sal_uInt16& rnStart, sal_uInt16& rnEnd ) const
371 : {
372 : /*
373 : rnStart get the start position, is possibly adjusted wrt. Wrong start
374 : rnEnd does not have to be initialized.
375 : */
376 0 : for (WrongList::const_iterator i = begin(); i != end(); ++i)
377 : {
378 0 : if ( i->nEnd > rnStart )
379 : {
380 0 : rnStart = i->nStart;
381 0 : rnEnd = i->nEnd;
382 0 : return sal_True;
383 : }
384 : }
385 0 : return sal_False;
386 : }
387 :
388 0 : sal_Bool WrongList::HasWrong( sal_uInt16 nStart, sal_uInt16 nEnd ) const
389 : {
390 0 : for (WrongList::const_iterator i = begin(); i != end(); ++i)
391 : {
392 0 : if (i->nStart == nStart && i->nEnd == nEnd)
393 0 : return sal_True;
394 0 : else if ( i->nStart >= nStart )
395 0 : break;
396 : }
397 0 : return sal_False;
398 : }
399 :
400 10 : sal_Bool WrongList::HasAnyWrong( sal_uInt16 nStart, sal_uInt16 nEnd ) const
401 : {
402 10 : for (WrongList::const_iterator i = begin(); i != end(); ++i)
403 : {
404 0 : if (i->nEnd >= nStart && i->nStart < nEnd)
405 0 : return sal_True;
406 0 : else if (i->nStart >= nEnd)
407 0 : break;
408 : }
409 10 : return sal_False;
410 : }
411 :
412 0 : void WrongList::ClearWrongs( sal_uInt16 nStart, sal_uInt16 nEnd,
413 : const ContentNode* pNode )
414 : {
415 0 : for (WrongList::iterator i = begin(); i != end(); )
416 : {
417 0 : if (i->nEnd > nStart && i->nStart < nEnd)
418 : {
419 0 : if (i->nEnd > nEnd) // Runs out
420 : {
421 0 : i->nStart = nEnd;
422 : // Blanks?
423 0 : while (i->nStart < pNode->Len() &&
424 0 : (pNode->GetChar(i->nStart) == ' ' ||
425 0 : pNode->IsFeature(i->nStart)))
426 : {
427 0 : ++(i->nStart);
428 : }
429 0 : ++i;
430 : }
431 : else
432 : {
433 0 : i = maRanges.erase(i);
434 : // no increment here
435 : }
436 : }
437 : else
438 : {
439 0 : ++i;
440 : }
441 : }
442 :
443 : SAL_WARN_IF(DbgIsBuggy(), "editeng", "ClearWrongs: WrongList broken!");
444 0 : }
445 :
446 0 : void WrongList::InsertWrong( sal_uInt16 nStart, sal_uInt16 nEnd,
447 : sal_Bool bClearRange )
448 : {
449 0 : WrongList::iterator nPos = end();
450 0 : for (WrongList::iterator i = begin(); i != end(); ++i)
451 : {
452 0 : if (i->nStart >= nStart )
453 : {
454 0 : nPos = i;
455 0 : if ( bClearRange )
456 : {
457 : // It can really only happen that the Wrong starts exactly here
458 : // and runs along, but not that there are several ranges ...
459 : // Exactly in the range is no one allowed to be, otherwise this
460 : // Method can not be called!
461 : SAL_WARN_IF((i->nStart != nStart || i->nEnd <= nEnd) && i->nStart <= nEnd, "editeng", "InsertWrong: RangeMismatch!");
462 0 : if (i->nStart == nStart && i->nEnd > nEnd)
463 0 : i->nStart = nEnd + 1;
464 : }
465 0 : break;
466 : }
467 : }
468 :
469 0 : if (nPos != maRanges.end())
470 0 : maRanges.insert(nPos, WrongRange(nStart, nEnd));
471 : else
472 0 : maRanges.push_back(WrongRange(nStart, nEnd));
473 :
474 : SAL_WARN_IF(DbgIsBuggy(), "editeng", "InsertWrong: WrongList broken!");
475 0 : }
476 :
477 0 : void WrongList::MarkWrongsInvalid()
478 : {
479 0 : if (!maRanges.empty())
480 0 : MarkInvalid(maRanges.front().nStart, maRanges.back().nEnd );
481 0 : }
482 :
483 19960 : WrongList* WrongList::Clone() const
484 : {
485 19960 : return new WrongList(*this);
486 : }
487 :
488 : // #i102062#
489 0 : bool WrongList::operator==(const WrongList& rCompare) const
490 : {
491 : // cleck direct members
492 0 : if(GetInvalidStart() != rCompare.GetInvalidStart()
493 0 : || GetInvalidEnd() != rCompare.GetInvalidEnd()
494 0 : || maRanges.size() != rCompare.maRanges.size())
495 0 : return false;
496 :
497 0 : WrongList::const_iterator rCA = maRanges.begin();
498 0 : WrongList::const_iterator rCB = rCompare.maRanges.begin();
499 :
500 0 : for (; rCA != maRanges.end(); ++rCA, ++rCB)
501 : {
502 0 : if(rCA->nStart != rCB->nStart || rCA->nEnd != rCB->nEnd)
503 0 : return false;
504 : }
505 :
506 0 : return true;
507 : }
508 :
509 1019 : bool WrongList::empty() const
510 : {
511 1019 : return maRanges.empty();
512 : }
513 :
514 0 : void WrongList::push_back(const WrongRange& rRange)
515 : {
516 0 : maRanges.push_back(rRange);
517 0 : }
518 :
519 0 : WrongRange& WrongList::back()
520 : {
521 0 : return maRanges.back();
522 : }
523 :
524 0 : const WrongRange& WrongList::back() const
525 : {
526 0 : return maRanges.back();
527 : }
528 :
529 288 : WrongList::iterator WrongList::begin()
530 : {
531 288 : return maRanges.begin();
532 : }
533 :
534 288 : WrongList::iterator WrongList::end()
535 : {
536 288 : return maRanges.end();
537 : }
538 :
539 10 : WrongList::const_iterator WrongList::begin() const
540 : {
541 10 : return maRanges.begin();
542 : }
543 :
544 10 : WrongList::const_iterator WrongList::end() const
545 : {
546 10 : return maRanges.end();
547 : }
548 :
549 0 : sal_Bool WrongList::DbgIsBuggy() const
550 : {
551 : // Check if the ranges overlap.
552 0 : sal_Bool bError = sal_False;
553 0 : for (WrongList::const_iterator i = begin(); !bError && (i != end()); ++i)
554 : {
555 0 : for (WrongList::const_iterator j = i + 1; !bError && (j != end()); ++j)
556 : {
557 : // 1) Start before, End after the second Start
558 0 : if (i->nStart <= j->nStart && i->nEnd >= j->nStart)
559 0 : bError = sal_True;
560 : // 2) Start after the second Start, but still before the second End
561 0 : else if (i->nStart >= j->nStart && i->nStart <= j->nEnd)
562 0 : bError = sal_True;
563 : }
564 : }
565 0 : return bError;
566 : }
567 :
568 : //////////////////////////////////////////////////////////////////////
569 :
570 0 : EdtAutoCorrDoc::EdtAutoCorrDoc(
571 : EditEngine* pE, ContentNode* pN, sal_uInt16 nCrsr, sal_Unicode cIns) :
572 : mpEditEngine(pE),
573 : pCurNode(pN),
574 : nCursor(nCrsr),
575 : bAllowUndoAction(cIns != 0),
576 0 : bUndoAction(false) {}
577 :
578 0 : EdtAutoCorrDoc::~EdtAutoCorrDoc()
579 : {
580 0 : if ( bUndoAction )
581 0 : mpEditEngine->UndoActionEnd( EDITUNDO_INSERT );
582 0 : }
583 :
584 0 : sal_Bool EdtAutoCorrDoc::Delete( sal_uInt16 nStt, sal_uInt16 nEnd )
585 : {
586 0 : EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) );
587 0 : mpEditEngine->DeleteSelection(aSel);
588 : SAL_WARN_IF(nCursor < nEnd, "editeng",
589 : "Cursor in the heart of the action?!");
590 0 : nCursor -= ( nEnd-nStt );
591 0 : bAllowUndoAction = sal_False;
592 0 : return sal_True;
593 : }
594 :
595 0 : sal_Bool EdtAutoCorrDoc::Insert( sal_uInt16 nPos, const String& rTxt )
596 : {
597 0 : EditSelection aSel = EditPaM( pCurNode, nPos );
598 0 : mpEditEngine->InsertText(aSel, rTxt);
599 : SAL_WARN_IF(nCursor < nPos, "editeng",
600 : "Cursor in the heart of the action?!");
601 0 : nCursor = nCursor + rTxt.Len();
602 :
603 0 : if ( bAllowUndoAction && ( rTxt.Len() == 1 ) )
604 0 : ImplStartUndoAction();
605 0 : bAllowUndoAction = sal_False;
606 :
607 0 : return sal_True;
608 : }
609 :
610 0 : sal_Bool EdtAutoCorrDoc::Replace( sal_uInt16 nPos, const String& rTxt )
611 : {
612 0 : return ReplaceRange( nPos, rTxt.Len(), rTxt );
613 : }
614 :
615 0 : sal_Bool EdtAutoCorrDoc::ReplaceRange( xub_StrLen nPos, xub_StrLen nSourceLength, const String& rTxt )
616 : {
617 : // Actually a Replace introduce => corresponds to UNDO
618 0 : sal_uInt16 nEnd = nPos+nSourceLength;
619 0 : if ( nEnd > pCurNode->Len() )
620 0 : nEnd = pCurNode->Len();
621 :
622 : // #i5925# First insert new text behind to be deleted text, for keeping attributes.
623 0 : mpEditEngine->InsertText(EditSelection(EditPaM(pCurNode, nEnd)), rTxt);
624 : mpEditEngine->DeleteSelection(
625 0 : EditSelection(EditPaM(pCurNode, nPos), EditPaM(pCurNode, nEnd)));
626 :
627 0 : if ( nPos == nCursor )
628 0 : nCursor = nCursor + rTxt.Len();
629 :
630 0 : if ( bAllowUndoAction && ( rTxt.Len() == 1 ) )
631 0 : ImplStartUndoAction();
632 :
633 0 : bAllowUndoAction = sal_False;
634 :
635 0 : return sal_True;
636 : }
637 :
638 0 : sal_Bool EdtAutoCorrDoc::SetAttr( sal_uInt16 nStt, sal_uInt16 nEnd,
639 : sal_uInt16 nSlotId, SfxPoolItem& rItem )
640 : {
641 0 : SfxItemPool* pPool = &mpEditEngine->GetEditDoc().GetItemPool();
642 0 : while ( pPool->GetSecondaryPool() &&
643 0 : !pPool->GetName().equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("EditEngineItemPool")) )
644 : {
645 0 : pPool = pPool->GetSecondaryPool();
646 :
647 : }
648 0 : sal_uInt16 nWhich = pPool->GetWhich( nSlotId );
649 0 : if ( nWhich )
650 : {
651 0 : rItem.SetWhich( nWhich );
652 :
653 0 : SfxItemSet aSet = mpEditEngine->GetEmptyItemSet();
654 0 : aSet.Put( rItem );
655 :
656 0 : EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) );
657 0 : aSel.Max().SetIndex( nEnd ); // ???
658 0 : mpEditEngine->SetAttribs( aSel, aSet, ATTRSPECIAL_EDGE );
659 0 : bAllowUndoAction = false;
660 : }
661 0 : return sal_True;
662 : }
663 :
664 0 : sal_Bool EdtAutoCorrDoc::SetINetAttr( sal_uInt16 nStt, sal_uInt16 nEnd,
665 : const String& rURL )
666 : {
667 : // Turn the Text into a command field ...
668 0 : EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) );
669 0 : String aText = mpEditEngine->GetSelected(aSel);
670 0 : aSel = mpEditEngine->DeleteSelection(aSel);
671 : SAL_WARN_IF(nCursor < nEnd, "editeng",
672 : "Cursor in the heart of the action?!");
673 0 : nCursor -= ( nEnd-nStt );
674 : SvxFieldItem aField( SvxURLField( rURL, aText, SVXURLFORMAT_REPR ),
675 0 : EE_FEATURE_FIELD );
676 0 : mpEditEngine->InsertField(aSel, aField);
677 0 : nCursor++;
678 0 : mpEditEngine->UpdateFieldsOnly();
679 0 : bAllowUndoAction = false;
680 0 : return sal_True;
681 : }
682 :
683 0 : sal_Bool EdtAutoCorrDoc::HasSymbolChars( sal_uInt16 nStt, sal_uInt16 nEnd )
684 : {
685 0 : sal_uInt16 nScriptType = mpEditEngine->GetScriptType( EditPaM( pCurNode, nStt ) );
686 0 : sal_uInt16 nScriptFontInfoItemId = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType );
687 :
688 0 : const CharAttribList::AttribsType& rAttribs = pCurNode->GetCharAttribs().GetAttribs();
689 0 : CharAttribList::AttribsType::const_iterator it = rAttribs.begin(), itEnd = rAttribs.end();
690 0 : for (; it != itEnd; ++it)
691 : {
692 0 : const EditCharAttrib& rAttr = *it;
693 0 : if (rAttr.GetStart() >= nEnd)
694 0 : return false;
695 :
696 0 : if (rAttr.Which() == nScriptFontInfoItemId &&
697 0 : static_cast<const SvxFontItem*>(rAttr.GetItem())->GetCharSet() == RTL_TEXTENCODING_SYMBOL)
698 : {
699 : // check if the Attribtuteis within range...
700 0 : if (rAttr.GetEnd() >= nStt)
701 0 : return true;
702 : }
703 : }
704 0 : return false;
705 : }
706 :
707 0 : const String* EdtAutoCorrDoc::GetPrevPara( sal_Bool )
708 : {
709 : // Return previous paragraph, so that it can be determined,
710 : // whether the current word is at the beginning of a sentence.
711 :
712 0 : bAllowUndoAction = sal_False; // Not anymore ...
713 :
714 0 : EditDoc& rNodes = mpEditEngine->GetEditDoc();
715 0 : sal_uInt16 nPos = rNodes.GetPos( pCurNode );
716 :
717 : // Special case: Bullet => Paragraph start => simply return NULL...
718 : const SfxBoolItem& rBulletState = (const SfxBoolItem&)
719 0 : mpEditEngine->GetParaAttrib( nPos, EE_PARA_BULLETSTATE );
720 0 : sal_Bool bBullet = rBulletState.GetValue() ? sal_True : sal_False;
721 0 : if ( !bBullet && (mpEditEngine->GetControlWord() & EE_CNTRL_OUTLINER) )
722 : {
723 : // The Outliner has still a Bullet at Level 0.
724 : const SfxInt16Item& rLevel = (const SfxInt16Item&)
725 0 : mpEditEngine->GetParaAttrib( nPos, EE_PARA_OUTLLEVEL );
726 0 : if ( rLevel.GetValue() == 0 )
727 0 : bBullet = sal_True;
728 : }
729 0 : if ( bBullet )
730 0 : return NULL;
731 :
732 0 : for ( sal_uInt16 n = nPos; n; )
733 : {
734 0 : n--;
735 0 : ContentNode* pNode = rNodes[n];
736 0 : if ( pNode->Len() )
737 0 : return &pNode->GetString();
738 : }
739 0 : return NULL;
740 :
741 : }
742 :
743 0 : sal_Bool EdtAutoCorrDoc::ChgAutoCorrWord( sal_uInt16& rSttPos,
744 : sal_uInt16 nEndPos, SvxAutoCorrect& rACorrect,
745 : const String** ppPara )
746 : {
747 : // Paragraph-start or a blank found, search for the word
748 : // shortcut in Auto
749 0 : bAllowUndoAction = sal_False; // Not anymore ...
750 :
751 0 : String aShort( pCurNode->Copy( rSttPos, nEndPos - rSttPos ) );
752 0 : sal_Bool bRet = sal_False;
753 :
754 0 : if( !aShort.Len() )
755 0 : return bRet;
756 :
757 0 : LanguageType eLang = mpEditEngine->GetLanguage( EditPaM( pCurNode, rSttPos+1 ) );
758 0 : const SvxAutocorrWord* pFnd = rACorrect.SearchWordsInList(pCurNode->GetString(), rSttPos, nEndPos, *this, eLang);
759 0 : if( pFnd && pFnd->IsTextOnly() )
760 : {
761 : // then replace
762 : EditSelection aSel( EditPaM( pCurNode, rSttPos ),
763 0 : EditPaM( pCurNode, nEndPos ) );
764 0 : aSel = mpEditEngine->DeleteSelection(aSel);
765 : SAL_WARN_IF(nCursor < nEndPos, "editeng",
766 : "Cursor in the heart of the action?!");
767 0 : nCursor -= ( nEndPos-rSttPos );
768 0 : mpEditEngine->InsertText(aSel, pFnd->GetLong());
769 0 : nCursor = nCursor + pFnd->GetLong().Len();
770 0 : if( ppPara )
771 0 : *ppPara = &pCurNode->GetString();
772 0 : bRet = sal_True;
773 : }
774 :
775 0 : return bRet;
776 : }
777 :
778 0 : LanguageType EdtAutoCorrDoc::GetLanguage( sal_uInt16 nPos, sal_Bool ) const
779 : {
780 0 : return mpEditEngine->GetLanguage( EditPaM( pCurNode, nPos+1 ) );
781 : }
782 :
783 0 : void EdtAutoCorrDoc::ImplStartUndoAction()
784 : {
785 0 : sal_uInt16 nPara = mpEditEngine->GetEditDoc().GetPos( pCurNode );
786 0 : ESelection aSel( nPara, nCursor, nPara, nCursor );
787 0 : mpEditEngine->UndoActionStart( EDITUNDO_INSERT, aSel );
788 0 : bUndoAction = sal_True;
789 0 : bAllowUndoAction = sal_False;
790 0 : }
791 :
792 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|