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