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