LCOV - code coverage report
Current view: top level - cui/source/dialogs - SpellDialog.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 0 1037 0.0 %
Date: 2015-06-13 12:38:46 Functions: 0 99 0.0 %
Legend: Lines: hit not hit

          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             : #include <vcl/wrkwin.hxx>
      21             : #include <vcl/menu.hxx>
      22             : #include <vcl/layout.hxx>
      23             : #include <vcl/scrbar.hxx>
      24             : #include <vcl/settings.hxx>
      25             : #include <SpellAttrib.hxx>
      26             : #include <sfx2/dispatch.hxx>
      27             : #include <sfx2/bindings.hxx>
      28             : #include <svl/undo.hxx>
      29             : #include <unotools/lingucfg.hxx>
      30             : #include <vcl/textdata.hxx>
      31             : #include <vcl/graphicfilter.hxx>
      32             : #include <editeng/unolingu.hxx>
      33             : #include <editeng/splwrap.hxx>
      34             : #include <linguistic/lngprops.hxx>
      35             : #include <linguistic/misc.hxx>
      36             : #include <comphelper/processfactory.hxx>
      37             : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
      38             : #include <com/sun/star/lang/XServiceInfo.hpp>
      39             : #include <com/sun/star/lang/XServiceDisplayName.hpp>
      40             : #include <com/sun/star/linguistic2/SpellFailure.hpp>
      41             : #include <com/sun/star/frame/XStorable.hpp>
      42             : #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
      43             : #include <com/sun/star/system/SystemShellExecute.hpp>
      44             : #include <sfx2/app.hxx>
      45             : #include <vcl/help.hxx>
      46             : #include <vcl/graph.hxx>
      47             : #include <vcl/builderfactory.hxx>
      48             : #include <osl/file.hxx>
      49             : #include <cuires.hrc>
      50             : #include <editeng/optitems.hxx>
      51             : #include <editeng/svxenum.hxx>
      52             : #include <svx/SpellDialogChildWindow.hxx>
      53             : #include "SpellDialog.hxx"
      54             : #include <svx/dlgutil.hxx>
      55             : #include "optlingu.hxx"
      56             : #include <dialmgr.hxx>
      57             : #include <svx/svxerr.hxx>
      58             : #include "treeopt.hxx"
      59             : #include <svtools/langtab.hxx>
      60             : #include <comphelper/anytostring.hxx>
      61             : #include <cppuhelper/exc_hlp.hxx>
      62             : #include <boost/scoped_ptr.hpp>
      63             : 
      64             : using namespace ::com::sun::star;
      65             : using namespace ::com::sun::star::uno;
      66             : using namespace ::com::sun::star::beans;
      67             : using namespace ::com::sun::star::linguistic2;
      68             : using namespace linguistic;
      69             : 
      70             : 
      71             : // struct SpellDialog_Impl ---------------------------------------------
      72             : 
      73           0 : struct SpellDialog_Impl
      74             : {
      75             :     Sequence< Reference< XDictionary >  >   aDics;
      76             : };
      77             : 
      78             : 
      79             : #define SPELLUNDO_START                     200
      80             : 
      81             : #define SPELLUNDO_CHANGE_LANGUAGE           (SPELLUNDO_START + 1)
      82             : #define SPELLUNDO_CHANGE_TEXTENGINE         (SPELLUNDO_START + 2)
      83             : #define SPELLUNDO_CHANGE_NEXTERROR          (SPELLUNDO_START + 3)
      84             : #define SPELLUNDO_CHANGE_ADD_TO_DICTIONARY  (SPELLUNDO_START + 4)
      85             : #define SPELLUNDO_CHANGE_GROUP              (SPELLUNDO_START + 5) //undo list
      86             : #define SPELLUNDO_MOVE_ERROREND             (SPELLUNDO_START + 6)
      87             : #define SPELLUNDO_UNDO_EDIT_MODE            (SPELLUNDO_START + 7)
      88             : #define SPELLUNDO_ADD_IGNORE_RULE           (SPELLUNDO_START + 8)
      89             : 
      90             : namespace svx{
      91             : class SpellUndoAction_Impl : public SfxUndoAction
      92             : {
      93             :     sal_uInt16          m_nId;
      94             :     const Link<>&   m_rActionLink;
      95             :     //undo of button enabling
      96             :     bool            m_bEnableChangePB;
      97             :     bool            m_bEnableChangeAllPB;
      98             :     //undo of MarkNextError - used in change and change all, ignore and ignore all
      99             :     long            m_nNewErrorStart;
     100             :     long            m_nNewErrorEnd;
     101             :     long            m_nOldErrorStart;
     102             :     long            m_nOldErrorEnd;
     103             :     bool            m_bIsErrorLanguageSelected;
     104             :     //undo of AddToDictionary
     105             :     Reference<XDictionary>  m_xDictionary;
     106             :     OUString                m_sAddedWord;
     107             :     //move end of error - ::ChangeMarkedWord()
     108             :     long            m_nOffset;
     109             : 
     110             : public:
     111           0 :     SpellUndoAction_Impl(sal_uInt16 nId, const Link<>& rActionLink) :
     112             :         m_nId(nId),
     113             :         m_rActionLink( rActionLink),
     114             :         m_bEnableChangePB(false),
     115             :         m_bEnableChangeAllPB(false),
     116             :         m_nNewErrorStart(-1),
     117             :         m_nNewErrorEnd(-1),
     118             :         m_nOldErrorStart(-1),
     119             :         m_nOldErrorEnd(-1),
     120             :         m_bIsErrorLanguageSelected(false),
     121           0 :         m_nOffset(0)
     122           0 :         {}
     123             : 
     124             :     virtual ~SpellUndoAction_Impl();
     125             : 
     126             :     virtual void            Undo() SAL_OVERRIDE;
     127             :     virtual sal_uInt16          GetId() const SAL_OVERRIDE;
     128             : 
     129           0 :     void                    SetEnableChangePB(){m_bEnableChangePB = true;}
     130           0 :     bool                    IsEnableChangePB(){return m_bEnableChangePB;}
     131             : 
     132           0 :     void                    SetEnableChangeAllPB(){m_bEnableChangeAllPB = true;}
     133           0 :     bool                    IsEnableChangeAllPB(){return m_bEnableChangeAllPB;}
     134             : 
     135           0 :     void                    SetErrorMove(long nNewStart, long nNewEnd, long nOldStart, long nOldEnd)
     136             :                                 {
     137           0 :                                         m_nNewErrorStart = nNewStart;
     138           0 :                                         m_nNewErrorEnd  = nNewEnd;
     139           0 :                                         m_nOldErrorStart = nOldStart;
     140           0 :                                         m_nOldErrorEnd = nOldEnd;
     141           0 :                                 }
     142           0 :     long                    GetOldErrorStart() { return m_nOldErrorStart;}
     143           0 :     long                    GetOldErrorEnd() { return m_nOldErrorEnd;}
     144             : 
     145           0 :     void                    SetErrorLanguageSelected(bool bSet){ m_bIsErrorLanguageSelected = bSet;}
     146           0 :     bool                    IsErrorLanguageSelected() const {return m_bIsErrorLanguageSelected;}
     147             : 
     148           0 :     void                    SetDictionary(Reference<XDictionary> xDict) { m_xDictionary = xDict; }
     149           0 :     Reference<XDictionary>  GetDictionary() const {return m_xDictionary;}
     150           0 :     void                    SetAddedWord(const OUString& rWord) {m_sAddedWord = rWord;}
     151           0 :     const OUString&         GetAddedWord() const { return m_sAddedWord;}
     152             : 
     153           0 :     void                    SetOffset(long nSet) {m_nOffset = nSet;}
     154           0 :     long                    GetOffset() const {return m_nOffset;}
     155             : };
     156             : }//namespace svx
     157             : using namespace ::svx;
     158             : 
     159             : 
     160           0 : SpellUndoAction_Impl::~SpellUndoAction_Impl()
     161             : {
     162           0 : }
     163             : 
     164             : 
     165           0 : void SpellUndoAction_Impl::Undo()
     166             : {
     167           0 :     m_rActionLink.Call(this);
     168           0 : }
     169             : 
     170             : 
     171           0 : sal_uInt16 SpellUndoAction_Impl::GetId()const
     172             : {
     173           0 :     return m_nId;
     174             : }
     175             : 
     176             : // class SvxSpellCheckDialog ---------------------------------------------
     177             : 
     178           0 : SpellDialog::SpellDialog(SpellDialogChildWindow* pChildWindow,
     179             :     vcl::Window * pParent, SfxBindings* _pBindings)
     180             :     : SfxModelessDialog (_pBindings, pChildWindow,
     181             :         pParent, "SpellingDialog", "cui/ui/spellingdialog.ui")
     182             :     , aDialogUndoLink(LINK (this, SpellDialog, DialogUndoHdl))
     183             :     , bModified(false)
     184             :     , bFocusLocked(true)
     185           0 :     , rParent(*pChildWindow)
     186             : {
     187           0 :     m_sTitleSpellingGrammar = GetText();
     188           0 :     m_sTitleSpelling = get<FixedText>("alttitleft")->GetText();
     189             : 
     190             :     // fdo#68794 set initial title for cases where no text has been processed
     191             :     // yet to show its language attributes
     192           0 :     OUString sTitle = rParent.HasGrammarChecking() ? m_sTitleSpellingGrammar : m_sTitleSpelling;
     193           0 :     SetText(sTitle.replaceFirst("$LANGUAGE ($LOCATION)", ""));
     194             : 
     195           0 :     m_sResumeST = get<FixedText>("resumeft")->GetText();
     196           0 :     m_sNoSuggestionsST = get<FixedText>("nosuggestionsft")->GetText();
     197             : 
     198           0 :     get(m_pLanguageFT, "languageft");
     199           0 :     get(m_pLanguageLB, "languagelb");
     200           0 :     get(m_pExplainFT, "explain");
     201           0 :     get(m_pExplainLink, "explainlink");
     202           0 :     get(m_pNotInDictFT, "notindictft");
     203           0 :     get(m_pSentenceED, "sentence");
     204           0 :     Size aEdSize(LogicToPixel(Size(197, 48), MAP_APPFONT));
     205           0 :     m_pSentenceED->set_width_request(aEdSize.Width());
     206           0 :     m_pSentenceED->set_height_request(aEdSize.Height());
     207           0 :     get(m_pSuggestionFT, "suggestionsft");
     208           0 :     get(m_pSuggestionLB, "suggestionslb");
     209           0 :     m_pSuggestionLB->SetDropDownLineCount(5);
     210           0 :     m_pSuggestionLB->set_width_request(aEdSize.Width());
     211           0 :     get(m_pIgnorePB, "ignore");
     212           0 :     m_sIgnoreOnceST = m_pIgnorePB->GetText();
     213           0 :     get(m_pIgnoreAllPB, "ignoreall");
     214           0 :     get(m_pIgnoreRulePB, "ignorerule");
     215           0 :     get(m_pAddToDictPB, "add");
     216           0 :     get(m_pAddToDictMB, "addmb");
     217           0 :     m_pAddToDictMB->SetHelpId(m_pAddToDictPB->GetHelpId());
     218           0 :     get(m_pChangePB, "change");
     219           0 :     get(m_pChangeAllPB, "changeall");
     220           0 :     get(m_pAutoCorrPB, "autocorrect");
     221           0 :     get(m_pCheckGrammarCB, "checkgrammar");
     222           0 :     get(m_pOptionsPB, "options");
     223           0 :     get(m_pUndoPB, "undo");
     224           0 :     get(m_pClosePB, "close");
     225           0 :     xSpell = LinguMgr::GetSpellChecker();
     226           0 :     pImpl = new SpellDialog_Impl;
     227             : 
     228           0 :     const StyleSettings& rSettings = GetSettings().GetStyleSettings();
     229           0 :     Color aCol = rSettings.GetHelpColor();
     230           0 :     Wallpaper aWall( aCol );
     231           0 :     m_pExplainLink->SetBackground( aWall );
     232           0 :     m_pExplainFT->SetBackground( aWall );
     233             : 
     234           0 :     Init_Impl();
     235             : 
     236             :     // disable controls if service is missing
     237           0 :     Enable(xSpell.is());
     238             : 
     239             :     //InitHdl wants to use virtual methods, so it
     240             :     //can't be called during the ctor, so init
     241             :     //it on next event cycle post-ctor
     242             :     Application::PostUserEvent(
     243           0 :         LINK( this, SpellDialog, InitHdl ), NULL, true );
     244           0 : }
     245             : 
     246             : 
     247             : 
     248           0 : SpellDialog::~SpellDialog()
     249             : {
     250           0 :     disposeOnce();
     251           0 : }
     252             : 
     253           0 : void SpellDialog::dispose()
     254             : {
     255           0 :     if (pImpl)
     256             :     {
     257             :         // save possibly modified user-dictionaries
     258           0 :         Reference< XSearchableDictionaryList >  xDicList( SvxGetDictionaryList() );
     259           0 :         if (xDicList.is())
     260           0 :             SaveDictionaries( xDicList );
     261             : 
     262           0 :         delete pImpl;
     263           0 :         pImpl = NULL;
     264             :     }
     265           0 :     m_pLanguageFT.clear();
     266           0 :     m_pLanguageLB.clear();
     267           0 :     m_pExplainFT.clear();
     268           0 :     m_pExplainLink.clear();
     269           0 :     m_pNotInDictFT.clear();
     270           0 :     m_pSentenceED.clear();
     271           0 :     m_pSuggestionFT.clear();
     272           0 :     m_pSuggestionLB.clear();
     273           0 :     m_pIgnorePB.clear();
     274           0 :     m_pIgnoreAllPB.clear();
     275           0 :     m_pIgnoreRulePB.clear();
     276           0 :     m_pAddToDictPB.clear();
     277           0 :     m_pAddToDictMB.clear();
     278           0 :     m_pChangePB.clear();
     279           0 :     m_pChangeAllPB.clear();
     280           0 :     m_pAutoCorrPB.clear();
     281           0 :     m_pCheckGrammarCB.clear();
     282           0 :     m_pOptionsPB.clear();
     283           0 :     m_pUndoPB.clear();
     284           0 :     m_pClosePB.clear();
     285           0 :     SfxModelessDialog::dispose();
     286           0 : }
     287             : 
     288           0 : void SpellDialog::Init_Impl()
     289             : {
     290             :     // initialize handler
     291           0 :     m_pClosePB->SetClickHdl(LINK( this, SpellDialog, CancelHdl ) );
     292           0 :     m_pChangePB->SetClickHdl(LINK( this, SpellDialog, ChangeHdl ) );
     293           0 :     m_pChangeAllPB->SetClickHdl(LINK( this, SpellDialog, ChangeAllHdl ) );
     294           0 :     m_pIgnorePB->SetClickHdl(LINK( this, SpellDialog, IgnoreHdl ) );
     295           0 :     m_pIgnoreAllPB->SetClickHdl(LINK( this, SpellDialog, IgnoreAllHdl ) );
     296           0 :     m_pIgnoreRulePB->SetClickHdl(LINK( this, SpellDialog, IgnoreAllHdl ) );
     297           0 :     m_pUndoPB->SetClickHdl(LINK( this, SpellDialog, UndoHdl ) );
     298             : 
     299           0 :     m_pAutoCorrPB->SetClickHdl( LINK( this, SpellDialog, ExtClickHdl ) );
     300           0 :     m_pCheckGrammarCB->SetClickHdl( LINK( this, SpellDialog, CheckGrammarHdl ));
     301           0 :     m_pOptionsPB->SetClickHdl( LINK( this, SpellDialog, ExtClickHdl ) );
     302             : 
     303           0 :     m_pSuggestionLB->SetDoubleClickHdl( LINK( this, SpellDialog, ChangeHdl ) );
     304             : 
     305           0 :     m_pSentenceED->SetModifyHdl(LINK ( this, SpellDialog, ModifyHdl) );
     306             : 
     307           0 :     m_pAddToDictMB->SetSelectHdl(LINK ( this, SpellDialog, AddToDictSelectHdl ) );
     308           0 :     m_pAddToDictPB->SetClickHdl(LINK ( this, SpellDialog, AddToDictClickHdl ) );
     309             : 
     310           0 :     m_pLanguageLB->SetSelectHdl(LINK( this, SpellDialog, LanguageSelectHdl ) );
     311             : 
     312           0 :     m_pExplainLink->SetClickHdl( LINK( this, SpellDialog, HandleHyperlink ) );
     313             : 
     314             :     // initialize language ListBox
     315           0 :     m_pLanguageLB->SetLanguageList( SvxLanguageListFlags::SPELL_USED, false, false, true );
     316             : 
     317           0 :     m_pSentenceED->ClearModifyFlag();
     318           0 :     SvxGetChangeAllList()->clear();
     319           0 : }
     320             : 
     321             : 
     322             : 
     323           0 : void SpellDialog::UpdateBoxes_Impl()
     324             : {
     325             :     sal_Int32 i;
     326           0 :     m_pSuggestionLB->Clear();
     327             : 
     328           0 :     const SpellErrorDescription* pSpellErrorDescription = m_pSentenceED->GetAlternatives();
     329             : 
     330           0 :     LanguageType nAltLanguage = LANGUAGE_NONE;
     331           0 :     Sequence< OUString > aNewWords;
     332           0 :     bool bIsGrammarError = false;
     333           0 :     if( pSpellErrorDescription )
     334             :     {
     335           0 :         nAltLanguage    = LanguageTag::convertToLanguageType( pSpellErrorDescription->aLocale );
     336           0 :         aNewWords       = pSpellErrorDescription->aSuggestions;
     337           0 :         bIsGrammarError = pSpellErrorDescription->bIsGrammarError;
     338           0 :         m_pExplainLink->SetURL( pSpellErrorDescription->sExplanationURL );
     339           0 :         m_pExplainFT->SetText( pSpellErrorDescription->sExplanation );
     340             :     }
     341           0 :     if( pSpellErrorDescription && !pSpellErrorDescription->sDialogTitle.isEmpty() )
     342             :     {
     343             :         // use this function to apply the correct image to be used...
     344           0 :         SetTitle_Impl( nAltLanguage );
     345             :         // then change the title to the one to be actually used
     346           0 :         SetText( pSpellErrorDescription->sDialogTitle );
     347             :     }
     348             :     else
     349           0 :         SetTitle_Impl( nAltLanguage );
     350           0 :     SetSelectedLang_Impl( nAltLanguage );
     351           0 :     int nDicts = InitUserDicts();
     352             : 
     353             :     // enter alternatives
     354           0 :     const OUString *pNewWords = aNewWords.getConstArray();
     355           0 :     const sal_Int32 nSize = aNewWords.getLength();
     356           0 :     for ( i = 0; i < nSize; ++i )
     357             :     {
     358           0 :         OUString aTmp( pNewWords[i] );
     359           0 :         if ( LISTBOX_ENTRY_NOTFOUND == m_pSuggestionLB->GetEntryPos( aTmp ) )
     360             :         {
     361           0 :             m_pSuggestionLB->InsertEntry( aTmp );
     362           0 :             m_pSuggestionLB->SetEntryFlags(m_pSuggestionLB->GetEntryCount() - 1, ListBoxEntryFlags::MultiLine);
     363             :         }
     364           0 :     }
     365           0 :     if(!nSize)
     366           0 :         m_pSuggestionLB->InsertEntry(m_sNoSuggestionsST);
     367           0 :     m_pAutoCorrPB->Enable( nSize > 0 );
     368             : 
     369           0 :     m_pSuggestionFT->Enable(nSize > 0);
     370           0 :     m_pSuggestionLB->Enable(nSize > 0);
     371           0 :     if( nSize )
     372             :     {
     373           0 :         m_pSuggestionLB->SelectEntryPos(0);
     374             :     }
     375           0 :     m_pChangePB->Enable( nSize > 0);
     376           0 :     m_pChangeAllPB->Enable(nSize > 0);
     377           0 :     bool bShowChangeAll = !bIsGrammarError;
     378           0 :     m_pChangeAllPB->Show( bShowChangeAll );
     379           0 :     m_pExplainFT->Show( !bShowChangeAll );
     380           0 :     m_pLanguageLB->Enable( bShowChangeAll );
     381           0 :     m_pIgnoreAllPB->Show( bShowChangeAll );
     382             : 
     383           0 :     m_pAddToDictMB->Show( bShowChangeAll && nDicts > 1);
     384           0 :     m_pAddToDictPB->Show( bShowChangeAll && nDicts <= 1);
     385           0 :     m_pIgnoreRulePB->Show( !bShowChangeAll );
     386           0 :     m_pIgnoreRulePB->Enable(pSpellErrorDescription && !pSpellErrorDescription->sRuleId.isEmpty());
     387           0 :     m_pAutoCorrPB->Show( bShowChangeAll && rParent.HasAutoCorrection() );
     388             : 
     389           0 :     bool bOldShowGrammar = m_pCheckGrammarCB->IsVisible();
     390           0 :     bool bOldShowExplain = m_pExplainLink->IsVisible();
     391             : 
     392           0 :     m_pCheckGrammarCB->Show(rParent.HasGrammarChecking());
     393           0 :     m_pExplainLink->Show(!m_pExplainLink->GetURL().isEmpty());
     394           0 :     if (m_pExplainFT->GetText().isEmpty())
     395             :     {
     396           0 :         m_pExplainFT->Hide();
     397           0 :         m_pExplainLink->Hide();
     398             :     }
     399             : 
     400           0 :     if (bOldShowExplain != (bool) m_pExplainLink->IsVisible() || bOldShowGrammar != (bool) m_pCheckGrammarCB->IsVisible())
     401           0 :         setOptimalLayoutSize();
     402           0 : }
     403             : 
     404             : 
     405           0 : void SpellDialog::SpellContinue_Impl(bool bUseSavedSentence, bool bIgnoreCurrentError )
     406             : {
     407             :     //initially or after the last error of a sentence MarkNextError will fail
     408             :     //then GetNextSentence() has to be called followed again by MarkNextError()
     409             :     //MarkNextError is not initially called if the UndoEdit mode is active
     410           0 :     bool bNextSentence = false;
     411           0 :     if((!m_pSentenceED->IsUndoEditMode() && m_pSentenceED->MarkNextError( bIgnoreCurrentError, xSpell )) ||
     412           0 :             ( bNextSentence = GetNextSentence_Impl(bUseSavedSentence, m_pSentenceED->IsUndoEditMode()) && m_pSentenceED->MarkNextError( false, xSpell )))
     413             :     {
     414           0 :         const SpellErrorDescription* pSpellErrorDescription = m_pSentenceED->GetAlternatives();
     415           0 :         if( pSpellErrorDescription )
     416             :         {
     417           0 :             UpdateBoxes_Impl();
     418             :             Control* aControls[] =
     419             :             {
     420             :                 m_pNotInDictFT,
     421             :                 m_pSentenceED,
     422             :                 m_pLanguageFT,
     423             :                 0
     424           0 :             };
     425           0 :             sal_Int32 nIdx = 0;
     426           0 :             do
     427             :             {
     428           0 :                 aControls[nIdx]->Enable(true);
     429             :             }
     430           0 :             while(aControls[++nIdx]);
     431             : 
     432             :         }
     433           0 :         if( bNextSentence )
     434             :         {
     435             :             //remove undo if a new sentence is active
     436           0 :             m_pSentenceED->ResetUndo();
     437           0 :             m_pUndoPB->Enable(false);
     438             :         }
     439             :     }
     440           0 : }
     441             : /* Initialize, asynchronous to prevent virtial calls
     442             :    from a constructor
     443             :  */
     444           0 : IMPL_LINK( SpellDialog, InitHdl, SpellDialog *, )
     445             : {
     446           0 :     SetUpdateMode( false );
     447             :     //show or hide AutoCorrect depending on the modules abilities
     448           0 :     m_pAutoCorrPB->Show(rParent.HasAutoCorrection());
     449           0 :     SpellContinue_Impl();
     450           0 :     m_pSentenceED->ResetUndo();
     451           0 :     m_pUndoPB->Enable(false);
     452             : 
     453             :     // get current language
     454           0 :     UpdateBoxes_Impl();
     455             : 
     456             :     // fill dictionary PopupMenu
     457           0 :     InitUserDicts();
     458             : 
     459           0 :     LockFocusChanges(true);
     460           0 :     if( m_pChangePB->IsEnabled() )
     461           0 :         m_pChangePB->GrabFocus();
     462           0 :     else if( m_pIgnorePB->IsEnabled() )
     463           0 :         m_pIgnorePB->GrabFocus();
     464           0 :     else if( m_pClosePB->IsEnabled() )
     465           0 :         m_pClosePB->GrabFocus();
     466           0 :     LockFocusChanges(false);
     467             :     //show grammar CheckBox depending on the modules abilities
     468           0 :     m_pCheckGrammarCB->Check( rParent.IsGrammarChecking() );
     469           0 :     SetUpdateMode( true );
     470           0 :     Show();
     471           0 :     return 0;
     472             : };
     473             : 
     474             : 
     475             : 
     476           0 : IMPL_LINK( SpellDialog, ExtClickHdl, Button *, pBtn )
     477             : {
     478           0 :     if (m_pOptionsPB == pBtn)
     479           0 :         StartSpellOptDlg_Impl();
     480           0 :     else if (m_pAutoCorrPB == pBtn)
     481             :     {
     482             :         //get the currently selected wrong word
     483           0 :         OUString sCurrentErrorText = m_pSentenceED->GetErrorText();
     484             :         //get the wrong word from the XSpellAlternative
     485           0 :         const SpellErrorDescription* pSpellErrorDescription = m_pSentenceED->GetAlternatives();
     486           0 :         if( pSpellErrorDescription )
     487             :         {
     488           0 :             OUString sWrong(pSpellErrorDescription->sErrorText);
     489             :             //if the word has not been edited in the MultiLineEdit then
     490             :             //the current suggestion should be used
     491             :             //if it's not the 'no suggestions' entry
     492           0 :             if(sWrong == sCurrentErrorText &&
     493           0 :                     m_pSuggestionLB->IsEnabled() && m_pSuggestionLB->GetSelectEntryCount() > 0 &&
     494           0 :                     !m_sNoSuggestionsST.equals(m_pSuggestionLB->GetSelectEntry()))
     495             :             {
     496           0 :                 sCurrentErrorText = m_pSuggestionLB->GetSelectEntry();
     497             :             }
     498           0 :             if(sWrong != sCurrentErrorText)
     499             :             {
     500           0 :                 SvxPrepareAutoCorrect( sWrong, sCurrentErrorText );
     501           0 :                 LanguageType eLang = GetSelectedLang_Impl();
     502           0 :                 rParent.AddAutoCorrection( sWrong, sCurrentErrorText, eLang );
     503           0 :             }
     504           0 :         }
     505             :     }
     506           0 :     return 0;
     507             : }
     508             : 
     509           0 : IMPL_LINK( SpellDialog, CheckGrammarHdl, CheckBox*, pBox )
     510             : {
     511           0 :     rParent.SetGrammarChecking( pBox->IsChecked() );
     512           0 :     Impl_Restore();
     513           0 :     return 0;
     514             : }
     515             : 
     516           0 : void SpellDialog::StartSpellOptDlg_Impl()
     517             : {
     518             :     sal_uInt16 aSpellInfos[] =
     519             :     {
     520             :         SID_ATTR_SPELL,SID_ATTR_SPELL,
     521             :         SID_SPELL_MODIFIED, SID_SPELL_MODIFIED,
     522             :         SID_AUTOSPELL_CHECK, SID_AUTOSPELL_CHECK,
     523             :         0
     524           0 :     };
     525           0 :     SfxItemSet aSet( SfxGetpApp()->GetPool(), aSpellInfos);
     526           0 :     aSet.Put(SfxSpellCheckItem( xSpell, SID_ATTR_SPELL ));
     527             :     VclPtr<SfxSingleTabDialog> pDlg(
     528           0 :         VclPtr<SfxSingleTabDialog>::Create(this, aSet, "SpellOptionsDialog", "cui/ui/spelloptionsdialog.ui"));
     529           0 :     VclPtr<SfxTabPage> pPage = SvxLinguTabPage::Create( pDlg->get_content_area(), &aSet );
     530           0 :     static_cast<SvxLinguTabPage*>(pPage.get())->HideGroups( GROUP_MODULES );
     531           0 :     pDlg->SetTabPage( pPage );
     532           0 :     if(RET_OK == pDlg->Execute())
     533             :     {
     534           0 :         InitUserDicts();
     535           0 :         const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
     536           0 :         if(pOutSet)
     537           0 :             OfaTreeOptionsDialog::ApplyLanguageOptions(*pOutSet);
     538           0 :     }
     539           0 : }
     540             : 
     541             : namespace
     542             : {
     543           0 :     OUString getDotReplacementString(const OUString &rErrorText, const OUString &rSuggestedReplacement)
     544             :     {
     545           0 :         OUString aString = rErrorText;
     546             : 
     547             :         //dots are sometimes part of the spelled word but they are not necessarily part of the replacement
     548           0 :         bool bDot = aString.endsWith(".");
     549             : 
     550           0 :         aString = rSuggestedReplacement;
     551             : 
     552           0 :         if(bDot && (aString.isEmpty() || !aString.endsWith(".")))
     553           0 :             aString += ".";
     554             : 
     555           0 :         return aString;
     556             :     }
     557             : }
     558             : 
     559             : 
     560           0 : OUString SpellDialog::getReplacementString() const
     561             : {
     562           0 :     OUString sOrigString = m_pSentenceED->GetErrorText();
     563             : 
     564           0 :     OUString sReplacement(sOrigString);
     565             : 
     566           0 :     if(m_pSuggestionLB->IsEnabled() &&
     567           0 :             m_pSuggestionLB->GetSelectEntryCount()>0 &&
     568           0 :             !m_sNoSuggestionsST.equals(m_pSuggestionLB->GetSelectEntry()))
     569           0 :         sReplacement = m_pSuggestionLB->GetSelectEntry();
     570             : 
     571           0 :     return getDotReplacementString(sOrigString, sReplacement);
     572             : }
     573             : 
     574             : 
     575             : 
     576           0 : IMPL_LINK_NOARG(SpellDialog, ChangeHdl)
     577             : {
     578           0 :     if(m_pSentenceED->IsUndoEditMode())
     579             :     {
     580           0 :         SpellContinue_Impl();
     581             :     }
     582             :     else
     583             :     {
     584           0 :         m_pSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
     585           0 :         OUString aString = getReplacementString();
     586           0 :         m_pSentenceED->ChangeMarkedWord(aString, GetSelectedLang_Impl());
     587           0 :         SpellContinue_Impl();
     588           0 :         bModified = false;
     589           0 :         m_pSentenceED->UndoActionEnd();
     590             :     }
     591           0 :     if(!m_pChangePB->IsEnabled())
     592           0 :         m_pIgnorePB->GrabFocus();
     593           0 :     return 1;
     594             : }
     595             : 
     596             : 
     597             : 
     598           0 : IMPL_LINK_NOARG(SpellDialog, ChangeAllHdl)
     599             : {
     600           0 :     m_pSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
     601           0 :     OUString aString = getReplacementString();
     602           0 :     LanguageType eLang = GetSelectedLang_Impl();
     603             : 
     604             :     // add new word to ChangeAll list
     605           0 :     OUString  aOldWord( m_pSentenceED->GetErrorText() );
     606           0 :     SvxPrepareAutoCorrect( aOldWord, aString );
     607           0 :     Reference<XDictionary> aXDictionary( SvxGetChangeAllList(), UNO_QUERY );
     608             :     DictionaryError nAdded = AddEntryToDic( aXDictionary,
     609             :             aOldWord, true,
     610           0 :             aString, eLang );
     611             : 
     612           0 :     if(nAdded == DictionaryError::NONE)
     613             :     {
     614             :         SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
     615           0 :                         SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink);
     616           0 :         pAction->SetDictionary(aXDictionary);
     617           0 :         pAction->SetAddedWord(aOldWord);
     618           0 :         m_pSentenceED->AddUndoAction(pAction);
     619             :     }
     620             : 
     621           0 :     m_pSentenceED->ChangeMarkedWord(aString, eLang);
     622           0 :     SpellContinue_Impl();
     623           0 :     bModified = false;
     624           0 :     m_pSentenceED->UndoActionEnd();
     625           0 :     return 1;
     626             : }
     627             : 
     628             : 
     629           0 : IMPL_LINK( SpellDialog, IgnoreAllHdl, Button *, pButton )
     630             : {
     631           0 :     m_pSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
     632             :     // add word to IgnoreAll list
     633           0 :     Reference< XDictionary > aXDictionary( SvxGetIgnoreAllList(), UNO_QUERY );
     634             :     //in case the error has been changed manually it has to be restored
     635           0 :     m_pSentenceED->RestoreCurrentError();
     636           0 :     if (pButton == m_pIgnoreRulePB)
     637             :     {
     638           0 :         const SpellErrorDescription* pSpellErrorDescription = m_pSentenceED->GetAlternatives();
     639             :         try
     640             :         {
     641           0 :             if( pSpellErrorDescription && pSpellErrorDescription->xGrammarChecker.is() )
     642             :             {
     643           0 :                 pSpellErrorDescription->xGrammarChecker->ignoreRule( pSpellErrorDescription->sRuleId,
     644           0 :                     pSpellErrorDescription->aLocale );
     645             :                 // refresh the layout (workaround to launch a dictionary event)
     646           0 :                 aXDictionary->setActive(sal_False);
     647           0 :                 aXDictionary->setActive(sal_True);
     648             :             }
     649             :         }
     650           0 :         catch( const uno::Exception& )
     651             :         {
     652             :         }
     653             :     }
     654             :     else
     655             :     {
     656           0 :         OUString sErrorText(m_pSentenceED->GetErrorText());
     657             :         DictionaryError nAdded = AddEntryToDic( aXDictionary,
     658             :             sErrorText, false,
     659           0 :             OUString(), LANGUAGE_NONE );
     660           0 :         if(nAdded == DictionaryError::NONE)
     661             :         {
     662             :             SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
     663           0 :                             SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink);
     664           0 :             pAction->SetDictionary(aXDictionary);
     665           0 :             pAction->SetAddedWord(sErrorText);
     666           0 :             m_pSentenceED->AddUndoAction(pAction);
     667           0 :         }
     668             :     }
     669             : 
     670           0 :     SpellContinue_Impl();
     671           0 :     bModified = false;
     672           0 :     m_pSentenceED->UndoActionEnd();
     673           0 :     return 1;
     674             : }
     675             : 
     676             : 
     677           0 : IMPL_LINK_NOARG(SpellDialog, UndoHdl)
     678             : {
     679           0 :     m_pSentenceED->Undo();
     680           0 :     if(!m_pSentenceED->GetUndoActionCount())
     681           0 :         m_pUndoPB->Enable(false);
     682           0 :     return 0;
     683             : }
     684             : 
     685             : 
     686           0 : IMPL_LINK( SpellDialog, DialogUndoHdl, SpellUndoAction_Impl*, pAction )
     687             : {
     688           0 :     switch(pAction->GetId())
     689             :     {
     690             :         case SPELLUNDO_CHANGE_TEXTENGINE:
     691             :         {
     692           0 :             if(pAction->IsEnableChangePB())
     693           0 :                 m_pChangePB->Enable(false);
     694           0 :             if(pAction->IsEnableChangeAllPB())
     695           0 :                 m_pChangeAllPB->Enable(false);
     696             :         }
     697           0 :         break;
     698             :         case SPELLUNDO_CHANGE_NEXTERROR:
     699             :         {
     700           0 :             m_pSentenceED->MoveErrorMarkTo((sal_uInt16)pAction->GetOldErrorStart(), (sal_uInt16)pAction->GetOldErrorEnd(), false);
     701           0 :             if(pAction->IsErrorLanguageSelected())
     702             :             {
     703           0 :                 UpdateBoxes_Impl();
     704             :             }
     705             :         }
     706           0 :         break;
     707             :         case SPELLUNDO_CHANGE_ADD_TO_DICTIONARY:
     708             :         {
     709           0 :             if(pAction->GetDictionary().is())
     710           0 :                 pAction->GetDictionary()->remove(pAction->GetAddedWord());
     711             :         }
     712           0 :         break;
     713             :         case SPELLUNDO_MOVE_ERROREND :
     714             :         {
     715           0 :             if(pAction->GetOffset() != 0)
     716           0 :                 m_pSentenceED->MoveErrorEnd(pAction->GetOffset());
     717             :         }
     718           0 :         break;
     719             :         case SPELLUNDO_UNDO_EDIT_MODE :
     720             :         {
     721             :             //refill the dialog with the currently spelled sentence - throw away all changes
     722           0 :             SpellContinue_Impl(true);
     723             :         }
     724           0 :         break;
     725             :         case SPELLUNDO_ADD_IGNORE_RULE:
     726             :             //undo of ignored rules is not supported
     727           0 :         break;
     728             :     }
     729             : 
     730           0 :     return 0;
     731             : }
     732             : 
     733           0 : void SpellDialog::Impl_Restore()
     734             : {
     735             :     //clear the "ChangeAllList"
     736           0 :     SvxGetChangeAllList()->clear();
     737             :     //get a new sentence
     738           0 :     m_pSentenceED->SetText(OUString());
     739           0 :     m_pSentenceED->ResetModified();
     740             :     //Resolves: fdo#39348 refill the dialog with the currently spelled sentence
     741           0 :     SpellContinue_Impl(true);
     742           0 :     m_pIgnorePB->SetText(m_sIgnoreOnceST);
     743           0 : }
     744             : 
     745           0 : IMPL_LINK_NOARG(SpellDialog, IgnoreHdl)
     746             : {
     747           0 :     if (m_sResumeST.equals(m_pIgnorePB->GetText()))
     748             :     {
     749           0 :         Impl_Restore();
     750             :     }
     751             :     else
     752             :     {
     753             :         //in case the error has been changed manually it has to be restored,
     754             :         // since the users choice now was to ignore the error
     755           0 :         m_pSentenceED->RestoreCurrentError();
     756             : 
     757             :         // the word is being ignored
     758           0 :         SpellContinue_Impl( false, true );
     759             :     }
     760           0 :     return 1;
     761             : }
     762             : 
     763             : 
     764             : 
     765           0 : bool SpellDialog::Close()
     766             : {
     767             :     // We have to call ToggleChildWindow directly; calling SfxDispatcher's
     768             :     // Execute() does not work here when we are in a document with protected
     769             :     // section - in that case, the cursor can move from the editable field to
     770             :     // the protected area, and the slots get disabled because of
     771             :     // SW_DISABLE_ON_PROTECTED_CURSOR (see FN_SPELL_GRAMMAR_DIALOG in .sdi).
     772           0 :     SfxViewFrame::Current()->ToggleChildWindow(rParent.GetType());
     773             : 
     774           0 :     return true;
     775             : }
     776             : 
     777             : 
     778           0 : void SpellDialog::SetSelectedLang_Impl( LanguageType nLang )
     779             : {
     780           0 :     m_pLanguageLB->SelectLanguage( nLang );
     781           0 : }
     782             : 
     783             : 
     784             : 
     785           0 : LanguageType SpellDialog::GetSelectedLang_Impl() const
     786             : {
     787           0 :     sal_Int16 nLang = m_pLanguageLB->GetSelectLanguage();
     788           0 :     return nLang;
     789             : }
     790             : 
     791             : 
     792           0 : IMPL_LINK(SpellDialog, LanguageSelectHdl, SvxLanguageBox*, pBox)
     793             : {
     794             :     //If selected language changes, then add->list should be regenerated to
     795             :     //match
     796           0 :     InitUserDicts();
     797             : 
     798             :     //if currently an error is selected then search for alternatives for
     799             :     //this word and fill the alternatives ListBox accordingly
     800           0 :     OUString sError = m_pSentenceED->GetErrorText();
     801           0 :     m_pSuggestionLB->Clear();
     802           0 :     if(!sError.isEmpty())
     803             :     {
     804           0 :         LanguageType eLanguage = pBox->GetSelectLanguage();
     805           0 :         Reference <XSpellAlternatives> xAlt = xSpell->spell( sError, eLanguage,
     806           0 :                                             Sequence< PropertyValue >() );
     807           0 :         if( xAlt.is() )
     808           0 :             m_pSentenceED->SetAlternatives( xAlt );
     809             :         else
     810             :         {
     811           0 :             m_pSentenceED->ChangeMarkedWord( sError, eLanguage );
     812           0 :             SpellContinue_Impl();
     813             :         }
     814             : 
     815           0 :          m_pSentenceED->AddUndoAction(new SpellUndoAction_Impl(SPELLUNDO_CHANGE_LANGUAGE, aDialogUndoLink));
     816             :     }
     817           0 :     SpellDialog::UpdateBoxes_Impl();
     818           0 :     return 0;
     819             : }
     820             : 
     821             : 
     822           0 : void SpellDialog::SetLanguage( sal_uInt16 nLang )
     823             : /*
     824             :     Description:
     825             :     If the language has been changed in thesaurus,
     826             :     it must be changed here, too.
     827             : */
     828             : {
     829           0 :     SetTitle_Impl( nLang );
     830           0 :     m_pLanguageLB->SelectLanguage( nLang );
     831           0 : }
     832             : 
     833           0 : void SpellDialog::SetTitle_Impl(LanguageType nLang)
     834             : {
     835           0 :     OUString sTitle = rParent.HasGrammarChecking() ? m_sTitleSpellingGrammar : m_sTitleSpelling;
     836           0 :     sTitle = sTitle.replaceFirst( "$LANGUAGE ($LOCATION)", SvtLanguageTable::GetLanguageString(nLang) );
     837           0 :     SetText( sTitle );
     838           0 : }
     839             : 
     840           0 : int SpellDialog::InitUserDicts()
     841             : {
     842           0 :     const LanguageType nLang = m_pLanguageLB->GetSelectLanguage();
     843             : 
     844           0 :     const Reference< XDictionary >  *pDic = 0;
     845             : 
     846             :     // get list of dictionaries
     847           0 :     Reference< XSearchableDictionaryList >  xDicList( SvxGetDictionaryList() );
     848           0 :     if (xDicList.is())
     849             :     {
     850             :         // add active, positive dictionary to dic-list (if not already done).
     851             :         // This is to ensure that there is at least on dictionary to which
     852             :         // words could be added.
     853           0 :         Reference< XDictionary >  xDic( SvxGetOrCreatePosDic( xDicList ) );
     854           0 :         if (xDic.is())
     855           0 :             xDic->setActive( sal_True );
     856             : 
     857           0 :         pImpl->aDics = xDicList->getDictionaries();
     858             :     }
     859             : 
     860           0 :     SvtLinguConfig aCfg;
     861             : 
     862             :     // list suitable dictionaries
     863           0 :     bool bEnable = false;
     864           0 :     const sal_Int32 nSize = pImpl->aDics.getLength();
     865           0 :     pDic = pImpl->aDics.getConstArray();
     866           0 :     PopupMenu* pMenu = m_pAddToDictMB->GetPopupMenu();
     867             :     assert(pMenu);
     868           0 :     pMenu->Clear();
     869           0 :     pMenu->SetMenuFlags(MenuFlags::NoAutoMnemonics);
     870           0 :     sal_uInt16 nItemId = 1;     // menu items should be enumerated from 1 and not 0
     871           0 :     for (sal_Int32 i = 0; i < nSize; ++i)
     872             :     {
     873           0 :         uno::Reference< linguistic2::XDictionary >  xDicTmp( pDic[i], uno::UNO_QUERY );
     874           0 :         if (!xDicTmp.is() || SvxGetIgnoreAllList() == xDicTmp)
     875           0 :             continue;
     876             : 
     877           0 :         uno::Reference< frame::XStorable > xStor( xDicTmp, uno::UNO_QUERY );
     878           0 :         LanguageType nActLanguage = LanguageTag( xDicTmp->getLocale() ).getLanguageType();
     879           0 :         if( xDicTmp->isActive()
     880           0 :             &&  xDicTmp->getDictionaryType() != linguistic2::DictionaryType_NEGATIVE
     881           0 :             && (nLang == nActLanguage || LANGUAGE_NONE == nActLanguage )
     882           0 :             && (!xStor.is() || !xStor->isReadonly()) )
     883             :         {
     884           0 :             pMenu->InsertItem( nItemId, xDicTmp->getName() );
     885           0 :             bEnable = true;
     886             : 
     887           0 :             uno::Reference< lang::XServiceInfo > xSvcInfo( xDicTmp, uno::UNO_QUERY );
     888           0 :             if (xSvcInfo.is())
     889             :             {
     890             :                 OUString aDictionaryImageUrl( aCfg.GetSpellAndGrammarContextDictionaryImage(
     891           0 :                         xSvcInfo->getImplementationName()) );
     892           0 :                 if (!aDictionaryImageUrl.isEmpty())
     893             :                 {
     894           0 :                     Image aImage( aDictionaryImageUrl );
     895           0 :                     pMenu->SetItemImage( nItemId, aImage );
     896           0 :                 }
     897             :             }
     898             : 
     899           0 :             ++nItemId;
     900             :         }
     901           0 :     }
     902           0 :     m_pAddToDictMB->Enable( bEnable );
     903           0 :     m_pAddToDictPB->Enable( bEnable );
     904             : 
     905           0 :     int nDicts = nItemId-1;
     906             : 
     907           0 :     m_pAddToDictMB->Show( nDicts > 1 );
     908           0 :     m_pAddToDictPB->Show( nDicts <= 1 );
     909             : 
     910           0 :     return nDicts;
     911             : }
     912             : 
     913             : 
     914           0 : IMPL_LINK(SpellDialog, AddToDictClickHdl, PushButton*, )
     915             : {
     916           0 :     return AddToDictionaryExecute(1, m_pAddToDictMB->GetPopupMenu());
     917             : }
     918             : 
     919             : 
     920           0 : IMPL_LINK_TYPED(SpellDialog, AddToDictSelectHdl, MenuButton*, pButton, void )
     921             : {
     922           0 :     AddToDictionaryExecute(pButton->GetCurItemId(), pButton->GetPopupMenu());
     923           0 : }
     924             : 
     925             : 
     926           0 : int SpellDialog::AddToDictionaryExecute( sal_uInt16 nItemId, PopupMenu *pMenu )
     927             : {
     928           0 :     m_pSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
     929             : 
     930             :     //GetErrorText() returns the current error even if the text is already
     931             :     //manually changed
     932           0 :     const OUString aNewWord = m_pSentenceED->GetErrorText();
     933             : 
     934           0 :     OUString aDicName ( pMenu->GetItemText( nItemId ) );
     935             : 
     936           0 :     uno::Reference< linguistic2::XDictionary >      xDic;
     937           0 :     uno::Reference< linguistic2::XSearchableDictionaryList >  xDicList( SvxGetDictionaryList() );
     938           0 :     if (xDicList.is())
     939           0 :         xDic = xDicList->getDictionaryByName( aDicName );
     940             : 
     941           0 :     DictionaryError nAddRes = DictionaryError::UNKNOWN;
     942           0 :     if (xDic.is())
     943             :     {
     944           0 :         nAddRes = AddEntryToDic( xDic, aNewWord, false, OUString(), LANGUAGE_NONE );
     945             :         // save modified user-dictionary if it is persistent
     946           0 :         uno::Reference< frame::XStorable >  xSavDic( xDic, uno::UNO_QUERY );
     947           0 :         if (xSavDic.is())
     948           0 :             xSavDic->store();
     949             : 
     950           0 :         if (nAddRes == DictionaryError::NONE)
     951             :         {
     952             :             SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
     953           0 :                             SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink);
     954           0 :             pAction->SetDictionary( xDic );
     955           0 :             pAction->SetAddedWord( aNewWord );
     956           0 :             m_pSentenceED->AddUndoAction( pAction );
     957             :         }
     958             :         // failed because there is already an entry?
     959           0 :         if (DictionaryError::NONE != nAddRes && xDic->getEntry( aNewWord ).is())
     960           0 :             nAddRes = DictionaryError::NONE;
     961             :     }
     962           0 :     if (DictionaryError::NONE != nAddRes)
     963             :     {
     964           0 :         SvxDicError( this, nAddRes );
     965           0 :         return 0; // don't continue
     966             :     }
     967             : 
     968             :     // go on
     969           0 :     SpellContinue_Impl();
     970           0 :     m_pSentenceED->UndoActionEnd();
     971           0 :     return 0;
     972             : }
     973             : 
     974             : 
     975           0 : IMPL_LINK(SpellDialog, ModifyHdl, SentenceEditWindow_Impl*, pEd)
     976             : {
     977           0 :     if (m_pSentenceED == pEd)
     978             :     {
     979           0 :         bModified = true;
     980           0 :         m_pSuggestionLB->SetNoSelection();
     981           0 :         m_pSuggestionLB->Disable();
     982           0 :         OUString sNewText( m_pSentenceED->GetText() );
     983           0 :         m_pAutoCorrPB->Enable( sNewText != m_pSentenceED->GetText() );
     984           0 :         SpellUndoAction_Impl* pSpellAction = new SpellUndoAction_Impl(SPELLUNDO_CHANGE_TEXTENGINE, aDialogUndoLink);
     985           0 :         if(!m_pChangeAllPB->IsEnabled())
     986             :         {
     987           0 :             m_pChangeAllPB->Enable();
     988           0 :             pSpellAction->SetEnableChangeAllPB();
     989             :         }
     990           0 :         if(!m_pChangePB->IsEnabled())
     991             :         {
     992           0 :             m_pChangePB->Enable();
     993           0 :             pSpellAction->SetEnableChangePB();
     994             :         }
     995           0 :         m_pSentenceED->AddUndoAction(pSpellAction);
     996             :     }
     997           0 :     return 0;
     998             : };
     999             : 
    1000             : 
    1001           0 : IMPL_LINK_NOARG(SpellDialog, CancelHdl)
    1002             : {
    1003             :     //apply changes and ignored text parts first - if there are any
    1004           0 :     rParent.ApplyChangedSentence(m_pSentenceED->CreateSpellPortions(true), false);
    1005           0 :     Close();
    1006           0 :     return 0;
    1007             : }
    1008             : 
    1009             : 
    1010           0 : bool SpellDialog::Notify( NotifyEvent& rNEvt )
    1011             : {
    1012             :     /* #i38338#
    1013             :     *   FIXME: LoseFocus and GetFocus are signals from vcl that
    1014             :     *   a window actually got/lost the focus, it never should be
    1015             :     *   forwarded from another window, that is simply wrong.
    1016             :     *   FIXME: overriding the virtual methods GetFocus and LoseFocus
    1017             :     *   in SpellDialogChildWindow by making them pure is at least questionable.
    1018             :     *   The only sensible thing would be to call the new Method differently,
    1019             :     *   e.g. DialogGot/LostFocus or so.
    1020             :     */
    1021           0 :     if( IsVisible() && !bFocusLocked )
    1022             :     {
    1023           0 :         if( rNEvt.GetType() ==  MouseNotifyEvent::GETFOCUS )
    1024             :         {
    1025             :             //notify the child window of the focus change
    1026           0 :             rParent.GetFocus();
    1027             :         }
    1028           0 :         else if( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
    1029             :         {
    1030             :             //notify the child window of the focus change
    1031           0 :             rParent.LoseFocus();
    1032             :         }
    1033             :     }
    1034           0 :     return SfxModelessDialog::Notify(rNEvt);
    1035             : }
    1036             : 
    1037             : 
    1038           0 : void SpellDialog::InvalidateDialog()
    1039             : {
    1040           0 :     if( bFocusLocked )
    1041           0 :         return;
    1042           0 :     m_pIgnorePB->SetText(m_sResumeST);
    1043             :     vcl::Window* aDisableArr[] =
    1044             :     {
    1045             :         m_pNotInDictFT,
    1046             :         m_pSentenceED,
    1047             :         m_pSuggestionFT,
    1048             :         m_pSuggestionLB,
    1049             :         m_pLanguageFT,
    1050             :         m_pLanguageLB,
    1051             :         m_pIgnoreAllPB,
    1052             :         m_pIgnoreRulePB,
    1053             :         m_pAddToDictMB,
    1054             :         m_pAddToDictPB,
    1055             :         m_pChangePB,
    1056             :         m_pChangeAllPB,
    1057             :         m_pAutoCorrPB,
    1058             :         m_pUndoPB,
    1059             :         0
    1060           0 :     };
    1061           0 :     sal_Int16 i = 0;
    1062           0 :     while(aDisableArr[i])
    1063             :     {
    1064           0 :         aDisableArr[i]->Enable(false);
    1065           0 :         i++;
    1066             :     }
    1067           0 :     SfxModelessDialog::Deactivate();
    1068             : }
    1069             : 
    1070             : 
    1071           0 : bool SpellDialog::GetNextSentence_Impl(bool bUseSavedSentence, bool bRecheck)
    1072             : {
    1073           0 :     bool bRet = false;
    1074           0 :     if(!bUseSavedSentence)
    1075             :     {
    1076             :         //apply changes and ignored text parts
    1077           0 :         rParent.ApplyChangedSentence(m_pSentenceED->CreateSpellPortions(true), bRecheck);
    1078             :     }
    1079           0 :     m_pSentenceED->ResetIgnoreErrorsAt();
    1080           0 :     m_pSentenceED->ResetModified();
    1081           0 :     SpellPortions aSentence = bUseSavedSentence ? m_aSavedSentence : rParent.GetNextWrongSentence( bRecheck );
    1082           0 :     if(!bUseSavedSentence)
    1083           0 :         m_aSavedSentence = aSentence;
    1084           0 :     bool bHasReplaced = false;
    1085           0 :     while(!aSentence.empty())
    1086             :     {
    1087             :         //apply all changes that are already part of the "ChangeAllList"
    1088             :         //returns true if the list still contains errors after the changes have been applied
    1089             : 
    1090           0 :         if(!ApplyChangeAllList_Impl(aSentence, bHasReplaced))
    1091             :         {
    1092           0 :             rParent.ApplyChangedSentence(aSentence, bRecheck);
    1093           0 :             aSentence = rParent.GetNextWrongSentence( bRecheck );
    1094             :         }
    1095             :         else
    1096           0 :             break;
    1097             :     }
    1098             : 
    1099           0 :     if(!aSentence.empty())
    1100             :     {
    1101           0 :         SpellPortions::iterator aStart = aSentence.begin();
    1102           0 :         OUString sText;
    1103           0 :         while(aStart != aSentence.end())
    1104             :         {
    1105             :             // hidden text has to be ignored
    1106           0 :             if(!aStart->bIsHidden)
    1107           0 :                 sText += aStart->sText;
    1108           0 :             ++aStart;
    1109             :         }
    1110           0 :         m_pSentenceED->SetText(sText);
    1111           0 :         aStart = aSentence.begin();
    1112           0 :         sal_Int32 nStartPosition = 0;
    1113           0 :         sal_Int32 nEndPosition = 0;
    1114             : 
    1115           0 :         while(aStart != aSentence.end())
    1116             :         {
    1117             :             // hidden text has to be ignored
    1118           0 :             if(!aStart->bIsHidden)
    1119             :             {
    1120           0 :                 nEndPosition += aStart->sText.getLength();
    1121           0 :                 if(aStart->xAlternatives.is())
    1122             :                 {
    1123           0 :                     uno::Reference< container::XNamed > xNamed( aStart->xAlternatives, uno::UNO_QUERY );
    1124           0 :                     OUString sServiceName;
    1125           0 :                     if( xNamed.is() )
    1126           0 :                         sServiceName = xNamed->getName();
    1127           0 :                     SpellErrorDescription aDesc( false, aStart->xAlternatives->getWord(),
    1128           0 :                                     aStart->xAlternatives->getLocale(), aStart->xAlternatives->getAlternatives(), 0, sServiceName);
    1129           0 :                     m_pSentenceED->SetAttrib( SpellErrorAttrib(aDesc), 0, (sal_uInt16) nStartPosition, (sal_uInt16) nEndPosition );
    1130             :                 }
    1131           0 :                 else if(aStart->bIsGrammarError )
    1132             :                 {
    1133           0 :                     beans::PropertyValues  aProperties = aStart->aGrammarError.aProperties;
    1134           0 :                     OUString sFullCommentURL;
    1135           0 :                     sal_Int32 i = 0;
    1136           0 :                     while ( sFullCommentURL.isEmpty() && i < aProperties.getLength() )
    1137             :                     {
    1138           0 :                         if ( aProperties[i].Name == "FullCommentURL" )
    1139             :                         {
    1140           0 :                             uno::Any aValue = aProperties[i].Value;
    1141           0 :                             aValue >>= sFullCommentURL;
    1142             :                         }
    1143           0 :                         ++i;
    1144             :                     }
    1145             : 
    1146           0 :                     uno::Reference< lang::XServiceInfo > xInfo( aStart->xGrammarChecker, uno::UNO_QUERY );
    1147             :                     SpellErrorDescription aDesc( true,
    1148           0 :                         aStart->sText,
    1149           0 :                         LanguageTag::convertToLocale( aStart->eLanguage ),
    1150           0 :                         aStart->aGrammarError.aSuggestions,
    1151           0 :                         aStart->xGrammarChecker,
    1152           0 :                         xInfo->getImplementationName(),
    1153           0 :                         &aStart->sDialogTitle,
    1154           0 :                         &aStart->aGrammarError.aFullComment,
    1155           0 :                         &aStart->aGrammarError.aRuleIdentifier,
    1156           0 :                         &sFullCommentURL );
    1157           0 :                     m_pSentenceED->SetAttrib( SpellErrorAttrib(aDesc), 0, (sal_uInt16) nStartPosition, (sal_uInt16) nEndPosition );
    1158             :                 }
    1159           0 :                 if(aStart->bIsField)
    1160           0 :                     m_pSentenceED->SetAttrib( SpellBackgroundAttrib(COL_LIGHTGRAY), 0, (sal_uInt16) nStartPosition, (sal_uInt16) nEndPosition );
    1161           0 :                 m_pSentenceED->SetAttrib( SpellLanguageAttrib(aStart->eLanguage), 0, (sal_uInt16) nStartPosition, (sal_uInt16) nEndPosition );
    1162           0 :                 nStartPosition = nEndPosition;
    1163             :             }
    1164           0 :             ++aStart;
    1165             :         }
    1166             :         //the edit field needs to be modified to apply the change from the ApplyChangeAllList
    1167           0 :         if(!bHasReplaced)
    1168           0 :             m_pSentenceED->ClearModifyFlag();
    1169           0 :         m_pSentenceED->ResetUndo();
    1170           0 :         m_pUndoPB->Enable(false);
    1171           0 :         bRet = nStartPosition > 0;
    1172             :     }
    1173           0 :     return bRet;
    1174             : }
    1175             : /*-------------------------------------------------------------------------
    1176             :     replace errors that have a replacement in the ChangeAllList
    1177             :     returns false if the result doesn't contain errors after the replacement
    1178             :   -----------------------------------------------------------------------*/
    1179           0 : bool SpellDialog::ApplyChangeAllList_Impl(SpellPortions& rSentence, bool &bHasReplaced)
    1180             : {
    1181           0 :     bHasReplaced = false;
    1182           0 :     bool bRet = true;
    1183           0 :     SpellPortions::iterator aStart = rSentence.begin();
    1184           0 :     Reference<XDictionary> xChangeAll( SvxGetChangeAllList(), UNO_QUERY );
    1185           0 :     if(!xChangeAll->getCount())
    1186           0 :         return bRet;
    1187           0 :     bRet = false;
    1188           0 :     while(aStart != rSentence.end())
    1189             :     {
    1190           0 :         if(aStart->xAlternatives.is())
    1191             :         {
    1192           0 :             const OUString &rString = aStart->sText;
    1193             : 
    1194           0 :             Reference<XDictionaryEntry> xEntry = xChangeAll->getEntry(rString);
    1195             : 
    1196           0 :             if(xEntry.is())
    1197             :             {
    1198           0 :                 aStart->sText = getDotReplacementString(rString, xEntry->getReplacementText());
    1199           0 :                 aStart->xAlternatives = 0;
    1200           0 :                 bHasReplaced = true;
    1201             :             }
    1202             :             else
    1203           0 :                 bRet = true;
    1204             :         }
    1205           0 :         else if( aStart->bIsGrammarError )
    1206           0 :             bRet = true;
    1207           0 :         ++aStart;
    1208             :     }
    1209           0 :     return bRet;
    1210             : }
    1211             : 
    1212             : 
    1213           0 : SentenceEditWindow_Impl::SentenceEditWindow_Impl(vcl::Window * pParent, WinBits nBits)
    1214             :     : VclMultiLineEdit(pParent, nBits)
    1215             :     , m_nErrorStart(0)
    1216             :     , m_nErrorEnd(0)
    1217           0 :     , m_bIsUndoEditMode(false)
    1218             : {
    1219           0 :     DisableSelectionOnFocus();
    1220           0 : }
    1221             : 
    1222           0 : VCL_BUILDER_DECL_FACTORY(SentenceEditWindow)
    1223             : {
    1224             :     (void)rMap;
    1225           0 :     rRet = VclPtr<SentenceEditWindow_Impl>::Create(pParent, WB_BORDER|WB_VSCROLL|WB_IGNORETAB);
    1226           0 : }
    1227             : 
    1228             : 
    1229             : /*-------------------------------------------------------------------------
    1230             :     The selection before inputting a key may have a range or not
    1231             :     and it may be inside or outside of field or error attributes.
    1232             :     A range may include the attribute partially, completely or together
    1233             :     with surrounding text. It may also contain more than one attribute
    1234             :     or no attribute at all.
    1235             :     Depending on this starting conditions some actions are necessary:
    1236             :     Attempts to delete a field are only allowed if the selection is the same
    1237             :     as the field's selection. Otherwise the field has to be selected and the key
    1238             :     input action has to be skipped.
    1239             :     Input of text at the start of the field requires the field attribute to be
    1240             :     corrected - it is not allowed to grow.
    1241             : 
    1242             :     In case of errors the appending of text should grow the error attribute because
    1243             :     that is what the user usually wants to do.
    1244             : 
    1245             :     Backspace at the start of the attribute requires to find out if a field ends
    1246             :     directly in front of the cursor position. In case of a field this attribute has to be
    1247             :     selected otherwise the key input method is allowed.
    1248             : 
    1249             :     All changes outside of the error attributes switch the dialog mode to a "Undo edit" state that
    1250             :     removes all visible attributes and switches off further attribute checks.
    1251             :     Undo in this restarts the dialog with a current sentence newly presented.
    1252             :     All changes to the sentence are undone including the ones before the "Undo edit state" has been reached
    1253             : 
    1254             :     We end up with 9 types of selection
    1255             :     1 (LEFT_NO)     - no range, start of attribute - can also be 3 at the same time
    1256             :     2 (INSIDE_NO)   - no range, inside of attribute
    1257             :     3 (RIGHT_NO)    - no range, end of attribute - can also be 1 at the same time
    1258             :     4 (FULL)        - range, same as attribute
    1259             :     5 (INSIDE_YES)  - range, inside of the attribute
    1260             :     6 (BRACE)- range, from outside of the attribute to the inside or
    1261             :                 including the complete attribute and something outside,
    1262             :                 maybe more than one attribute
    1263             :     7 (OUTSIDE_NO)  - no range, not at an attribute
    1264             :     8 (OUTSIDE_YES) - range, completely outside of all attributes
    1265             : 
    1266             :     What has to be done depending on the attribute type involved
    1267             :     possible actions:   UE - Undo edit mode
    1268             :                         CO - Continue, no additional action is required
    1269             :                         FS - Field has to be completely selected
    1270             :                         EX - The attribute has to be expanded to include the added text
    1271             : 
    1272             :     1 - backspace                   delete                      any other
    1273             :         UE                          on field FS on error CO     on field FS on error CO
    1274             : 
    1275             :     2 - on field FS on error C
    1276             :     3 - backspace                   delete                      any other
    1277             :         on field FS on error CO     UE                          on field UE on error EX
    1278             : 
    1279             :     if 1 and 3 happen to apply both then backspace and other handling is 1 delete is 3
    1280             : 
    1281             :     4 - on field UE and on error CO
    1282             :     5 - on field FS and on error CO
    1283             :     6 - on field FS and on error UE
    1284             :     7 - UE
    1285             :     8 - UE
    1286             :   -----------------------------------------------------------------------*/
    1287             : #define     INVALID     0
    1288             : #define     LEFT_NO     1
    1289             : #define     INSIDE_NO   2
    1290             : #define     RIGHT_NO    3
    1291             : #define     FULL        4
    1292             : #define     INSIDE_YES  5
    1293             : #define     BRACE       6
    1294             : #define     OUTSIDE_NO  7
    1295             : #define     OUTSIDE_YES 8
    1296             : 
    1297             : #define ACTION_UNDOEDIT    0
    1298             : #define ACTION_CONTINUE    1
    1299             : #define ACTION_SELECTFIELD 2
    1300             : #define ACTION_EXPAND      3
    1301             : 
    1302           0 : bool SentenceEditWindow_Impl::PreNotify( NotifyEvent& rNEvt )
    1303             : {
    1304           0 :     bool bChange = false;
    1305           0 :     if(rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
    1306             :     {
    1307           0 :         const KeyEvent& rKeyEvt = *rNEvt.GetKeyEvent();
    1308           0 :         bChange = TextEngine::DoesKeyChangeText( rKeyEvt );
    1309           0 :         if(bChange && !IsUndoEditMode() &&
    1310           0 :             rKeyEvt.GetKeyCode().GetCode() != KEY_TAB)
    1311             :         {
    1312           0 :             TextEngine* pTextEngine = GetTextEngine();
    1313           0 :             TextView* pTextView = pTextEngine->GetActiveView();
    1314           0 :             const TextSelection& rCurrentSelection = pTextView->GetSelection();
    1315             :             //determine if the selection contains a field
    1316           0 :             bool bHasField = false;
    1317           0 :             bool bHasError = false;
    1318           0 :             bool bHasFieldLeft = false;
    1319           0 :             bool bHasErrorLeft = false;
    1320             : 
    1321           0 :             bool bHasRange = rCurrentSelection.HasRange();
    1322           0 :             sal_uInt8 nSelectionType = 0; // invalid type!
    1323             : 
    1324           0 :             TextPaM aCursor(rCurrentSelection.GetStart());
    1325           0 :             const TextCharAttrib* pBackAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
    1326           0 :             const TextCharAttrib* pErrorAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
    1327           0 :             const TextCharAttrib* pBackAttrLeft = 0;
    1328           0 :             const TextCharAttrib* pErrorAttrLeft = 0;
    1329             : 
    1330           0 :             bHasField = pBackAttr != 0 && (bHasRange || pBackAttr->GetEnd() > aCursor.GetIndex());
    1331           0 :             bHasError = pErrorAttr != 0 && (bHasRange || pErrorAttr->GetEnd() > aCursor.GetIndex());
    1332           0 :             if(bHasRange)
    1333             :             {
    1334           0 :                 if(pBackAttr &&
    1335           0 :                         pBackAttr->GetStart() == rCurrentSelection.GetStart().GetIndex() &&
    1336           0 :                         pBackAttr->GetEnd() == rCurrentSelection.GetEnd().GetIndex())
    1337             :                 {
    1338           0 :                     nSelectionType = FULL;
    1339             :                 }
    1340           0 :                 else if(pErrorAttr &&
    1341           0 :                         pErrorAttr->GetStart() <= rCurrentSelection.GetStart().GetIndex() &&
    1342           0 :                         pErrorAttr->GetEnd() >= rCurrentSelection.GetEnd().GetIndex())
    1343             :                 {
    1344           0 :                     nSelectionType = INSIDE_YES;
    1345             :                 }
    1346             :                 else
    1347             :                 {
    1348           0 :                     nSelectionType = bHasField||bHasError ? BRACE : OUTSIDE_NO;
    1349           0 :                     while(aCursor.GetIndex() < rCurrentSelection.GetEnd().GetIndex())
    1350             :                     {
    1351           0 :                         ++aCursor.GetIndex();
    1352           0 :                         const TextCharAttrib* pIntBackAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
    1353           0 :                         const TextCharAttrib* pIntErrorAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
    1354             :                         //if any attr has been found then BRACE
    1355           0 :                         if(pIntBackAttr || pIntErrorAttr)
    1356           0 :                             nSelectionType = BRACE;
    1357             :                         //the field has to be selected
    1358           0 :                         if(pIntBackAttr && !pBackAttr)
    1359           0 :                             pBackAttr = pIntBackAttr;
    1360           0 :                         bHasField |= pIntBackAttr != 0;
    1361             :                     }
    1362             :                 }
    1363             :             }
    1364             :             else
    1365             :             {
    1366             :                 //no range selection: then 1 2 3 and 8 are possible
    1367           0 :                 const TextCharAttrib* pCurAttr = pBackAttr ? pBackAttr : pErrorAttr;
    1368           0 :                 if(pCurAttr)
    1369             :                 {
    1370           0 :                     nSelectionType = pCurAttr->GetStart() == rCurrentSelection.GetStart().GetIndex() ?
    1371           0 :                             LEFT_NO : pCurAttr->GetEnd() == rCurrentSelection.GetEnd().GetIndex() ? RIGHT_NO : INSIDE_NO;
    1372             :                 }
    1373             :                 else
    1374           0 :                     nSelectionType = OUTSIDE_NO;
    1375             : 
    1376           0 :                 bHasFieldLeft = pBackAttr && pBackAttr->GetEnd() == aCursor.GetIndex();
    1377           0 :                 if(bHasFieldLeft)
    1378             :                 {
    1379           0 :                     pBackAttrLeft = pBackAttr;
    1380           0 :                     pBackAttr = 0;
    1381             :                 }
    1382           0 :                 bHasErrorLeft = pErrorAttr && pErrorAttr->GetEnd() == aCursor.GetIndex();
    1383           0 :                 if(bHasErrorLeft)
    1384             :                 {
    1385           0 :                     pErrorAttrLeft = pErrorAttr;
    1386           0 :                     pErrorAttr = 0;
    1387             :                 }
    1388             : 
    1389             :                 //check previous position if this exists
    1390             :                 //that is a redundant in the case the attribute found above already is on the left cursor side
    1391             :                 //but it's o.k. for two errors/fields side by side
    1392           0 :                 if(aCursor.GetIndex())
    1393             :                 {
    1394           0 :                     --aCursor.GetIndex();
    1395           0 :                     pBackAttrLeft = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
    1396           0 :                     pErrorAttrLeft = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
    1397           0 :                     bHasFieldLeft = pBackAttrLeft !=0;
    1398           0 :                     bHasErrorLeft = pErrorAttrLeft != 0;
    1399           0 :                     ++aCursor.GetIndex();
    1400             :                 }
    1401             :             }
    1402             :             //Here we have to determine if the error found is the one currently active
    1403           0 :             bool bIsErrorActive = (pErrorAttr && pErrorAttr->GetStart() == m_nErrorStart) ||
    1404           0 :                     (pErrorAttrLeft && pErrorAttrLeft->GetStart() == m_nErrorStart);
    1405             : 
    1406             :             SAL_WARN_IF(
    1407             :                 nSelectionType == INVALID, "cui.dialogs",
    1408             :                 "selection type not set");
    1409             : 
    1410           0 :             const vcl::KeyCode& rKeyCode = rKeyEvt.GetKeyCode();
    1411           0 :             bool bDelete = rKeyCode.GetCode() == KEY_DELETE;
    1412           0 :             bool bBackspace = rKeyCode.GetCode() == KEY_BACKSPACE;
    1413             : 
    1414           0 :             sal_Int8 nAction = ACTION_CONTINUE;
    1415           0 :             switch(nSelectionType)
    1416             :             {
    1417             : //    1 - backspace                   delete                      any other
    1418             : //        UE                          on field FS on error CO     on field FS on error CO
    1419             :                 case LEFT_NO    :
    1420           0 :                     if(bBackspace)
    1421             :                     {
    1422           0 :                         nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
    1423             :                         //to force the use of pBackAttrLeft
    1424           0 :                         pBackAttr = 0;
    1425             :                     }
    1426           0 :                     else if(bDelete)
    1427           0 :                         nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
    1428             :                     else
    1429           0 :                         nAction = bHasError && !aCursor.GetIndex() ? ACTION_CONTINUE :
    1430           0 :                             bHasError ? ACTION_EXPAND : bHasErrorLeft ? ACTION_CONTINUE : ACTION_UNDOEDIT;
    1431           0 :                 break;
    1432             : //    2 - on field FS on error C
    1433             :                 case INSIDE_NO  :
    1434             :                     nAction =  bHasField ? ACTION_SELECTFIELD :
    1435           0 :                         bIsErrorActive ? ACTION_CONTINUE : ACTION_UNDOEDIT;
    1436           0 :                 break;
    1437             : //    3 - backspace                   delete                      any other
    1438             : //        on field FS on error CO     UE                          on field UE on error EX
    1439             :                 case RIGHT_NO   :
    1440           0 :                     if(bBackspace)
    1441           0 :                         nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_CONTINUE;
    1442           0 :                     else if(bDelete)
    1443           0 :                         nAction = bHasFieldLeft && bHasError ? ACTION_CONTINUE : ACTION_UNDOEDIT;
    1444             :                     else
    1445           0 :                         nAction = bHasFieldLeft && bHasError ? ACTION_EXPAND :
    1446           0 :                             bHasError ? ACTION_CONTINUE : bHasErrorLeft ? ACTION_EXPAND :ACTION_UNDOEDIT;
    1447           0 :                 break;
    1448             : //    4 - on field UE and on error CO
    1449             :                 case FULL       :
    1450           0 :                     nAction = ACTION_UNDOEDIT;
    1451           0 :                 break;
    1452             : //    5 - on field FS and on error CO
    1453             :                 case INSIDE_YES :
    1454           0 :                     nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
    1455           0 :                 break;
    1456             : //    6 - on field FS and on error UE
    1457             :                 case BRACE      :
    1458           0 :                     nAction = bHasField ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;;
    1459           0 :                 break;
    1460             : //    7 - UE
    1461             : //    8 - UE
    1462             :                 case OUTSIDE_NO :
    1463             :                 case OUTSIDE_YES:
    1464           0 :                     nAction = ACTION_UNDOEDIT;
    1465           0 :                 break;
    1466             :             }
    1467             :             //save the current paragraph
    1468           0 :             sal_Int32 nCurrentLen = GetText().getLength();
    1469           0 :             if(nAction != ACTION_SELECTFIELD)
    1470           0 :                 pTextView->GetWindow()->KeyInput(rKeyEvt);
    1471             :             else
    1472             :             {
    1473           0 :                 const TextCharAttrib* pCharAttr = pBackAttr ? pBackAttr : pBackAttrLeft;
    1474           0 :                 if(pCharAttr)
    1475             :                 {
    1476           0 :                     TextPaM aStart(0, pCharAttr->GetStart());
    1477           0 :                     TextPaM aEnd(0, pCharAttr->GetEnd());
    1478           0 :                     TextSelection aNewSel(aStart, aEnd);
    1479           0 :                     pTextView->SetSelection( aNewSel);
    1480             :                 }
    1481             :             }
    1482           0 :             if(nAction == ACTION_EXPAND)
    1483             :             {
    1484             :                 DBG_ASSERT(pErrorAttrLeft || pErrorAttr, "where is the error");
    1485             :                 //text has been added on the right and only the 'error attribute has to be corrected
    1486           0 :                 if(pErrorAttrLeft)
    1487             :                 {
    1488           0 :                     boost::scoped_ptr<TextAttrib> pNewError(pErrorAttrLeft->GetAttr().Clone());
    1489           0 :                     sal_uInt16 nStart = pErrorAttrLeft->GetStart();
    1490           0 :                     sal_uInt16 nEnd = pErrorAttrLeft->GetEnd();
    1491           0 :                     pTextEngine->RemoveAttrib( 0, *pErrorAttrLeft );
    1492           0 :                     SetAttrib( *pNewError, 0, nStart, ++nEnd );
    1493             :                     //only active errors move the mark
    1494           0 :                     if(bIsErrorActive)
    1495             :                     {
    1496           0 :                         bool bGrammar = static_cast<const SpellErrorAttrib&>(*pNewError).GetErrorDescription().bIsGrammarError;
    1497           0 :                         MoveErrorMarkTo(nStart, nEnd, bGrammar);
    1498           0 :                     }
    1499             :                 }
    1500             :                 //text has been added on the left then the error attribute has to be expanded and the
    1501             :                 //field attribute on the right - if any - has to be contracted
    1502           0 :                 else if(pErrorAttr)
    1503             :                 {
    1504             :                     //determine the change
    1505           0 :                     sal_Int32 nAddedChars = GetText().getLength() - nCurrentLen;
    1506             : 
    1507           0 :                     boost::scoped_ptr<TextAttrib> pNewError(pErrorAttr->GetAttr().Clone());
    1508           0 :                     sal_Int32 nStart = pErrorAttr->GetStart();
    1509           0 :                     sal_Int32 nEnd = pErrorAttr->GetEnd();
    1510           0 :                     pTextEngine->RemoveAttrib( 0, *pErrorAttr );
    1511           0 :                     nStart = nStart - nAddedChars;
    1512           0 :                     SetAttrib( *pNewError, 0, nStart - nAddedChars, nEnd );
    1513             :                     //only if the error is active the mark is moved here
    1514           0 :                     if(bIsErrorActive)
    1515             :                     {
    1516           0 :                         bool bGrammar = static_cast<const SpellErrorAttrib&>(*pNewError).GetErrorDescription().bIsGrammarError;
    1517           0 :                         MoveErrorMarkTo(nStart, nEnd, bGrammar);
    1518             :                     }
    1519           0 :                     pNewError.reset();
    1520             : 
    1521           0 :                     if(pBackAttrLeft)
    1522             :                     {
    1523           0 :                         boost::scoped_ptr<TextAttrib> pNewBack(pBackAttrLeft->GetAttr().Clone());
    1524           0 :                         sal_uInt16 _nStart = pBackAttrLeft->GetStart();
    1525           0 :                         sal_uInt16 _nEnd = pBackAttrLeft->GetEnd();
    1526           0 :                         pTextEngine->RemoveAttrib( 0, *pBackAttrLeft );
    1527           0 :                         SetAttrib( *pNewBack, 0, _nStart, _nEnd - nAddedChars);
    1528           0 :                     }
    1529             :                 }
    1530             :             }
    1531           0 :             else if(nAction == ACTION_UNDOEDIT)
    1532             :             {
    1533           0 :                 SetUndoEditMode(true);
    1534             :             }
    1535             :             //make sure the error positions are correct after text changes
    1536             :             //the old attribute may have been deleted
    1537             :             //all changes inside of the current error leave the error attribute at the current
    1538             :             //start position
    1539           0 :             if(!IsUndoEditMode() && bIsErrorActive)
    1540             :             {
    1541           0 :                 const TextCharAttrib* pFontColor = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_FONTCOLOR );
    1542           0 :                 const TextCharAttrib*  pErrorAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_ERROR );
    1543           0 :                 if(pFontColor && pErrorAttrib )
    1544             :                 {
    1545           0 :                     m_nErrorStart = pFontColor->GetStart();
    1546           0 :                     m_nErrorEnd = pFontColor->GetEnd();
    1547           0 :                     if(pErrorAttrib->GetStart() != m_nErrorStart || pErrorAttrib->GetEnd() != m_nErrorEnd)
    1548             :                     {
    1549           0 :                         boost::scoped_ptr<TextAttrib> pNewError(pErrorAttrib->GetAttr().Clone());
    1550           0 :                         pTextEngine->RemoveAttrib( 0, *pErrorAttr );
    1551           0 :                         SetAttrib( *pNewError, 0, m_nErrorStart, m_nErrorEnd );
    1552             :                     }
    1553             :                 }
    1554             :             }
    1555             :             //this is not a modification anymore
    1556           0 :             if(nAction != ACTION_SELECTFIELD && !m_bIsUndoEditMode)
    1557           0 :                 CallModifyLink();
    1558             :         }
    1559             :         else
    1560           0 :             bChange = false;
    1561             :     }
    1562           0 :     return bChange || VclMultiLineEdit::PreNotify(rNEvt);
    1563             : }
    1564             : 
    1565             : 
    1566           0 : bool SentenceEditWindow_Impl::MarkNextError( bool bIgnoreCurrentError, com::sun::star::uno::Reference<com::sun::star::linguistic2::XSpellChecker1> xSpell )
    1567             : {
    1568           0 :     if (bIgnoreCurrentError)
    1569           0 :         m_aIgnoreErrorsAt.insert( m_nErrorStart );
    1570           0 :     ExtTextEngine* pTextEngine = GetTextEngine();
    1571           0 :     sal_uInt16 nTextLen = pTextEngine->GetTextLen(0);
    1572           0 :     if(m_nErrorEnd >= nTextLen - 1)
    1573           0 :         return false;
    1574             :     //if it's not already modified the modified flag has to be reset at the end of the marking
    1575           0 :     bool bModified = IsModified();
    1576           0 :     bool bRet = false;
    1577           0 :     const sal_uInt16 nOldErrorStart = m_nErrorStart;
    1578           0 :     const sal_uInt16 nOldErrorEnd   = m_nErrorEnd;
    1579             : 
    1580             :     //create a cursor behind the end of the last error
    1581             :     //- or at 0 at the start of the sentence
    1582           0 :     TextPaM aCursor(0, m_nErrorEnd ? m_nErrorEnd + 1 : 0);
    1583             :     //search for SpellErrorAttrib
    1584             : 
    1585           0 :     const TextCharAttrib* pNextError = 0;
    1586             :     //iterate over the text and search for the next error that maybe has
    1587             :     //to be replace by a ChangeAllList replacement
    1588           0 :     bool bGrammarError = false;
    1589           0 :     while(aCursor.GetIndex() < nTextLen)
    1590             :     {
    1591           0 :         while(aCursor.GetIndex() < nTextLen &&
    1592           0 :                 0 == (pNextError = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR)))
    1593             :         {
    1594           0 :             ++aCursor.GetIndex();
    1595             :         }
    1596             :         // maybe the error found here is already in the ChangeAllList and has to be replaced
    1597             : 
    1598           0 :         Reference<XDictionary> xChangeAll( SvxGetChangeAllList(), UNO_QUERY );
    1599           0 :         Reference<XDictionaryEntry> xEntry;
    1600             : 
    1601           0 :         const SpellErrorDescription* pSpellErrorDescription = 0;
    1602           0 :         if(pNextError)
    1603             :         {
    1604           0 :             pSpellErrorDescription = &static_cast<const SpellErrorAttrib&>(pNextError->GetAttr()).GetErrorDescription();
    1605           0 :             bGrammarError = pSpellErrorDescription->bIsGrammarError;
    1606           0 :             m_nErrorStart = pNextError->GetStart();
    1607           0 :             m_nErrorEnd = pNextError->GetEnd();
    1608             :         }
    1609           0 :         if(xChangeAll->getCount() && pSpellErrorDescription &&
    1610           0 :                 (xEntry = xChangeAll->getEntry( pSpellErrorDescription->sErrorText )).is())
    1611             :         {
    1612             : 
    1613           0 :             OUString sReplacement(getDotReplacementString(GetErrorText(), xEntry->getReplacementText()));
    1614             : 
    1615           0 :             ChangeMarkedWord(sReplacement, LanguageTag::convertToLanguageType( pSpellErrorDescription->aLocale ));
    1616             : 
    1617           0 :             aCursor.GetIndex() = aCursor.GetIndex() + (sal_uInt16)(xEntry->getReplacementText().getLength());
    1618             :         // maybe the error found here is already added to the dictionary and has to be ignored
    1619           0 :         } else if(pSpellErrorDescription && !bGrammarError && xSpell->isValid( GetErrorText(), LanguageTag::convertToLanguageType( pSpellErrorDescription->aLocale ), Sequence< PropertyValue >() )) {
    1620           0 :             aCursor.GetIndex() = aCursor.GetIndex() + 1;
    1621             :         }
    1622             :         else
    1623           0 :             break;
    1624           0 :     }
    1625             : 
    1626             :     //if an attrib has been found search for the end of the error string
    1627           0 :     if(aCursor.GetIndex() < nTextLen)
    1628             :     {
    1629           0 :         m_nErrorStart = aCursor.GetIndex();
    1630           0 :         m_nErrorEnd = pNextError->GetEnd();
    1631           0 :         MoveErrorMarkTo(m_nErrorStart, m_nErrorEnd, bGrammarError);
    1632           0 :         bRet = true;
    1633             :         //add an undo action
    1634             :         SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
    1635           0 :                 SPELLUNDO_CHANGE_NEXTERROR, GetSpellDialog()->aDialogUndoLink);
    1636           0 :         pAction->SetErrorMove(m_nErrorStart, m_nErrorEnd, nOldErrorStart, nOldErrorEnd);
    1637             :         const SpellErrorAttrib* pOldAttrib = static_cast<const SpellErrorAttrib*>(
    1638           0 :                 pTextEngine->FindAttrib( TextPaM(0, nOldErrorStart), TEXTATTR_SPELL_ERROR ));
    1639           0 :         pAction->SetErrorLanguageSelected(pOldAttrib && pOldAttrib->GetErrorDescription().aSuggestions.getLength() &&
    1640           0 :                 LanguageTag( pOldAttrib->GetErrorDescription().aLocale).getLanguageType() ==
    1641           0 :                                         GetSpellDialog()->m_pLanguageLB->GetSelectLanguage());
    1642           0 :         AddUndoAction(pAction);
    1643             :     }
    1644             :     else
    1645           0 :         m_nErrorStart = m_nErrorEnd = nTextLen;
    1646           0 :     if( !bModified )
    1647           0 :         ClearModifyFlag();
    1648           0 :     SpellDialog* pSpellDialog = GetSpellDialog();
    1649           0 :     pSpellDialog->m_pIgnorePB->Enable(bRet);
    1650           0 :     pSpellDialog->m_pIgnoreAllPB->Enable(bRet);
    1651           0 :     pSpellDialog->m_pAutoCorrPB->Enable(bRet);
    1652           0 :     pSpellDialog->m_pAddToDictMB->Enable(bRet);
    1653           0 :     pSpellDialog->m_pAddToDictPB->Enable(bRet);
    1654           0 :     return bRet;
    1655             : }
    1656             : 
    1657             : 
    1658           0 : void SentenceEditWindow_Impl::MoveErrorMarkTo(sal_uInt16 nStart, sal_uInt16 nEnd, bool bGrammarError)
    1659             : {
    1660           0 :     TextEngine* pTextEngine = GetTextEngine();
    1661           0 :     pTextEngine->RemoveAttribs( 0, (sal_uInt16)TEXTATTR_FONTCOLOR, true );
    1662           0 :     pTextEngine->RemoveAttribs( 0, (sal_uInt16)TEXTATTR_FONTWEIGHT, true );
    1663           0 :     pTextEngine->SetAttrib( TextAttribFontWeight(WEIGHT_BOLD), 0, nStart, nEnd );
    1664           0 :     pTextEngine->SetAttrib( TextAttribFontColor(bGrammarError ? COL_LIGHTBLUE : COL_LIGHTRED), 0, nStart, nEnd );
    1665           0 :     m_nErrorStart = nStart;
    1666           0 :     m_nErrorEnd = nEnd;
    1667           0 : }
    1668             : 
    1669             : 
    1670           0 : void SentenceEditWindow_Impl::ChangeMarkedWord(const OUString& rNewWord, LanguageType eLanguage)
    1671             : {
    1672             :     //calculate length changes
    1673           0 :     long nDiffLen = rNewWord.getLength() - m_nErrorEnd + m_nErrorStart;
    1674           0 :     TextSelection aSel(TextPaM(0, m_nErrorStart), TextPaM(0, m_nErrorEnd));
    1675             :     //Remove spell error attribute
    1676           0 :     ExtTextEngine* pTextEngine = GetTextEngine();
    1677           0 :     pTextEngine->UndoActionStart();
    1678           0 :     const TextCharAttrib*  pErrorAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_ERROR );
    1679             :     DBG_ASSERT(pErrorAttrib, "no error attribute found");
    1680           0 :     const SpellErrorDescription* pSpellErrorDescription = 0;
    1681           0 :     if(pErrorAttrib)
    1682             :     {
    1683           0 :         pTextEngine->RemoveAttrib(0, *pErrorAttrib);
    1684           0 :         pSpellErrorDescription = &static_cast<const SpellErrorAttrib&>(pErrorAttrib->GetAttr()).GetErrorDescription();
    1685             :     }
    1686           0 :     const TextCharAttrib*  pBackAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_BACKGROUND );
    1687           0 :     pTextEngine->ReplaceText( aSel, rNewWord );
    1688             : 
    1689           0 :     if(!m_nErrorStart)
    1690             :     {
    1691             :         //attributes following an error at the start of the text are not moved but expanded from the
    1692             :         //text engine - this is done to keep full-paragraph-attributes
    1693             :         //in the current case that handling is not desired
    1694             :         const TextCharAttrib*  pLangAttrib =
    1695             :                 pTextEngine->FindCharAttrib(
    1696           0 :                     TextPaM(0, m_nErrorEnd), TEXTATTR_SPELL_LANGUAGE );
    1697           0 :         sal_uInt16 nTextLen = pTextEngine->GetTextLen( 0 );
    1698           0 :         if(pLangAttrib && !pLangAttrib->GetStart() && pLangAttrib->GetEnd() ==
    1699             :             nTextLen)
    1700             :         {
    1701           0 :             SpellLanguageAttrib aNewLangAttrib( static_cast<const SpellLanguageAttrib&>(pLangAttrib->GetAttr()).GetLanguage());
    1702           0 :             pTextEngine->RemoveAttrib(0, *pLangAttrib);
    1703           0 :             pTextEngine->SetAttrib( aNewLangAttrib, 0, (sal_uInt16)(m_nErrorEnd + nDiffLen) , nTextLen );
    1704             :         }
    1705             :     }
    1706             :     // undo expanded attributes!
    1707           0 :     if( pBackAttrib && pBackAttrib->GetStart() < m_nErrorStart && pBackAttrib->GetEnd() == m_nErrorEnd + nDiffLen)
    1708             :     {
    1709           0 :         boost::scoped_ptr<TextAttrib> pNewBackground(pBackAttrib->GetAttr().Clone());
    1710           0 :         sal_uInt16 nStart = pBackAttrib->GetStart();
    1711           0 :         pTextEngine->RemoveAttrib(0, *pBackAttrib);
    1712           0 :         pTextEngine->SetAttrib(*pNewBackground, 0, nStart, m_nErrorStart);
    1713             :     }
    1714           0 :     pTextEngine->SetModified(true);
    1715             : 
    1716             :     //adjust end position
    1717           0 :     long nEndTemp = m_nErrorEnd;
    1718           0 :     nEndTemp += nDiffLen;
    1719           0 :     m_nErrorEnd = (sal_uInt16)nEndTemp;
    1720             : 
    1721             :     SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
    1722           0 :                     SPELLUNDO_MOVE_ERROREND, GetSpellDialog()->aDialogUndoLink);
    1723           0 :     pAction->SetOffset(nDiffLen);
    1724           0 :     AddUndoAction(pAction);
    1725           0 :     if(pSpellErrorDescription)
    1726           0 :         SetAttrib( SpellErrorAttrib(*pSpellErrorDescription), 0, m_nErrorStart, m_nErrorEnd );
    1727           0 :     SetAttrib( SpellLanguageAttrib(eLanguage), 0, m_nErrorStart, m_nErrorEnd );
    1728           0 :     pTextEngine->UndoActionEnd();
    1729           0 : }
    1730             : 
    1731             : 
    1732           0 : OUString SentenceEditWindow_Impl::GetErrorText() const
    1733             : {
    1734           0 :     return GetTextEngine()->GetText(TextSelection(TextPaM(0, m_nErrorStart), TextPaM(0, m_nErrorEnd) ));
    1735             : }
    1736             : 
    1737             : 
    1738           0 : const SpellErrorDescription* SentenceEditWindow_Impl::GetAlternatives()
    1739             : {
    1740           0 :     TextPaM aCursor(0, m_nErrorStart);
    1741             :     const SpellErrorAttrib* pAttrib = static_cast<const SpellErrorAttrib*>(
    1742           0 :             GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR));
    1743           0 :     return pAttrib ? &pAttrib->GetErrorDescription() : 0;
    1744             : }
    1745             : 
    1746             : 
    1747           0 : void SentenceEditWindow_Impl::RestoreCurrentError()
    1748             : {
    1749           0 :     TextPaM aCursor(0, m_nErrorStart);
    1750             :     const SpellErrorAttrib* pAttrib = static_cast<const SpellErrorAttrib*>(
    1751           0 :             GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR));
    1752           0 :     if( pAttrib )
    1753             :     {
    1754           0 :         const SpellErrorDescription& rDesc = pAttrib->GetErrorDescription();
    1755           0 :         if( !rDesc.sErrorText.equals( GetErrorText() ) )
    1756           0 :             ChangeMarkedWord(rDesc.sErrorText, LanguageTag::convertToLanguageType( rDesc.aLocale ));
    1757             :     }
    1758           0 : }
    1759             : 
    1760             : 
    1761           0 : void SentenceEditWindow_Impl::SetAlternatives( Reference< XSpellAlternatives> xAlt )
    1762             : {
    1763           0 :     TextPaM aCursor(0, m_nErrorStart);
    1764             :     DBG_ASSERT(static_cast<const SpellErrorAttrib*>(
    1765             :             GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR)), "no error set?");
    1766             : 
    1767           0 :     OUString aWord;
    1768           0 :     lang::Locale    aLocale;
    1769           0 :     uno::Sequence< OUString >    aAlts;
    1770           0 :     OUString sServiceName;
    1771           0 :     if (xAlt.is())
    1772             :     {
    1773           0 :         aWord   = xAlt->getWord();
    1774           0 :         aLocale = xAlt->getLocale();
    1775           0 :         aAlts   = xAlt->getAlternatives();
    1776           0 :         uno::Reference< container::XNamed > xNamed( xAlt, uno::UNO_QUERY );
    1777           0 :         if (xNamed.is())
    1778           0 :             sServiceName = xNamed->getName();
    1779             :     }
    1780           0 :     SpellErrorDescription aDesc( false, aWord, aLocale, aAlts, 0, sServiceName);
    1781           0 :     GetTextEngine()->SetAttrib( SpellErrorAttrib(aDesc), 0, m_nErrorStart, m_nErrorEnd );
    1782           0 : }
    1783             : 
    1784             : 
    1785           0 : void SentenceEditWindow_Impl::SetAttrib( const TextAttrib& rAttr, sal_uLong nPara, sal_uInt16 nStart, sal_uInt16 nEnd )
    1786             : {
    1787           0 :     GetTextEngine()->SetAttrib(rAttr, nPara, nStart, nEnd);
    1788           0 : }
    1789             : 
    1790             : 
    1791           0 : void SentenceEditWindow_Impl::SetText( const OUString& rStr )
    1792             : {
    1793           0 :     m_nErrorStart = m_nErrorEnd = 0;
    1794           0 :     GetTextEngine()->SetText(rStr);
    1795           0 : }
    1796             : 
    1797             : 
    1798             : struct LanguagePosition_Impl
    1799             : {
    1800             :     sal_uInt16          nPosition;
    1801             :     LanguageType    eLanguage;
    1802             : 
    1803           0 :     LanguagePosition_Impl(sal_uInt16 nPos, LanguageType eLang) :
    1804             :         nPosition(nPos),
    1805           0 :         eLanguage(eLang)
    1806           0 :         {}
    1807             : };
    1808             : typedef std::vector<LanguagePosition_Impl> LanguagePositions_Impl;
    1809             : 
    1810           0 : static void lcl_InsertBreakPosition_Impl(
    1811             :         LanguagePositions_Impl& rBreakPositions, sal_uInt16 nInsert, LanguageType eLanguage)
    1812             : {
    1813           0 :     LanguagePositions_Impl::iterator aStart = rBreakPositions.begin();
    1814           0 :     while(aStart != rBreakPositions.end())
    1815             :     {
    1816           0 :         if(aStart->nPosition == nInsert)
    1817             :         {
    1818             :             //the language of following starts has to overwrite
    1819             :             //the one of previous ends
    1820           0 :             aStart->eLanguage = eLanguage;
    1821           0 :             return;
    1822             :         }
    1823           0 :         else if(aStart->nPosition > nInsert)
    1824             :         {
    1825             : 
    1826           0 :             rBreakPositions.insert(aStart, LanguagePosition_Impl(nInsert, eLanguage));
    1827           0 :             return;
    1828             :         }
    1829             :         else
    1830           0 :             ++aStart;
    1831             :     }
    1832           0 :     rBreakPositions.push_back(LanguagePosition_Impl(nInsert, eLanguage));
    1833             : }
    1834             : /*-------------------------------------------------------------------------
    1835             :     Returns the text in spell portions. Each portion contains text with an
    1836             :     equal language and attribute. The spell alternatives are empty.
    1837             :   -----------------------------------------------------------------------*/
    1838           0 : svx::SpellPortions SentenceEditWindow_Impl::CreateSpellPortions( bool bSetIgnoreFlag ) const
    1839             : {
    1840           0 :     svx::SpellPortions aRet;
    1841           0 :     ExtTextEngine* pTextEngine = GetTextEngine();
    1842           0 :     const sal_uInt16 nTextLen = pTextEngine->GetTextLen(0);
    1843           0 :     if(nTextLen)
    1844             :     {
    1845           0 :         TextPaM aCursor(0, 0);
    1846           0 :         LanguagePositions_Impl aBreakPositions;
    1847           0 :         const TextCharAttrib* pLastLang = 0;
    1848           0 :         const TextCharAttrib* pLastError = 0;
    1849           0 :         LanguageType eLang = LANGUAGE_DONTKNOW;
    1850           0 :         const TextCharAttrib* pError = 0;
    1851           0 :         while(aCursor.GetIndex() < nTextLen)
    1852             :         {
    1853           0 :             const TextCharAttrib* pLang = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_LANGUAGE);
    1854           0 :             if(pLang && pLang != pLastLang)
    1855             :             {
    1856           0 :                 eLang = static_cast<const SpellLanguageAttrib&>(pLang->GetAttr()).GetLanguage();
    1857           0 :                 lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->GetStart(), eLang);
    1858           0 :                 lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->GetEnd(), eLang);
    1859           0 :                 pLastLang = pLang;
    1860             :             }
    1861           0 :             pError = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR);
    1862           0 :             if(pError && pLastError != pError)
    1863             :             {
    1864           0 :                 lcl_InsertBreakPosition_Impl(aBreakPositions, pError->GetStart(), eLang);
    1865           0 :                 lcl_InsertBreakPosition_Impl(aBreakPositions, pError->GetEnd(), eLang);
    1866           0 :                 pLastError = pError;
    1867             : 
    1868             :             }
    1869           0 :             aCursor.GetIndex()++;
    1870             :         }
    1871             : 
    1872           0 :         if(nTextLen && aBreakPositions.empty())
    1873             :         {
    1874             :             //if all content has been overwritten the attributes may have been removed, too
    1875           0 :             svx::SpellPortion aPortion1;
    1876           0 :             aPortion1.eLanguage = GetSpellDialog()->GetSelectedLang_Impl();
    1877           0 :             aPortion1.sText = pTextEngine->GetText(
    1878           0 :                         TextSelection(TextPaM(0, 0), TextPaM(0, nTextLen)));
    1879             : 
    1880           0 :             aRet.push_back(aPortion1);
    1881             : 
    1882             :         }
    1883           0 :         else if(!aBreakPositions.empty())
    1884             :         {
    1885           0 :             LanguagePositions_Impl::iterator aStart = aBreakPositions.begin();
    1886             :             //start should always be Null
    1887           0 :             eLang = aStart->eLanguage;
    1888           0 :             sal_uInt16 nStart = aStart->nPosition;
    1889             :             DBG_ASSERT(!nStart, "invalid start position - language attribute missing?");
    1890           0 :             ++aStart;
    1891             : 
    1892           0 :             while(aStart != aBreakPositions.end())
    1893             :             {
    1894           0 :                 svx::SpellPortion aPortion1;
    1895           0 :                 aPortion1.eLanguage = eLang;
    1896           0 :                 aPortion1.sText = pTextEngine->GetText(
    1897           0 :                             TextSelection(TextPaM(0, nStart), TextPaM(0, aStart->nPosition)));
    1898           0 :                 bool bIsIgnoreError = m_aIgnoreErrorsAt.find( nStart ) != m_aIgnoreErrorsAt.end();
    1899           0 :                 if( bSetIgnoreFlag && bIsIgnoreError )
    1900             :                 {
    1901           0 :                     aPortion1.bIgnoreThisError = true;
    1902             :                 }
    1903           0 :                 aRet.push_back(aPortion1);
    1904           0 :                 nStart = aStart->nPosition;
    1905           0 :                 eLang = aStart->eLanguage;
    1906           0 :                 ++aStart;
    1907           0 :             }
    1908             :         }
    1909             : 
    1910             :         // quick partly fix of #i71318. Correct fix needs to patch the TextEngine itself...
    1911             :         // this one will only prevent text from disappearing. It may to not have the
    1912             :         // correct language and will probably not spell checked...
    1913           0 :         sal_uLong nPara = pTextEngine->GetParagraphCount();
    1914           0 :         if (nPara > 1)
    1915             :         {
    1916           0 :             OUString aLeftOverText;
    1917           0 :             for (sal_uLong i = 1;  i < nPara;  ++i)
    1918             :             {
    1919           0 :                 aLeftOverText += "\x0a";    // the manual line break...
    1920           0 :                 aLeftOverText += pTextEngine->GetText(i);
    1921             :             }
    1922           0 :             if (pError)
    1923             :             {   // we need to add a new portion containing the left-over text
    1924           0 :                 svx::SpellPortion aPortion2;
    1925           0 :                 aPortion2.eLanguage = eLang;
    1926           0 :                 aPortion2.sText = aLeftOverText;
    1927           0 :                 aRet.push_back( aPortion2 );
    1928             :             }
    1929             :             else
    1930             :             {   // we just need to append the left-over text to the last portion (which had no errors)
    1931           0 :                 aRet[ aRet.size() - 1 ].sText += aLeftOverText;
    1932           0 :             }
    1933           0 :         }
    1934             :    }
    1935           0 :     return aRet;
    1936             : }
    1937             : 
    1938             : 
    1939           0 : void SentenceEditWindow_Impl::Undo()
    1940             : {
    1941           0 :     ::svl::IUndoManager& rUndoMgr = GetTextEngine()->GetUndoManager();
    1942             :     DBG_ASSERT(GetUndoActionCount(), "no undo actions available" );
    1943           0 :     if(!GetUndoActionCount())
    1944           0 :         return;
    1945           0 :     bool bSaveUndoEdit = IsUndoEditMode();
    1946             :     sal_uInt16 nId;
    1947             :     //if the undo edit mode is active then undo all changes until the UNDO_EDIT_MODE action has been found
    1948           0 :     do
    1949             :     {
    1950           0 :         nId = rUndoMgr.GetUndoActionId();
    1951           0 :         rUndoMgr.Undo();
    1952           0 :     }while(bSaveUndoEdit && SPELLUNDO_UNDO_EDIT_MODE != nId && GetUndoActionCount());
    1953             : 
    1954           0 :     if(bSaveUndoEdit || SPELLUNDO_CHANGE_GROUP == nId)
    1955           0 :         GetSpellDialog()->UpdateBoxes_Impl();
    1956             : }
    1957             : 
    1958             : 
    1959           0 : void SentenceEditWindow_Impl::ResetUndo()
    1960             : {
    1961           0 :     GetTextEngine()->ResetUndo();
    1962           0 : }
    1963             : 
    1964             : 
    1965           0 : void SentenceEditWindow_Impl::AddUndoAction( SfxUndoAction *pAction, bool bTryMerg )
    1966             : {
    1967           0 :     ::svl::IUndoManager& rUndoMgr = GetTextEngine()->GetUndoManager();
    1968           0 :     rUndoMgr.AddUndoAction(pAction, bTryMerg);
    1969           0 :     GetSpellDialog()->m_pUndoPB->Enable();
    1970           0 : }
    1971             : 
    1972             : 
    1973           0 : sal_uInt16 SentenceEditWindow_Impl::GetUndoActionCount()
    1974             : {
    1975           0 :     return GetTextEngine()->GetUndoManager().GetUndoActionCount();
    1976             : }
    1977             : 
    1978             : 
    1979           0 : void SentenceEditWindow_Impl::UndoActionStart( sal_uInt16 nId )
    1980             : {
    1981           0 :     GetTextEngine()->UndoActionStart(nId);
    1982           0 : }
    1983             : 
    1984             : 
    1985           0 : void SentenceEditWindow_Impl::UndoActionEnd()
    1986             : {
    1987           0 :     GetTextEngine()->UndoActionEnd();
    1988           0 : }
    1989             : 
    1990             : 
    1991           0 : void SentenceEditWindow_Impl::MoveErrorEnd(long nOffset)
    1992             : {
    1993           0 :     if(nOffset > 0)
    1994           0 :         m_nErrorEnd = m_nErrorEnd - (sal_uInt16)nOffset;
    1995             :     else
    1996           0 :         m_nErrorEnd = m_nErrorEnd -(sal_uInt16)- nOffset;
    1997           0 : }
    1998             : 
    1999             : 
    2000           0 : void  SentenceEditWindow_Impl::SetUndoEditMode(bool bSet)
    2001             : {
    2002             :     DBG_ASSERT(!bSet || m_bIsUndoEditMode != bSet, "SetUndoEditMode with equal values?");
    2003           0 :     m_bIsUndoEditMode = bSet;
    2004             :     //disable all buttons except the Change
    2005           0 :     SpellDialog* pSpellDialog = GetSpellDialog();
    2006             :     Control* aControls[] =
    2007             :     {
    2008             :         pSpellDialog->m_pChangeAllPB,
    2009             :         pSpellDialog->m_pExplainFT,
    2010             :         pSpellDialog->m_pIgnoreAllPB,
    2011             :         pSpellDialog->m_pIgnoreRulePB,
    2012             :         pSpellDialog->m_pIgnorePB,
    2013             :         pSpellDialog->m_pSuggestionLB,
    2014             :         pSpellDialog->m_pSuggestionFT,
    2015             :         pSpellDialog->m_pLanguageFT,
    2016             :         pSpellDialog->m_pLanguageLB,
    2017             :         pSpellDialog->m_pAddToDictMB,
    2018             :         pSpellDialog->m_pAddToDictPB,
    2019             :         pSpellDialog->m_pAutoCorrPB,
    2020             :         0
    2021           0 :     };
    2022           0 :     sal_Int32 nIdx = 0;
    2023           0 :     do
    2024             :     {
    2025           0 :         aControls[nIdx]->Enable(false);
    2026             :     }
    2027           0 :     while(aControls[++nIdx]);
    2028             : 
    2029             :     //remove error marks
    2030           0 :     TextEngine* pTextEngine = GetTextEngine();
    2031           0 :     pTextEngine->RemoveAttribs( 0, (sal_uInt16)TEXTATTR_FONTCOLOR, true );
    2032           0 :     pTextEngine->RemoveAttribs( 0, (sal_uInt16)TEXTATTR_FONTWEIGHT, true );
    2033             : 
    2034             :     //put the appropriate action on the Undo-stack
    2035             :     SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
    2036           0 :                         SPELLUNDO_UNDO_EDIT_MODE, GetSpellDialog()->aDialogUndoLink);
    2037           0 :     AddUndoAction(pAction);
    2038           0 :     pSpellDialog->m_pChangePB->Enable();
    2039           0 : }
    2040             : 
    2041           0 : IMPL_LINK( SpellDialog, HandleHyperlink, FixedHyperlink*, pHyperlink )
    2042             : {
    2043           0 :     OUString sURL=pHyperlink->GetURL();
    2044           0 :     OUString sTitle=GetText();
    2045             : 
    2046           0 :     if ( sURL.isEmpty() ) // Nothing to do, when the URL is empty
    2047           0 :         return 1;
    2048             :     try
    2049             :     {
    2050             :         uno::Reference< com::sun::star::system::XSystemShellExecute > xSystemShellExecute(
    2051           0 :             com::sun::star::system::SystemShellExecute::create(::comphelper::getProcessComponentContext()) );
    2052           0 :         xSystemShellExecute->execute( sURL, OUString(), com::sun::star::system::SystemShellExecuteFlags::URIS_ONLY );
    2053             :     }
    2054           0 :     catch ( uno::Exception& )
    2055             :     {
    2056           0 :         uno::Any exc( ::cppu::getCaughtException() );
    2057           0 :         OUString msg( ::comphelper::anyToString( exc ) );
    2058           0 :         const SolarMutexGuard guard;
    2059           0 :         ScopedVclPtrInstance< MessageDialog > aErrorBox(nullptr, msg);
    2060           0 :         aErrorBox->SetText(sTitle);
    2061           0 :         aErrorBox->Execute();
    2062             :     }
    2063             : 
    2064           0 :     return 1;
    2065           0 : }
    2066             : 
    2067             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11