1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: edlingu.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
34 #include <com/sun/star/linguistic2/ProofreadingResult.hpp>
35 #include <com/sun/star/linguistic2/XProofreader.hpp>
36 #include <com/sun/star/linguistic2/XProofreadingIterator.hpp>
37 #include <com/sun/star/text/XFlatParagraph.hpp>
39 #include <unoflatpara.hxx>
42 #include <comcore.hrc>
44 #include <hintids.hxx>
45 #include <linguistic/lngprops.hxx>
46 #include <vcl/msgbox.hxx>
47 #include <svx/unolingu.hxx>
48 #include <svx/svxacorr.hxx>
49 #include <svx/langitem.hxx>
50 #include <svx/SpellPortions.hxx>
51 #include <svx/scripttypeitem.hxx>
52 #include <fmthbsh.hxx>
53 #include <charatr.hxx>
56 #include <rootfrm.hxx> // SwRootFrm
58 #include <swundo.hxx> // fuer die UndoIds
59 #include <ndtxt.hxx> // AdjHyphPos
60 #include <viewopt.hxx> // HyphStart/End
61 #include <viscrs.hxx> // SwShellCrsr
62 #include <SwGrammarMarkUp.hxx> // SwWrongList
63 #include <mdiexp.hxx> // Statusanzeige
65 #include <statstr.hrc> // StatLine-String
68 #include <crsskip.hxx>
69 #include <splargs.hxx>
70 #include <redline.hxx> // SwRedline
71 #include <docary.hxx> // SwRedlineTbl
74 using namespace ::svx
;
75 using namespace ::com::sun::star
;
76 using namespace ::com::sun::star::uno
;
77 using namespace ::com::sun::star::beans
;
78 using namespace ::com::sun::star::linguistic2
;
80 #define C2U(cChar) rtl::OUString::createFromAscii(cChar)
82 extern void repaintTextFrames( SwModify
& rModify
);
84 /*************************************************************************
86 *************************************************************************/
99 inline SwEditShell
*GetSh() { return pSh
; }
100 inline const SwEditShell
*GetSh() const { return pSh
; }
102 inline const SwPosition
*GetEnd() const { return pEnd
; }
103 inline void SetEnd( SwPosition
* pNew
){ delete pEnd
; pEnd
= pNew
; }
105 inline const SwPosition
*GetStart() const { return pStart
; }
106 inline void SetStart( SwPosition
* pNew
){ delete pStart
; pStart
= pNew
; }
108 inline const SwPosition
*GetCurr() const { return pCurr
; }
109 inline void SetCurr( SwPosition
* pNew
){ delete pCurr
; pCurr
= pNew
; }
111 inline const SwPosition
*GetCurrX() const { return pCurrX
; }
112 inline void SetCurrX( SwPosition
* pNew
){ delete pCurrX
; pCurrX
= pNew
; }
114 inline sal_uInt16
& GetCrsrCnt(){ return nCrsrCnt
; }
116 // Der UI-Bauchladen:
117 void _Start( SwEditShell
*pSh
, SwDocPositions eStart
,
118 SwDocPositions eEnd
);
119 void _End(bool bRestoreSelection
= true);
122 /*************************************************************************
124 *************************************************************************/
126 // #i18881# to be able to identify the postions of the changed words
127 // the content positions of each portion need to be saved
128 struct SpellContentPosition
133 typedef std::vector
<SpellContentPosition
> SpellContentPositions
;
134 class SwSpellIter
: public SwLinguIter
136 uno::Reference
< XSpellChecker1
> xSpeller
;
137 ::svx::SpellPortions aLastPortions
;
139 SpellContentPositions aLastPositions
;
140 bool bBackToStartOfSentence
;
143 void CreatePortion(uno::Reference
< XSpellAlternatives
> xAlt
,
144 linguistic2::ProofreadingResult
* pGrammarResult
,
145 bool bIsField
, bool bIsHidden
);
147 void AddPortion(uno::Reference
< XSpellAlternatives
> xAlt
,
148 linguistic2::ProofreadingResult
* pGrammarResult
,
149 const SpellContentPositions
& rDeletedRedlines
);
152 bBackToStartOfSentence(false) {}
154 void Start( SwEditShell
*pSh
, SwDocPositions eStart
, SwDocPositions eEnd
);
156 uno::Any
Continue( sal_uInt16
* pPageCnt
, sal_uInt16
* pPageSt
);
158 bool SpellSentence(::svx::SpellPortions
& rPortions
, bool bIsGrammarCheck
);
159 void ToSentenceStart();
160 const ::svx::SpellPortions
GetLastPortions(){ return aLastPortions
;}
161 SpellContentPositions
GetLastPositions() {return aLastPositions
;}
164 /*************************************************************************
166 * used for text conversion
167 *************************************************************************/
169 class SwConvIter
: public SwLinguIter
171 SwConversionArgs
&rArgs
;
173 SwConvIter( SwConversionArgs
&rConvArgs
) :
177 void Start( SwEditShell
*pSh
, SwDocPositions eStart
, SwDocPositions eEnd
);
179 uno::Any
Continue( sal_uInt16
* pPageCnt
, sal_uInt16
* pPageSt
);
182 /*************************************************************************
184 *************************************************************************/
186 class SwHyphIter
: public SwLinguIter
189 void DelSoftHyph( SwPaM
&rPam
);
192 SwHyphIter() : bOldIdle(sal_False
) {}
194 void Start( SwEditShell
*pSh
, SwDocPositions eStart
, SwDocPositions eEnd
);
199 uno::Any
Continue( sal_uInt16
* pPageCnt
, sal_uInt16
* pPageSt
);
202 void InsertSoftHyph( const xub_StrLen nHyphPos
);
203 void ShowSelection();
206 static SwSpellIter
* pSpellIter
= 0;
207 static SwConvIter
* pConvIter
= 0;
208 static SwHyphIter
* pHyphIter
= 0;
210 // Wir ersparen uns in Hyphenate ein GetFrm()
211 // Achtung: in txtedt.cxx stehen extern-Deklarationen auf diese Pointer!
212 const SwTxtNode
*pLinguNode
;
215 /*************************************************************************
216 * SwLinguIter::SwLinguIter
217 *************************************************************************/
219 SwLinguIter::SwLinguIter()
220 : pSh( 0 ), pStart( 0 ), pEnd( 0 ), pCurr( 0 ), pCurrX( 0 )
222 // @@@ es fehlt: Sicherstellen der Reentrance, ASSERTs etc.
225 /*************************************************************************
227 *************************************************************************/
231 void SwLinguIter::_Start( SwEditShell
*pShell
, SwDocPositions eStart
,
232 SwDocPositions eEnd
)
234 // es fehlt: Sicherstellen der Reentrance, Locking
242 SET_CURR_SHELL( pSh
);
244 ASSERT( !pEnd
, "LinguStart ohne End?");
246 SwPaM
*pCrsr
= pSh
->GetCrsr();
248 // pStk->SetCurCrsr();
249 // if( pCrsr->HasMark() || pCrsr != pCrsr->GetNext() )
250 if( pShell
->HasSelection() || pCrsr
!= pCrsr
->GetNext() )
252 bSetCurr
= 0 != GetCurr();
253 nCrsrCnt
= pSh
->GetCrsrCnt();
254 if( pSh
->IsTableMode() )
255 pSh
->TblCrsrToCursor();
259 for( n
= 0; n
< nCrsrCnt
; ++n
)
264 pSh
->Pop( sal_False
);
268 bSetCurr
= sal_False
;
271 pSh
->SetLinguRange( eStart
, eEnd
);
274 pCrsr
= pSh
->GetCrsr();
275 if ( *pCrsr
->GetPoint() > *pCrsr
->GetMark() )
278 pStart
= new SwPosition( *pCrsr
->GetPoint() );
279 pEnd
= new SwPosition( *pCrsr
->GetMark() );
282 SwPosition
* pNew
= new SwPosition( *GetStart() );
284 pNew
= new SwPosition( *pNew
);
294 /*************************************************************************
296 *************************************************************************/
300 void SwLinguIter::_End(bool bRestoreSelection
)
305 ASSERT( pEnd
, "SwEditShell::SpellEnd() ohne Start?");
306 if(bRestoreSelection
)
309 pSh
->Pop( sal_False
);
321 #ifdef LINGU_STATISTIK
322 aSwLinguStat
.Flush();
326 /*************************************************************************
327 * virtual SwSpellIter::Start()
328 *************************************************************************/
332 void SwSpellIter::Start( SwEditShell
*pShell
, SwDocPositions eStart
,
333 SwDocPositions eEnd
)
338 uno::Reference
< beans::XPropertySet
> xProp( ::GetLinguPropertySet() );
339 xSpeller
= ::GetSpellChecker();
341 _Start( pShell
, eStart
, eEnd
);
342 aLastPortions
.clear();
343 aLastPositions
.clear();
346 /*************************************************************************
347 * SwSpellIter::Continue
348 *************************************************************************/
350 // SwSpellIter::Continue ist das alte Original von
351 // SwEditShell::SpellContinue()
353 uno::Any
SwSpellIter::Continue( sal_uInt16
* pPageCnt
, sal_uInt16
* pPageSt
)
356 //!! Please check SwConvIter also when modifying this
360 SwEditShell
*pMySh
= GetSh();
364 // const SwPosition *pEnd = GetEnd();
366 ASSERT( GetEnd(), "SwEditShell::SpellContinue() ohne Start?");
368 uno::Reference
< uno::XInterface
> xSpellRet
;
369 sal_Bool bGoOn
= sal_True
;
371 SwPaM
*pCrsr
= pMySh
->GetCrsr();
372 if ( !pCrsr
->HasMark() )
375 uno::Reference
< beans::XPropertySet
> xProp( GetLinguPropertySet() );
376 *pMySh
->GetCrsr()->GetPoint() = *GetCurr();
377 *pMySh
->GetCrsr()->GetMark() = *GetEnd();
378 pMySh
->GetDoc()->Spell(*pMySh
->GetCrsr(),
379 xSpeller
, pPageCnt
, pPageSt
, false ) >>= xSpellRet
;
380 bGoOn
= GetCrsrCnt() > 1;
384 SwPosition
* pNewPoint
= new SwPosition( *pCrsr
->GetPoint() );
385 SwPosition
* pNewMark
= new SwPosition( *pCrsr
->GetMark() );
386 SetCurr( pNewPoint
);
387 SetCurrX( pNewMark
);
391 pMySh
->Pop( sal_False
);
392 pCrsr
= pMySh
->GetCrsr();
393 if ( *pCrsr
->GetPoint() > *pCrsr
->GetMark() )
395 SwPosition
* pNew
= new SwPosition( *pCrsr
->GetPoint() );
397 pNew
= new SwPosition( *pCrsr
->GetMark() );
399 pNew
= new SwPosition( *GetStart() );
401 pNew
= new SwPosition( *pNew
);
407 aSpellRet
<<= xSpellRet
;
411 /*************************************************************************
412 * virtual SwConvIter::Start()
413 *************************************************************************/
417 void SwConvIter::Start( SwEditShell
*pShell
, SwDocPositions eStart
,
418 SwDocPositions eEnd
)
422 _Start( pShell
, eStart
, eEnd
);
425 /*************************************************************************
426 * SwConvIter::Continue
427 *************************************************************************/
429 uno::Any
SwConvIter::Continue( sal_uInt16
* pPageCnt
, sal_uInt16
* pPageSt
)
432 //!! Please check SwSpellIter also when modifying this
435 uno::Any
aConvRet( makeAny( rtl::OUString() ) );
436 SwEditShell
*pMySh
= GetSh();
440 // const SwPosition *pEnd = GetEnd();
442 ASSERT( GetEnd(), "SwConvIter::Continue() ohne Start?");
444 rtl::OUString aConvText
;
445 sal_Bool bGoOn
= sal_True
;
447 SwPaM
*pCrsr
= pMySh
->GetCrsr();
448 if ( !pCrsr
->HasMark() )
451 *pMySh
->GetCrsr()->GetPoint() = *GetCurr();
452 *pMySh
->GetCrsr()->GetMark() = *GetEnd();
454 // call function to find next text portion to be converted
455 uno::Reference
< linguistic2::XSpellChecker1
> xEmpty
;
456 pMySh
->GetDoc()->Spell( *pMySh
->GetCrsr(),
457 xEmpty
, pPageCnt
, pPageSt
, false, &rArgs
) >>= aConvText
;
459 bGoOn
= GetCrsrCnt() > 1;
460 if( aConvText
.getLength() )
463 SwPosition
* pNewPoint
= new SwPosition( *pCrsr
->GetPoint() );
464 SwPosition
* pNewMark
= new SwPosition( *pCrsr
->GetMark() );
466 SetCurr( pNewPoint
);
467 SetCurrX( pNewMark
);
471 pMySh
->Pop( sal_False
);
472 pCrsr
= pMySh
->GetCrsr();
473 if ( *pCrsr
->GetPoint() > *pCrsr
->GetMark() )
475 SwPosition
* pNew
= new SwPosition( *pCrsr
->GetPoint() );
477 pNew
= new SwPosition( *pCrsr
->GetMark() );
479 pNew
= new SwPosition( *GetStart() );
481 pNew
= new SwPosition( *pNew
);
487 return makeAny( aConvText
);
491 /*************************************************************************
493 *************************************************************************/
496 sal_Bool
SwHyphIter::IsAuto()
498 uno::Reference
< beans::XPropertySet
> xProp( ::GetLinguPropertySet() );
499 return xProp
.is() ? *(sal_Bool
*)xProp
->getPropertyValue(
500 C2U(UPN_IS_HYPH_AUTO
) ).getValue()
505 void SwHyphIter::ShowSelection()
507 SwEditShell
*pMySh
= GetSh();
510 pMySh
->StartAction();
511 // Ganz fatal: durch das EndAction() werden Formatierungen
512 // angeregt, die dazu fuehren koennen, dass im Hyphenator
513 // neue Worte eingestellt werden. Deswegen sichern!
518 /*************************************************************************
519 * virtual SwHyphIter::Start()
520 *************************************************************************/
524 void SwHyphIter::Start( SwEditShell
*pShell
, SwDocPositions eStart
, SwDocPositions eEnd
)
527 if( GetSh() || GetEnd() )
529 ASSERT( !GetSh(), "+SwEditShell::HyphStart: missing HyphEnd()" );
533 // nothing to be done (at least not in the way as in the "else" part)
534 bOldIdle
= pShell
->GetViewOptions()->IsIdle();
535 ((SwViewOption
*)pShell
->GetViewOptions())->SetIdle( sal_False
);
536 _Start( pShell
, eStart
, eEnd
);
539 /*************************************************************************
540 * virtual SwHyphIter::End
541 *************************************************************************/
543 // Selektionen wiederherstellen
547 void SwHyphIter::End()
551 ((SwViewOption
*)GetSh()->GetViewOptions())->SetIdle( bOldIdle
);
555 /*************************************************************************
556 * SwHyphIter::Continue
557 *************************************************************************/
559 uno::Any
SwHyphIter::Continue( sal_uInt16
* pPageCnt
, sal_uInt16
* pPageSt
)
562 SwEditShell
*pMySh
= GetSh();
566 const sal_Bool bAuto
= IsAuto();
567 uno::Reference
< XHyphenatedWord
> xHyphWord
;
569 sal_Bool bGoOn
= sal_False
;
573 ASSERT( GetEnd(), "SwEditShell::SpellContinue() ohne Start?" );
574 pCrsr
= pMySh
->GetCrsr();
575 if ( !pCrsr
->HasMark() )
577 if ( *pCrsr
->GetPoint() < *pCrsr
->GetMark() )
584 if ( *pCrsr
->End() > *GetEnd() )
588 *pCrsr
->GetMark() = *GetEnd();
590 // Muss an der aktuellen Cursorpos das Wort getrennt werden ?
591 const Point
aCrsrPos( pMySh
->GetCharRect().Pos() );
592 xHyphWord
= pMySh
->GetDoc()->Hyphenate( pCrsr
, aCrsrPos
,
596 if( bAuto
&& xHyphWord
.is() )
598 pMySh
->InsertSoftHyph( xHyphWord
->getHyphenationPos() + 1);
600 } while( bAuto
&& xHyphWord
.is() ); //end of do-while
601 bGoOn
= !xHyphWord
.is() && GetCrsrCnt() > 1;
605 pMySh
->Pop( sal_False
);
606 pCrsr
= pMySh
->GetCrsr();
607 if ( *pCrsr
->GetPoint() > *pCrsr
->GetMark() )
609 SwPosition
* pNew
= new SwPosition(*pCrsr
->End());
615 aHyphRet
<<= xHyphWord
;
619 /*************************************************************************
620 * SwHyphIter::HyphIgnore
621 *************************************************************************/
623 // Beschreibung: Trennstelle ignorieren
625 void SwHyphIter::Ignore()
627 SwEditShell
*pMySh
= GetSh();
628 SwPaM
*pCrsr
= pMySh
->GetCrsr();
630 // Alten SoftHyphen loeschen
631 DelSoftHyph( *pCrsr
);
634 pCrsr
->Start()->nContent
= pCrsr
->End()->nContent
;
638 /*************************************************************************
639 * SwHyphIter::DelSoftHyph
640 *************************************************************************/
642 void SwHyphIter::DelSoftHyph( SwPaM
&rPam
)
644 const SwPosition
* pStt
= rPam
.Start();
645 const xub_StrLen nStart
= pStt
->nContent
.GetIndex();
646 const xub_StrLen nEnd
= rPam
.End()->nContent
.GetIndex();
647 SwTxtNode
*pNode
= pStt
->nNode
.GetNode().GetTxtNode();
648 pNode
->DelSoftHyph( nStart
, nEnd
);
651 /*************************************************************************
652 * SwHyphIter::InsertSoftHyph
653 *************************************************************************/
656 void SwHyphIter::InsertSoftHyph( const xub_StrLen nHyphPos
)
658 SwEditShell
*pMySh
= GetSh();
659 ASSERT( pMySh
, "+SwEditShell::InsertSoftHyph: missing HyphStart()");
663 SwPaM
*pCrsr
= pMySh
->GetCrsr();
664 SwPosition
* pSttPos
= pCrsr
->Start();
665 SwPosition
* pEndPos
= pCrsr
->End();
667 xub_StrLen nLastHyphLen
= GetEnd()->nContent
.GetIndex() -
668 pSttPos
->nContent
.GetIndex();
670 if( pSttPos
->nNode
!= pEndPos
->nNode
|| !nLastHyphLen
)
672 ASSERT( pSttPos
->nNode
== pEndPos
->nNode
,
673 "+SwEditShell::InsertSoftHyph: node warp during hyphenation" );
674 ASSERT(nLastHyphLen
, "+SwEditShell::InsertSoftHyph: missing HyphContinue()");
679 pMySh
->StartAction();
681 SwDoc
*pDoc
= pMySh
->GetDoc();
682 DelSoftHyph( *pCrsr
);
683 pSttPos
->nContent
+= nHyphPos
;
684 SwPaM
aRg( *pSttPos
);
685 pDoc
->Insert( aRg
, CHAR_SOFTHYPHEN
);
686 // Durch das Einfuegen des SoftHyphs ist ein Zeichen hinzugekommen
687 //JP 18.07.95: warum, ist doch ein SwIndex, dieser wird doch mitverschoben !!
688 // pSttPos->nContent++;
690 // Die Selektion wird wieder aufgehoben
696 // --------------------- Methoden der SwEditShell ------------------------
698 /*************************************************************************
699 * SwEditShell::HasConvIter
700 *************************************************************************/
702 BOOL
SwEditShell::HasConvIter() const
704 return 0 != pConvIter
;
707 /*************************************************************************
708 * SwEditShell::HasHyphIter
709 *************************************************************************/
711 BOOL
SwEditShell::HasHyphIter() const
713 return 0 != pHyphIter
;
716 /*************************************************************************
717 * SwEditShell::SetFindRange
718 *************************************************************************/
720 void SwEditShell::SetLinguRange( SwDocPositions eStart
, SwDocPositions eEnd
)
722 SwPaM
*pCrsr
= GetCrsr();
723 MakeFindRange( static_cast<USHORT
>(eStart
), static_cast<USHORT
>(eEnd
), pCrsr
);
724 if( *pCrsr
->GetPoint() > *pCrsr
->GetMark() )
728 /*************************************************************************
729 * SwEditShell::SpellStart
730 *************************************************************************/
732 void SwEditShell::SpellStart(
733 SwDocPositions eStart
, SwDocPositions eEnd
, SwDocPositions eCurr
,
734 SwConversionArgs
*pConvArgs
)
736 SwLinguIter
*pLinguIter
= 0;
738 // do not spell if interactive spelling is active elsewhere
739 if (!pConvArgs
&& !pSpellIter
)
741 ASSERT( !pSpellIter
, "wer ist da schon am spellen?" );
742 pSpellIter
= new SwSpellIter
;
743 pLinguIter
= pSpellIter
;
745 // do not do text conversion if it is active elsewhere
746 if (pConvArgs
&& !pConvIter
)
748 ASSERT( !pConvIter
, "text conversion already active!" );
749 pConvIter
= new SwConvIter( *pConvArgs
);
750 pLinguIter
= pConvIter
;
755 SwCursor
* pSwCrsr
= GetSwCrsr();
757 SwPosition
*pTmp
= new SwPosition( *pSwCrsr
->GetPoint() );
758 pSwCrsr
->FillFindPos( eCurr
, *pTmp
);
759 pLinguIter
->SetCurr( pTmp
);
761 pTmp
= new SwPosition( *pTmp
);
762 pLinguIter
->SetCurrX( pTmp
);
765 if (!pConvArgs
&& pSpellIter
)
766 pSpellIter
->Start( this, eStart
, eEnd
);
767 if (pConvArgs
&& pConvIter
)
768 pConvIter
->Start( this, eStart
, eEnd
);
771 /*************************************************************************
772 * SwEditShell::SpellEnd
773 *************************************************************************/
775 void SwEditShell::SpellEnd( SwConversionArgs
*pConvArgs
, bool bRestoreSelection
)
777 if (!pConvArgs
&& pSpellIter
&& pSpellIter
->GetSh() == this)
779 ASSERT( pSpellIter
, "wo ist mein Iterator?" );
780 pSpellIter
->_End(bRestoreSelection
);
781 delete pSpellIter
, pSpellIter
= 0;
783 if (pConvArgs
&& pConvIter
&& pConvIter
->GetSh() == this)
785 ASSERT( pConvIter
, "wo ist mein Iterator?" );
787 delete pConvIter
, pConvIter
= 0;
791 /*************************************************************************
792 * SwEditShell::SpellContinue
793 *************************************************************************/
795 // liefert Rueckgabewerte entsprechend SPL_ in splchk.hxx
797 uno::Any
SwEditShell::SpellContinue(
798 sal_uInt16
* pPageCnt
, sal_uInt16
* pPageSt
,
799 SwConversionArgs
*pConvArgs
)
803 if ((!pConvArgs
&& pSpellIter
->GetSh() != this) ||
804 ( pConvArgs
&& pConvIter
->GetSh() != this))
807 if( pPageCnt
&& !*pPageCnt
)
809 sal_uInt16 nEndPage
= GetLayout()->GetPageNum();
810 nEndPage
+= nEndPage
* 10 / 100;
811 *pPageCnt
= nEndPage
;
813 ::StartProgress( STR_STATSTR_SPELL
, 0, nEndPage
, GetDoc()->GetDocShell() );
816 ASSERT( pConvArgs
|| pSpellIter
, "SpellIter missing" );
817 ASSERT( !pConvArgs
|| pConvIter
, "ConvIter missing" );
818 //JP 18.07.95: verhinder bei Fehlermeldungen die Anzeige der Selektionen
819 // KEIN StartAction, da damit auch die Paints abgeschaltet
823 uno::Reference
< uno::XInterface
> xRet
;
826 pConvIter
->Continue( pPageCnt
, pPageSt
) >>= aRet
;
831 pSpellIter
->Continue( pPageCnt
, pPageSt
) >>= xRet
;
836 if( aRet
.getLength() || xRet
.is() )
838 // dann die awt::Selection sichtbar machen
844 /*************************************************************************
845 * SwEditShell::HyphStart
846 *************************************************************************/
848 /* Interaktive Trennung, BP 10.03.93
851 * - Aufheben aller Selektionen
852 * - Sichern des aktuellen Cursors
853 * - falls keine Selektion vorhanden:
854 * - neue Selektion bis zum Dokumentende
856 * - nLastHyphLen wird auf den Selektionsstart addiert
857 * - iteriert ueber alle selektierten Bereiche
858 * - pDoc->Hyphenate() iteriert ueber alle Nodes der Selektion
859 * - pTxtNode->Hyphenate() ruft das SwTxtFrm::Hyphenate zur EditShell
860 * - SwTxtFrm:Hyphenate() iteriert ueber die Zeilen des Pams
861 * - LineIter::Hyphenate() stellt den Hyphenator
862 * und den Pam auf das zu trennende Wort ein.
863 * - Es gibt nur zwei Returnwerte sal_True, wenn eine Trennstelle anliegt
864 * und sal_False, wenn der Pam abgearbeitet wurde.
865 * - Bei sal_True wird das selektierte Wort zur Anzeige gebracht und
866 * nLastHyphLen gesetzt.
867 * - Bei sal_False wird die aktuelle Selektion geloescht und die naechste
868 * zur aktuellen gewaehlt. Return HYPH_OK, wenn keine mehr vorhanden.
869 * 3) InsertSoftHyph (wird ggf. von der UI gerufen)
870 * - Der aktuelle Cursor wird plaziert und das Attribut eingefuegt.
872 * - Wiederherstellen des alten Cursors, EndAction
877 void SwEditShell::HyphStart( SwDocPositions eStart
, SwDocPositions eEnd
)
879 // do not hyphenate if interactive hyphenationg is active elsewhere
882 ASSERT( !pHyphIter
, "wer ist da schon am hyphinieren?" );
883 pHyphIter
= new SwHyphIter
;
884 pHyphIter
->Start( this, eStart
, eEnd
);
888 /*************************************************************************
889 * SwEditShell::HyphEnd
890 *************************************************************************/
892 // Selektionen wiederherstellen
896 void SwEditShell::HyphEnd()
898 if (pHyphIter
->GetSh() == this)
900 ASSERT( pHyphIter
, "wo ist mein Iterator?" );
902 delete pHyphIter
, pHyphIter
= 0;
906 /*************************************************************************
907 * SwEditShell::HyphContinue
908 *************************************************************************/
910 // Returnwerte: (BP: ich wuerde es genau umdrehen, aber die UI wuenscht es so)
911 // HYPH_CONTINUE, wenn eine Trennstelle anliegt
912 // HYPH_OK, wenn der selektierte Bereich abgearbeitet wurde.
915 uno::Reference
< uno::XInterface
>
916 SwEditShell::HyphContinue( sal_uInt16
* pPageCnt
, sal_uInt16
* pPageSt
)
918 if (pHyphIter
->GetSh() != this)
921 if( pPageCnt
&& !*pPageCnt
&& !*pPageSt
)
923 sal_uInt16 nEndPage
= GetLayout()->GetPageNum();
924 nEndPage
+= nEndPage
* 10 / 100;
927 *pPageCnt
= nEndPage
;
928 ::StartProgress( STR_STATSTR_HYPHEN
, 0, nEndPage
, GetDoc()->GetDocShell());
930 else // Hiermit unterdruecken wir ein fuer allemal
931 *pPageSt
= 1; // das StatLineStartPercent
934 ASSERT( pHyphIter
, "wo ist mein Iterator?" );
935 //JP 18.07.95: verhinder bei Fehlermeldungen die Anzeige der Selektionen
936 // KEIN StartAction, da damit auch die Paints abgeschaltet
939 uno::Reference
< uno::XInterface
> xRet
;
940 pHyphIter
->Continue( pPageCnt
, pPageSt
) >>= xRet
;
944 pHyphIter
->ShowSelection();
950 /*************************************************************************
951 * SwEditShell::InsertSoftHyph
952 *************************************************************************/
954 // Zum Einfuegen des SoftHyphens, Position ist der Offset
955 // innerhalb des getrennten Wortes.
958 void SwEditShell::InsertSoftHyph( const xub_StrLen nHyphPos
)
960 ASSERT( pHyphIter
, "wo ist mein Iterator?" );
961 pHyphIter
->InsertSoftHyph( nHyphPos
);
965 /*************************************************************************
966 * SwEditShell::HyphIgnore
967 *************************************************************************/
969 // Beschreibung: Trennstelle ignorieren
971 void SwEditShell::HyphIgnore()
973 ASSERT( pHyphIter
, "wo ist mein Iterator?" );
974 //JP 18.07.95: verhinder bei Fehlermeldungen die Anzeige der Selektionen
975 // KEIN StartAction, da damit auch die Paints abgeschaltet
981 pHyphIter
->ShowSelection();
984 /*************************************************************************
985 * SwEditShell::GetCorrection()
986 * liefert eine Liste von Vorschlaegen fuer falsch geschriebene Worte,
987 * ein NULL-Pointer signalisiert, dass das Wort richtig geschrieben ist,
988 * eine leere Liste, dass das Wort zwar unbekannt ist, aber keine Alternativen
989 * geliefert werden koennen.
990 *************************************************************************/
993 uno::Reference
< XSpellAlternatives
>
994 SwEditShell::GetCorrection( const Point
* pPt
, SwRect
& rSelectRect
)
996 uno::Reference
< XSpellAlternatives
> xSpellAlt
;
1000 SwPaM
* pCrsr
= GetCrsr();
1001 SwPosition
aPos( *pCrsr
->GetPoint() );
1003 SwCrsrMoveState
eTmpState( MV_SETONLYTEXT
);
1005 SwWrongList
*pWrong
;
1006 if( GetLayout()->GetCrsrOfst( &aPos
, aPt
, &eTmpState
) &&
1007 0 != (pNode
= aPos
.nNode
.GetNode().GetTxtNode()) &&
1008 0 != (pWrong
= pNode
->GetWrong()) &&
1009 !pNode
->IsInProtectSect() )
1011 xub_StrLen nBegin
= aPos
.nContent
.GetIndex();
1012 xub_StrLen nLen
= 1;
1013 if( pWrong
->InWrongWord(nBegin
,nLen
) && !pNode
->IsSymbol(nBegin
) )
1015 String
aText( pNode
->GetTxt().Copy( nBegin
, nLen
) );
1016 String
aWord( aText
);
1017 aWord
.EraseAllChars( CH_TXTATR_BREAKWORD
).EraseAllChars( CH_TXTATR_INWORD
);
1019 uno::Reference
< XSpellChecker1
> xSpell( ::GetSpellChecker() );
1022 LanguageType eActLang
= (LanguageType
)pNode
->GetLang( nBegin
, nLen
);
1023 if( xSpell
->hasLanguage( eActLang
))
1025 // restrict the maximal number of suggestions displayed
1026 // in the context menu.
1027 // Note: That could of course be done by clipping the
1028 // resulting sequence but the current third party
1029 // implementations result differs greatly if the number of
1030 // suggestions to be retuned gets changed. Statistically
1031 // it gets much better if told to return e.g. only 7 strings
1032 // than returning e.g. 16 suggestions and using only the
1033 // first 7. Thus we hand down the value to use to that
1034 // implementation here by providing an additional parameter.
1035 Sequence
< PropertyValue
> aPropVals(1);
1036 PropertyValue
&rVal
= aPropVals
.getArray()[0];
1037 rVal
.Name
= C2U( UPN_MAX_NUMBER_OF_SUGGESTIONS
);
1038 rVal
.Value
<<= (INT16
) 7;
1040 xSpellAlt
= xSpell
->spell( aWord
, eActLang
, aPropVals
);
1044 if ( xSpellAlt
.is() ) // error found?
1046 //save the start and end positons of the line and the starting point
1049 xub_StrLen nLineStart
= GetCrsr()->GetPoint()->nContent
.GetIndex();
1051 xub_StrLen nLineEnd
= GetCrsr()->GetPoint()->nContent
.GetIndex();
1054 // make sure the selection build later from the
1055 // data below does not include footnotes and other
1056 // "in word" character to the left and right in order
1057 // to preserve those. Therefore count those "in words"
1058 // in order to modify the selection accordingly.
1059 const sal_Unicode
* pChar
= aText
.GetBuffer();
1060 xub_StrLen nLeft
= 0;
1061 while (pChar
&& *pChar
++ == CH_TXTATR_INWORD
)
1063 pChar
= aText
.Len() ? aText
.GetBuffer() + aText
.Len() - 1 : 0;
1064 xub_StrLen nRight
= 0;
1065 while (pChar
&& *pChar
-- == CH_TXTATR_INWORD
)
1068 aPos
.nContent
= nBegin
+ nLeft
;
1070 *pCrsr
->GetPoint() = aPos
;
1072 ExtendSelection( sal_True
, nLen
- nLeft
- nRight
);
1073 //no determine the rectangle in the current line
1074 xub_StrLen nWordStart
= (nBegin
+ nLeft
) < nLineStart
? nLineStart
: nBegin
+ nLeft
;
1075 //take one less than the line end - otherwise the next line would be calculated
1076 xub_StrLen nWordEnd
= (nBegin
+ nLen
- nLeft
- nRight
) > nLineEnd
? nLineEnd
- 1: (nBegin
+ nLen
- nLeft
- nRight
);
1078 pCrsr
->DeleteMark();
1079 SwIndex
& rContent
= GetCrsr()->GetPoint()->nContent
;
1080 rContent
= nWordStart
;
1082 SwCrsrMoveState aState
;
1083 aState
.bRealWidth
= TRUE
;
1084 SwCntntNode
* pCntntNode
= pCrsr
->GetCntntNode();
1085 SwCntntFrm
*pCntntFrame
= pCntntNode
->GetFrm(pPt
, pCrsr
->GetPoint(), FALSE
);
1087 pCntntFrame
->GetCharRect( aStartRect
, *pCrsr
->GetPoint(), &aState
);
1088 rContent
= nWordEnd
;
1090 pCntntFrame
->GetCharRect( aEndRect
, *pCrsr
->GetPoint(),&aState
);
1091 rSelectRect
= aStartRect
.Union( aEndRect
);
1099 /*-------------------------------------------------------------------------
1101 -----------------------------------------------------------------------*/
1103 bool SwEditShell::GetGrammarCorrection(
1104 linguistic2::ProofreadingResult
/*out*/ &rResult
, // the complete result
1105 sal_Int32
/*out*/ &rErrorPosInText
, // offset of error position in string that was grammar checked...
1106 sal_Int32
/*out*/ &rErrorIndexInResult
, // index of error in rResult.aGrammarErrors
1107 uno::Sequence
< rtl::OUString
> /*out*/ &rSuggestions
, // suggestions to be used for the error found
1108 const Point
*pPt
, SwRect
&rSelectRect
)
1115 SwPaM
* pCrsr
= GetCrsr();
1116 SwPosition
aPos( *pCrsr
->GetPoint() );
1118 SwCrsrMoveState
eTmpState( MV_SETONLYTEXT
);
1120 SwGrammarMarkUp
*pWrong
;
1121 if( GetLayout()->GetCrsrOfst( &aPos
, aPt
, &eTmpState
) &&
1122 0 != (pNode
= aPos
.nNode
.GetNode().GetTxtNode()) &&
1123 0 != (pWrong
= pNode
->GetGrammarCheck()) &&
1124 !pNode
->IsInProtectSect() )
1126 xub_StrLen nBegin
= aPos
.nContent
.GetIndex();
1127 xub_StrLen nLen
= 1;
1128 if (pWrong
->InWrongWord(nBegin
, nLen
))
1130 String
aText( pNode
->GetTxt().Copy( nBegin
, nLen
) );
1131 String
aWord( aText
);
1132 aWord
.EraseAllChars( CH_TXTATR_BREAKWORD
).EraseAllChars( CH_TXTATR_INWORD
);
1134 uno::Reference
< linguistic2::XProofreadingIterator
> xGCIterator( pDoc
->GetGCIterator() );
1135 if (xGCIterator
.is())
1137 // LanguageType eActLang = (LanguageType)pNode->GetLang( nBegin, nLen );
1138 uno::Reference
< lang::XComponent
> xDoc( pDoc
->GetDocShell()->GetBaseModel(), uno::UNO_QUERY
);
1140 // Expand the string:
1141 rtl::OUString aExpandText
;
1142 const ModelToViewHelper::ConversionMap
* pConversionMap
=
1143 pNode
->BuildConversionMap( aExpandText
);
1144 // get XFlatParagraph to use...
1145 uno::Reference
< text::XFlatParagraph
> xFlatPara
= new SwXFlatParagraph( *pNode
, aExpandText
, pConversionMap
);
1147 // get error position of cursor in XFlatParagraph
1148 rErrorPosInText
= ModelToViewHelper::ConvertToViewPosition( pConversionMap
, nBegin
);
1150 sal_Int32 nStartOfSentence
= ModelToViewHelper::ConvertToViewPosition( pConversionMap
, pWrong
->getSentenceStart( nBegin
) );
1151 sal_Int32 nEndOfSentence
= ModelToViewHelper::ConvertToViewPosition( pConversionMap
, pWrong
->getSentenceEnd( nBegin
) );
1152 if( nEndOfSentence
== STRING_LEN
)
1154 /* if( nStartOfSentence == 0 )
1156 nStartOfSentence = -1;
1157 nEndOfSentence = -1;
1160 nEndOfSentence
= aExpandText
.getLength();
1163 rResult
= xGCIterator
->checkSentenceAtPosition(
1164 xDoc
, xFlatPara
, aExpandText
, lang::Locale(), nStartOfSentence
, nEndOfSentence
, rErrorPosInText
);
1167 // get suggestions to use for the specific error position
1168 sal_Int32 nErrors
= rResult
.aErrors
.getLength();
1169 rSuggestions
.realloc( 0 );
1170 for (sal_Int32 i
= 0; i
< nErrors
; ++i
)
1172 // return suggestions for first error that includes the given error position
1173 const linguistic2::SingleProofreadingError
&rError
= rResult
.aErrors
[i
];
1174 if (rError
.nErrorStart
<= rErrorPosInText
&&
1175 rErrorPosInText
< rError
.nErrorStart
+ rError
.nErrorLength
)
1177 rSuggestions
= rError
.aSuggestions
;
1178 rErrorIndexInResult
= i
;
1184 if (rResult
.aErrors
.getLength() > 0) // error found?
1186 //save the start and end positons of the line and the starting point
1189 xub_StrLen nLineStart
= GetCrsr()->GetPoint()->nContent
.GetIndex();
1191 xub_StrLen nLineEnd
= GetCrsr()->GetPoint()->nContent
.GetIndex();
1194 #if OSL_DEBUG_LEVEL > 1
1195 // pNode->GetGrammarCheck()->Invalidate( 0, STRING_LEN );
1196 // pNode->SetGrammarCheckDirty( true );
1198 // make sure the selection build later from the
1199 // data below does not include footnotes and other
1200 // "in word" character to the left and right in order
1201 // to preserve those. Therefore count those "in words"
1202 // in order to modify the selection accordingly.
1203 const sal_Unicode
* pChar
= aText
.GetBuffer();
1204 xub_StrLen nLeft
= 0;
1205 while (pChar
&& *pChar
++ == CH_TXTATR_INWORD
)
1207 pChar
= aText
.Len() ? aText
.GetBuffer() + aText
.Len() - 1 : 0;
1208 xub_StrLen nRight
= 0;
1209 while (pChar
&& *pChar
-- == CH_TXTATR_INWORD
)
1212 aPos
.nContent
= nBegin
+ nLeft
;
1214 *pCrsr
->GetPoint() = aPos
;
1216 ExtendSelection( sal_True
, nLen
- nLeft
- nRight
);
1217 //no determine the rectangle in the current line
1218 xub_StrLen nWordStart
= (nBegin
+ nLeft
) < nLineStart
? nLineStart
: nBegin
+ nLeft
;
1219 //take one less than the line end - otherwise the next line would be calculated
1220 xub_StrLen nWordEnd
= (nBegin
+ nLen
- nLeft
- nRight
) > nLineEnd
? nLineEnd
- 1: (nBegin
+ nLen
- nLeft
- nRight
);
1222 pCrsr
->DeleteMark();
1223 SwIndex
& rContent
= GetCrsr()->GetPoint()->nContent
;
1224 rContent
= nWordStart
;
1226 SwCrsrMoveState aState
;
1227 aState
.bRealWidth
= TRUE
;
1228 SwCntntNode
* pCntntNode
= pCrsr
->GetCntntNode();
1229 SwCntntFrm
*pCntntFrame
= pCntntNode
->GetFrm(pPt
, pCrsr
->GetPoint(), FALSE
);
1231 pCntntFrame
->GetCharRect( aStartRect
, *pCrsr
->GetPoint(), &aState
);
1232 rContent
= nWordEnd
;
1234 pCntntFrame
->GetCharRect( aEndRect
, *pCrsr
->GetPoint(),&aState
);
1235 rSelectRect
= aStartRect
.Union( aEndRect
);
1244 /*-- 18.09.2003 15:08:18---------------------------------------------------
1246 -----------------------------------------------------------------------*/
1247 bool SwEditShell::SpellSentence(::svx::SpellPortions
& rPortions
, bool bIsGrammarCheck
)
1249 ASSERT( pSpellIter
, "SpellIter missing" );
1252 bool bRet
= pSpellIter
->SpellSentence(rPortions
, bIsGrammarCheck
);
1254 // make Selection visible - this should simply move the
1255 // cursor to the end of the sentence
1260 /*-- 08.09.2008 09:35:19---------------------------------------------------
1261 make SpellIter start with the current sentence when called next time
1262 -----------------------------------------------------------------------*/
1263 void SwEditShell::PutSpellingToSentenceStart()
1265 ASSERT( pSpellIter
, "SpellIter missing" );
1268 pSpellIter
->ToSentenceStart();
1270 /*-- 02.02.2005 14:34:41---------------------------------------------------
1272 -----------------------------------------------------------------------*/
1273 sal_uInt32
lcl_CountRedlines(
1274 const ::svx::SpellPortions
& rLastPortions
)
1276 sal_uInt32 nRet
= 0;
1277 SpellPortions::const_iterator aIter
= rLastPortions
.begin();
1278 for( ; aIter
!= rLastPortions
.end(); ++aIter
)
1280 if( aIter
->bIsHidden
)
1285 /*-- 18.09.2003 15:08:20---------------------------------------------------
1287 -----------------------------------------------------------------------*/
1288 void SwEditShell::ApplyChangedSentence(const ::svx::SpellPortions
& rNewPortions
, bool bIsGrammarCheck
)
1290 ASSERT( pSpellIter
, "SpellIter missing" );
1293 const SpellPortions
& rLastPortions
= pSpellIter
->GetLastPortions();
1294 const SpellContentPositions rLastPositions
= pSpellIter
->GetLastPositions();
1295 ASSERT(rLastPortions
.size() > 0 &&
1296 rLastPortions
.size() == rLastPositions
.size(),
1297 "last vectors of spelling results are not set or not equal")
1299 // iterate over the new portions, beginning at the end to take advantage of the previously
1300 // saved content positions
1302 if(!rLastPortions
.size())
1305 SwPaM
*pCrsr
= GetCrsr();
1306 pDoc
->StartUndo( UNDO_OVERWRITE
, NULL
);
1308 sal_uInt32 nRedlinePortions
= lcl_CountRedlines(rLastPortions
);
1309 if((rLastPortions
.size() - nRedlinePortions
) == rNewPortions
.size())
1311 //the simple case: the same number of elements on both sides
1312 //each changed element has to be applied to the corresponding source element
1313 svx::SpellPortions::const_iterator aCurrentNewPortion
= rNewPortions
.end();
1314 SpellPortions::const_iterator aCurrentOldPortion
= rLastPortions
.end();
1315 SpellContentPositions::const_iterator aCurrentOldPosition
= rLastPositions
.end();
1318 --aCurrentNewPortion
;
1319 --aCurrentOldPortion
;
1320 --aCurrentOldPosition
;
1321 //jump over redline portions
1322 while(aCurrentOldPortion
->bIsHidden
)
1324 --aCurrentOldPortion
;
1325 --aCurrentOldPosition
;
1327 if ( !pCrsr
->HasMark() )
1329 pCrsr
->GetPoint()->nContent
= aCurrentOldPosition
->nLeft
;
1330 pCrsr
->GetMark()->nContent
= aCurrentOldPosition
->nRight
;
1331 USHORT nScriptType
= GetI18NScriptTypeOfLanguage( aCurrentNewPortion
->eLanguage
);
1332 USHORT nLangWhichId
= RES_CHRATR_LANGUAGE
;
1335 case SCRIPTTYPE_ASIAN
: nLangWhichId
= RES_CHRATR_CJK_LANGUAGE
; break;
1336 case SCRIPTTYPE_COMPLEX
: nLangWhichId
= RES_CHRATR_CTL_LANGUAGE
; break;
1338 if(aCurrentNewPortion
->sText
!= aCurrentOldPortion
->sText
)
1341 pDoc
->DeleteAndJoin(*pCrsr
);
1342 // ... and apply language if necessary
1343 if(aCurrentNewPortion
->eLanguage
!= aCurrentOldPortion
->eLanguage
)
1344 SetAttr( SvxLanguageItem(aCurrentNewPortion
->eLanguage
, nLangWhichId
), nLangWhichId
);
1345 pDoc
->Insert(*pCrsr
, aCurrentNewPortion
->sText
, true);
1347 else if(aCurrentNewPortion
->eLanguage
!= aCurrentOldPortion
->eLanguage
)
1350 SetAttr( SvxLanguageItem(aCurrentNewPortion
->eLanguage
, nLangWhichId
), nLangWhichId
);
1352 else if( aCurrentNewPortion
->bIgnoreThisError
)
1354 //add the 'ignore' markup to the TextNode's grammar ignore markup list
1355 IgnoreGrammarErrorAt( *pCrsr
);
1356 DBG_ERROR("TODO: add ignore mark to text node");
1358 if(aCurrentNewPortion
== rNewPortions
.begin())
1361 while(aCurrentNewPortion
!= rNewPortions
.begin());
1365 //select the complete sentence
1366 SpellContentPositions::const_iterator aCurrentEndPosition
= rLastPositions
.end();
1367 --aCurrentEndPosition
;
1368 SpellContentPositions::const_iterator aCurrentStartPosition
= rLastPositions
.begin();
1369 pCrsr
->GetPoint()->nContent
= aCurrentStartPosition
->nLeft
;
1370 pCrsr
->GetMark()->nContent
= aCurrentEndPosition
->nRight
;
1372 //delete the sentence completely
1373 pDoc
->DeleteAndJoin(*pCrsr
);
1374 svx::SpellPortions::const_iterator aCurrentNewPortion
= rNewPortions
.begin();
1375 while(aCurrentNewPortion
!= rNewPortions
.end())
1377 //set the language attribute
1378 USHORT nScriptType
= GetScriptType();
1379 USHORT nLangWhichId
= RES_CHRATR_LANGUAGE
;
1382 case SCRIPTTYPE_ASIAN
: nLangWhichId
= RES_CHRATR_CJK_LANGUAGE
; break;
1383 case SCRIPTTYPE_COMPLEX
: nLangWhichId
= RES_CHRATR_CTL_LANGUAGE
; break;
1385 SfxItemSet
aSet(GetAttrPool(), nLangWhichId
, nLangWhichId
, 0);
1387 const SvxLanguageItem
& rLang
= static_cast<const SvxLanguageItem
& >(aSet
.Get(nLangWhichId
));
1388 if(rLang
.GetLanguage() != aCurrentNewPortion
->eLanguage
)
1389 SetAttr( SvxLanguageItem(aCurrentNewPortion
->eLanguage
, nLangWhichId
) );
1390 //insert the new string
1391 pDoc
->Insert(*pCrsr
, aCurrentNewPortion
->sText
, true);
1393 //set the cursor to the end of the inserted string
1394 *pCrsr
->Start() = *pCrsr
->End();
1395 ++aCurrentNewPortion
;
1399 //set the cursor to the end of the new sentence
1400 *pCrsr
->Start() = *pCrsr
->End();
1401 if( bIsGrammarCheck
)
1403 //in grammar check the current sentence has to be checked again
1406 pDoc
->EndUndo( UNDO_OVERWRITE
, NULL
);
1410 /*-- 02.02.2005 10:46:45---------------------------------------------------
1411 collect all deleted redlines of the current text node beginning at the
1412 start of the cursor position
1413 -----------------------------------------------------------------------*/
1414 SpellContentPositions
lcl_CollectDeletedRedlines(SwEditShell
* pSh
)
1416 SpellContentPositions aRedlines
;
1417 SwDoc
* pDoc
= pSh
->GetDoc();
1418 const bool bShowChg
= IDocumentRedlineAccess::IsShowChanges( pDoc
->GetRedlineMode() );
1421 SwPaM
*pCrsr
= pSh
->GetCrsr();
1422 const SwPosition
* pStartPos
= pCrsr
->Start();
1423 const SwTxtNode
* pTxtNode
= pCrsr
->GetNode()->GetTxtNode();
1425 USHORT nAct
= pDoc
->GetRedlinePos( *pTxtNode
, USHRT_MAX
);
1426 const xub_StrLen nStartIndex
= pStartPos
->nContent
.GetIndex();
1427 for ( ; nAct
< pDoc
->GetRedlineTbl().Count(); nAct
++ )
1429 const SwRedline
* pRed
= pDoc
->GetRedlineTbl()[ nAct
];
1431 if ( pRed
->Start()->nNode
> pTxtNode
->GetIndex() )
1434 if( nsRedlineType_t::REDLINE_DELETE
== pRed
->GetType() )
1436 xub_StrLen nStart
, nEnd
;
1437 pRed
->CalcStartEnd( pTxtNode
->GetIndex(), nStart
, nEnd
);
1438 if(nStart
>= nStartIndex
|| nEnd
>= nStartIndex
)
1440 SpellContentPosition aAdd
;
1441 aAdd
.nLeft
= nStart
;
1443 aRedlines
.push_back(aAdd
);
1450 /*-- 02.02.2005 11:06:12---------------------------------------------------
1451 remove the redline positions after the current selection
1452 -----------------------------------------------------------------------*/
1453 void lcl_CutRedlines( SpellContentPositions
& aDeletedRedlines
, SwEditShell
* pSh
)
1455 if(!aDeletedRedlines
.empty())
1457 SwPaM
*pCrsr
= pSh
->GetCrsr();
1458 const SwPosition
* pEndPos
= pCrsr
->End();
1459 xub_StrLen nEnd
= pEndPos
->nContent
.GetIndex();
1460 while(!aDeletedRedlines
.empty() &&
1461 aDeletedRedlines
.back().nLeft
> nEnd
)
1463 aDeletedRedlines
.pop_back();
1467 /*-- 02.02.2005 11:43:00---------------------------------------------------
1469 -----------------------------------------------------------------------*/
1470 SpellContentPosition
lcl_FindNextDeletedRedline(
1471 const SpellContentPositions
& rDeletedRedlines
,
1472 xub_StrLen nSearchFrom
)
1474 SpellContentPosition aRet
;
1475 aRet
.nLeft
= aRet
.nRight
= STRING_MAXLEN
;
1476 if(!rDeletedRedlines
.empty())
1478 SpellContentPositions::const_iterator aIter
= rDeletedRedlines
.begin();
1479 for( ; aIter
!= rDeletedRedlines
.end(); ++aIter
)
1481 if(aIter
->nLeft
< nSearchFrom
)
1489 /*-- 18.09.2003 15:08:20---------------------------------------------------
1491 -----------------------------------------------------------------------*/
1492 bool SwSpellIter::SpellSentence(::svx::SpellPortions
& rPortions
, bool bIsGrammarCheck
)
1495 aLastPortions
.clear();
1496 aLastPositions
.clear();
1498 SwEditShell
*pMySh
= GetSh();
1502 ASSERT( GetEnd(), "SwEditShell::SpellSentence() ohne Start?");
1504 uno::Reference
< XSpellAlternatives
> xSpellRet
;
1505 linguistic2::ProofreadingResult aGrammarResult
;
1506 sal_Bool bGoOn
= sal_True
;
1507 bool bGrammarErrorFound
= false;
1509 SwPaM
*pCrsr
= pMySh
->GetCrsr();
1510 if ( !pCrsr
->HasMark() )
1513 *pCrsr
->GetPoint() = *GetCurr();
1514 *pCrsr
->GetMark() = *GetEnd();
1516 if( bBackToStartOfSentence
)
1518 pMySh
->GoStartSentence();
1519 bBackToStartOfSentence
= false;
1521 uno::Any aSpellRet
=
1522 pMySh
->GetDoc()->Spell(*pCrsr
,
1523 xSpeller
, 0, 0, bIsGrammarCheck
);
1524 aSpellRet
>>= xSpellRet
;
1525 aSpellRet
>>= aGrammarResult
;
1526 bGoOn
= GetCrsrCnt() > 1;
1527 bGrammarErrorFound
= aGrammarResult
.aErrors
.getLength() > 0;
1528 if( xSpellRet
.is() || bGrammarErrorFound
)
1531 SwPosition
* pNewPoint
= new SwPosition( *pCrsr
->GetPoint() );
1532 SwPosition
* pNewMark
= new SwPosition( *pCrsr
->GetMark() );
1534 SetCurr( pNewPoint
);
1535 SetCurrX( pNewMark
);
1539 pMySh
->Pop( sal_False
);
1540 pCrsr
= pMySh
->GetCrsr();
1541 if ( *pCrsr
->GetPoint() > *pCrsr
->GetMark() )
1543 SwPosition
* pNew
= new SwPosition( *pCrsr
->GetPoint() );
1545 pNew
= new SwPosition( *pCrsr
->GetMark() );
1547 pNew
= new SwPosition( *GetStart() );
1549 pNew
= new SwPosition( *pNew
);
1556 if(xSpellRet
.is() || bGrammarErrorFound
)
1558 //an error has been found
1559 //To fill the spell portions the beginning of the sentence has to be found
1560 SwPaM
*pCrsr
= pMySh
->GetCrsr();
1561 //set the mark to the right if necessary
1562 if ( *pCrsr
->GetPoint() > *pCrsr
->GetMark() )
1564 //the cursor has to be collapsed on the left to go to the start of the sentence - if sentence ends inside of the error
1565 pCrsr
->DeleteMark();
1567 BOOL bStartSent
= 0 != pMySh
->GoStartSentence();
1568 SpellContentPositions aDeletedRedlines
= lcl_CollectDeletedRedlines(pMySh
);
1571 //create a portion from the start part
1572 AddPortion(0, 0, aDeletedRedlines
);
1574 //Set the cursor to the error already found
1575 *pCrsr
->GetPoint() = *GetCurrX();
1576 *pCrsr
->GetMark() = *GetCurr();
1577 AddPortion(xSpellRet
, &aGrammarResult
, aDeletedRedlines
);
1580 //save the end position of the error to continue from here
1581 SwPosition aSaveStartPos
= *pCrsr
->End();
1582 //determine the end of the current sentence
1583 if ( *pCrsr
->GetPoint() < *pCrsr
->GetMark() )
1585 //again collapse to start marking after the end of the error
1586 pCrsr
->DeleteMark();
1589 pMySh
->GoEndSentence();
1590 if( bGrammarErrorFound
)
1592 rtl::OUString aExpandText
;
1593 const ModelToViewHelper::ConversionMap
* pConversionMap
= ((SwTxtNode
*)pCrsr
->GetNode())->BuildConversionMap( aExpandText
);
1594 xub_StrLen nSentenceEnd
= (xub_StrLen
)ModelToViewHelper::ConvertToViewPosition( pConversionMap
, aGrammarResult
.nBehindEndOfSentencePosition
);
1595 // remove trailing space
1596 if( aExpandText
[nSentenceEnd
- 1] == ' ' )
1598 if( pCrsr
->End()->nContent
.GetIndex() < nSentenceEnd
)
1600 pCrsr
->End()->nContent
.Assign(
1601 pCrsr
->End()->nNode
.GetNode().GetCntntNode(), nSentenceEnd
);
1605 lcl_CutRedlines( aDeletedRedlines
, pMySh
);
1606 //save the 'global' end of the spellchecking
1607 const SwPosition aSaveEndPos
= *GetEnd();
1608 //set the sentence end as 'local' end
1609 SetEnd( new SwPosition( *pCrsr
->End() ));
1611 *pCrsr
->GetPoint() = aSaveStartPos
;
1612 *pCrsr
->GetMark() = *GetEnd();
1613 //now the rest of the sentence has to be searched for errors
1614 // for each error the non-error text between the current and the last error has
1615 // to be added to the portions - if necessary broken into same-language-portions
1616 if( !bGrammarErrorFound
) //in grammar check there's only one error returned
1621 // don't search for grammar errors here anymore!
1622 pMySh
->GetDoc()->Spell(*pCrsr
,
1623 xSpeller
, 0, 0, false ) >>= xSpellRet
;
1624 if ( *pCrsr
->GetPoint() > *pCrsr
->GetMark() )
1626 SetCurr( new SwPosition( *pCrsr
->GetPoint() ));
1627 SetCurrX( new SwPosition( *pCrsr
->GetMark() ));
1629 //if an error has been found go back to the text
1630 //preceeding the error
1633 *pCrsr
->GetPoint() = aSaveStartPos
;
1634 *pCrsr
->GetMark() = *GetCurr();
1637 AddPortion(0, 0, aDeletedRedlines
);
1641 *pCrsr
->GetPoint() = *GetCurr();
1642 *pCrsr
->GetMark() = *GetCurrX();
1643 AddPortion(xSpellRet
, 0, aDeletedRedlines
);
1644 //move the cursor to the end of the error string
1645 *pCrsr
->GetPoint() = *GetCurrX();
1646 //and save the end of the error as new start position
1647 aSaveStartPos
= *GetCurrX();
1648 //and the end of the sentence
1649 *pCrsr
->GetMark() = *GetEnd();
1651 // if the end of the sentence has already been reached then break here
1652 if(*GetCurrX() >= *GetEnd())
1655 while(xSpellRet
.is());
1659 //go to the end of sentence as the grammar check returned it
1660 // at this time the Point is behind the grammar error
1661 // and the mark points to the sentence end as
1662 if ( *pCrsr
->GetPoint() < *pCrsr
->GetMark() )
1666 // the part between the last error and the end of the sentence has to be added
1667 *pMySh
->GetCrsr()->GetPoint() = *GetEnd();
1668 if(*GetCurrX() < *GetEnd())
1670 AddPortion(0, 0, aDeletedRedlines
);
1672 //set the shell cursor to the end of the sentence to prevent a visible selection
1673 *pCrsr
->GetMark() = *GetEnd();
1674 if( !bIsGrammarCheck
)
1676 //set the current position to the end of the sentence
1677 SetCurr( new SwPosition(*GetEnd()) );
1679 //restore the 'global' end
1680 SetEnd( new SwPosition(aSaveEndPos
) );
1681 rPortions
= aLastPortions
;
1686 //if no error could be found the selection has to be corrected - at least if it's not in the body
1687 *pMySh
->GetCrsr()->GetPoint() = *GetEnd();
1688 pMySh
->GetCrsr()->DeleteMark();
1694 /*-- 08.09.2008 09:37:15---------------------------------------------------
1696 -----------------------------------------------------------------------*/
1697 void SwSpellIter::ToSentenceStart()
1699 bBackToStartOfSentence
= true;
1701 /*-- 08.10.2003 08:49:56---------------------------------------------------
1703 -----------------------------------------------------------------------*/
1704 LanguageType
lcl_GetLanguage(SwEditShell
& rSh
)
1706 USHORT nScriptType
= rSh
.GetScriptType();
1707 USHORT nLangWhichId
= RES_CHRATR_LANGUAGE
;
1711 case SCRIPTTYPE_ASIAN
: nLangWhichId
= RES_CHRATR_CJK_LANGUAGE
; break;
1712 case SCRIPTTYPE_COMPLEX
: nLangWhichId
= RES_CHRATR_CTL_LANGUAGE
; break;
1714 SfxItemSet
aSet(rSh
.GetAttrPool(), nLangWhichId
, nLangWhichId
, 0);
1715 rSh
.GetCurAttr( aSet
);
1716 const SvxLanguageItem
& rLang
= static_cast<const SvxLanguageItem
& >(aSet
.Get(nLangWhichId
));
1717 return rLang
.GetLanguage();
1719 /*-- 08.10.2003 08:53:27---------------------------------------------------
1720 create a text portion at the given position
1721 -----------------------------------------------------------------------*/
1722 void SwSpellIter::CreatePortion(uno::Reference
< XSpellAlternatives
> xAlt
,
1723 linguistic2::ProofreadingResult
* pGrammarResult
,
1724 bool bIsField
, bool bIsHidden
)
1726 svx::SpellPortion aPortion
;
1728 GetSh()->GetSelectedText( sText
);
1731 //in case of redlined deletions the selection of an error is not
1732 //the same as the _real_ word
1734 aPortion
.sText
= xAlt
->getWord();
1735 else if(pGrammarResult
)
1737 aPortion
.bIsGrammarError
= true;
1738 if(pGrammarResult
->aErrors
.getLength())
1740 aPortion
.aGrammarError
= pGrammarResult
->aErrors
[0];
1741 aPortion
.sText
= pGrammarResult
->aText
.copy( aPortion
.aGrammarError
.nErrorStart
, aPortion
.aGrammarError
.nErrorLength
);
1742 aPortion
.xGrammarChecker
= pGrammarResult
->xProofreader
;
1743 const beans::PropertyValue
* pProperties
= pGrammarResult
->aProperties
.getConstArray();
1744 for( sal_Int32 nProp
= 0; nProp
< pGrammarResult
->aProperties
.getLength(); ++nProp
)
1746 if( pProperties
->Name
.equalsAscii("DialogTitle") )
1748 pProperties
->Value
>>= aPortion
.sDialogTitle
;
1755 aPortion
.sText
= sText
;
1756 aPortion
.eLanguage
= lcl_GetLanguage(*GetSh());
1757 aPortion
.bIsField
= bIsField
;
1758 aPortion
.bIsHidden
= bIsHidden
;
1759 aPortion
.xAlternatives
= xAlt
;
1760 SpellContentPosition aPosition
;
1761 SwPaM
*pCrsr
= GetSh()->GetCrsr();
1762 aPosition
.nLeft
= pCrsr
->Start()->nContent
.GetIndex();
1763 aPosition
.nRight
= pCrsr
->End()->nContent
.GetIndex();
1764 aLastPortions
.push_back(aPortion
);
1765 aLastPositions
.push_back(aPosition
);
1768 /*-- 19.09.2003 13:05:43---------------------------------------------------
1770 -----------------------------------------------------------------------*/
1771 void SwSpellIter::AddPortion(uno::Reference
< XSpellAlternatives
> xAlt
,
1772 linguistic2::ProofreadingResult
* pGrammarResult
,
1773 const SpellContentPositions
& rDeletedRedlines
)
1775 SwEditShell
*pMySh
= GetSh();
1777 pMySh
->GetSelectedText( sText
);
1780 if(xAlt
.is() || pGrammarResult
!= 0)
1782 CreatePortion(xAlt
, pGrammarResult
, false, false);
1786 SwPaM
*pCrsr
= GetSh()->GetCrsr();
1787 if ( *pCrsr
->GetPoint() > *pCrsr
->GetMark() )
1789 //save the start and end positions
1790 SwPosition
aStart(*pCrsr
->GetPoint());
1791 SwPosition
aEnd(*pCrsr
->GetMark());
1792 //iterate over the text to find changes in language
1793 //set the mark equal to the point
1794 *pCrsr
->GetMark() = aStart
;
1795 SwTxtNode
* pTxtNode
= pCrsr
->GetNode()->GetTxtNode();
1796 LanguageType eStartLanguage
= lcl_GetLanguage(*GetSh());
1797 SpellContentPosition aNextRedline
= lcl_FindNextDeletedRedline(
1798 rDeletedRedlines
, aStart
.nContent
.GetIndex() );
1799 if( aNextRedline
.nLeft
== aStart
.nContent
.GetIndex() )
1801 //select until the end of the current redline
1802 xub_StrLen nEnd
= aEnd
.nContent
.GetIndex() < aNextRedline
.nRight
?
1803 aEnd
.nContent
.GetIndex() : aNextRedline
.nRight
;
1804 pCrsr
->GetPoint()->nContent
.Assign( pTxtNode
, nEnd
);
1805 CreatePortion(xAlt
, pGrammarResult
, false, true);
1806 aStart
= *pCrsr
->End();
1807 //search for next redline
1808 aNextRedline
= lcl_FindNextDeletedRedline(
1809 rDeletedRedlines
, aStart
.nContent
.GetIndex() );
1811 while(*pCrsr
->GetPoint() < aEnd
)
1813 //#125786 in table cell with fixed row height the cursor might not move forward
1814 if(!GetSh()->Right(1, CRSR_SKIP_CELLS
))
1817 bool bField
= false;
1818 //read the character at the current position to check if it's a field
1819 xub_Unicode cChar
= pTxtNode
->GetTxt().GetChar( pCrsr
->GetMark()->nContent
.GetIndex() );
1820 if( CH_TXTATR_BREAKWORD
== cChar
|| CH_TXTATR_INWORD
== cChar
)
1822 const SwTxtAttr
* pTxtAttr
= pTxtNode
->GetTxtAttr(
1823 pCrsr
->GetMark()->nContent
.GetIndex(), RES_TXTATR_FIELD
);
1824 bField
= 0 != pTxtAttr
;
1827 const SwTxtAttr
* pTmpTxtAttr
= pTxtNode
->GetTxtAttr(
1828 pCrsr
->GetMark()->nContent
.GetIndex(), RES_TXTATR_FTN
);
1829 bField
= 0 != pTmpTxtAttr
;
1833 const SwTxtAttr
* pTmpTxtAttr
= pTxtNode
->GetTxtAttr(
1834 pCrsr
->GetMark()->nContent
.GetIndex(), RES_TXTATR_FLYCNT
);
1835 bField
= 0 != pTmpTxtAttr
;
1839 LanguageType eCurLanguage
= lcl_GetLanguage(*GetSh());
1840 bool bRedline
= aNextRedline
.nLeft
== pCrsr
->GetPoint()->nContent
.GetIndex();
1841 // create a portion if the next character
1843 // - is at the beginning of a deleted redline
1844 // - has a different language
1845 if(bField
|| bRedline
|| eCurLanguage
!= eStartLanguage
)
1847 eStartLanguage
= eCurLanguage
;
1848 //go one step back - the cursor currently selects the first character
1849 //with a different language
1850 //in the case of redlining it's different
1851 if(eCurLanguage
!= eStartLanguage
|| bField
)
1852 *pCrsr
->GetPoint() = *pCrsr
->GetMark();
1853 //set to the last start
1854 *pCrsr
->GetMark() = aStart
;
1855 //create portion should only be called if a selection exists
1856 //there's no selection if there's a field at the beginning
1857 if(*pCrsr
->Start() != *pCrsr
->End())
1858 CreatePortion(xAlt
, pGrammarResult
, false, false);
1859 aStart
= *pCrsr
->End();
1860 //now export the field - if there is any
1863 *pCrsr
->GetMark() = *pCrsr
->GetPoint();
1864 GetSh()->Right(1, CRSR_SKIP_CELLS
);
1865 CreatePortion(xAlt
, pGrammarResult
, true, false);
1866 aStart
= *pCrsr
->End();
1869 // if a redline start then create a portion for it
1872 *pCrsr
->GetMark() = *pCrsr
->GetPoint();
1873 //select until the end of the current redline
1874 xub_StrLen nEnd
= aEnd
.nContent
.GetIndex() < aNextRedline
.nRight
?
1875 aEnd
.nContent
.GetIndex() : aNextRedline
.nRight
;
1876 pCrsr
->GetPoint()->nContent
.Assign( pTxtNode
, nEnd
);
1877 CreatePortion(xAlt
, pGrammarResult
, false, true);
1878 aStart
= *pCrsr
->End();
1879 //search for next redline
1880 aNextRedline
= lcl_FindNextDeletedRedline(
1881 rDeletedRedlines
, aStart
.nContent
.GetIndex() );
1883 *pCrsr
->GetMark() = *pCrsr
->GetPoint();
1886 *pCrsr
->GetMark() = aStart
;
1887 CreatePortion(xAlt
, pGrammarResult
, false, false);
1891 /*-- 07.08.2008 15:01:25---------------------------------------------------
1893 -----------------------------------------------------------------------*/
1894 void SwEditShell::IgnoreGrammarErrorAt( SwPaM
& rErrorPosition
)
1897 SwWrongList
*pWrong
;
1898 SwNodeIndex aIdx
= rErrorPosition
.Start()->nNode
;
1899 SwNodeIndex aEndIdx
= rErrorPosition
.Start()->nNode
;
1900 xub_StrLen nStart
= rErrorPosition
.Start()->nContent
.GetIndex();
1901 xub_StrLen nEnd
= STRING_LEN
;
1902 while( aIdx
<= aEndIdx
)
1904 pNode
= aIdx
.GetNode().GetTxtNode();
1906 if( aIdx
== aEndIdx
)
1907 nEnd
= rErrorPosition
.End()->nContent
.GetIndex();
1908 pWrong
= pNode
->GetGrammarCheck();
1910 pWrong
->RemoveEntry( nStart
, nEnd
);
1911 pWrong
= pNode
->GetWrong();
1913 pWrong
->RemoveEntry( nStart
, nEnd
);
1914 ::repaintTextFrames( *pNode
);