/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
namespace svx{ class SpellUndoAction_Impl : public SfxUndoAction
{
sal_uInt16 m_nId; const Link<SpellUndoAction_Impl&,void>& m_rActionLink; //undo of button enabling bool m_bEnableChangePB; bool m_bEnableChangeAllPB; //undo of MarkNextError - used in change and change all, ignore and ignore all
tools::Long m_nOldErrorStart;
tools::Long m_nOldErrorEnd; bool m_bIsErrorLanguageSelected; //undo of AddToDictionary
Reference<XDictionary> m_xDictionary;
OUString m_sAddedWord; //move end of error - ::ChangeMarkedWord()
tools::Long m_nOffset;
// fdo#68794 set initial title for cases where no text has been processed // yet to show its language attributes
OUString sTitle = rParent.HasGrammarChecking() ? m_sTitleSpellingGrammar : m_sTitleSpelling;
m_xDialog->set_title(m_xDialog->strip_mnemonic(sTitle.replaceFirst("$LANGUAGE ($LOCATION)", "")));
// disable controls if service is missing
m_xDialog->set_sensitive(xSpell.is());
//InitHdl wants to use virtual methods, so it //can't be called during the ctor, so init //it on next event cycle post-ctor
m_pInitHdlEvent = Application::PostUserEvent(LINK(this, SpellDialog, InitHdl));
}
SpellDialog::~SpellDialog()
{ if (m_xOptionsDlg)
{
m_xOptionsDlg->response(RET_CANCEL);
m_xOptionsDlg.reset();
}
if (m_pInitHdlEvent)
Application::RemoveUserEvent(m_pInitHdlEvent); if (pImpl)
{ // save possibly modified user-dictionaries
Reference< XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() ); if (xDicList.is())
SaveDictionaries( xDicList );
m_xCheckGrammarCB->set_visible(rParent.HasGrammarChecking());
m_xExplainLink->set_visible(!m_xExplainLink->get_uri().isEmpty()); if (m_xExplainFT->get_label().isEmpty())
{
m_xExplainFT->hide();
m_xExplainLink->hide();
}
if (bOldShowExplain != m_xExplainLink->get_visible() || bOldShowGrammar != m_xCheckGrammarCB->get_visible())
m_xDialog->resize_to_request();
}
void SpellDialog::SpellContinue_Impl(std::unique_ptr<UndoChangeGroupGuard>* pGuard, bool bUseSavedSentence, bool bIgnoreCurrentError)
{ //initially or after the last error of a sentence MarkNextError will fail //then GetNextSentence() has to be called followed again by MarkNextError() //MarkNextError is not initially called if the UndoEdit mode is active bool bNextSentence = false; if (!m_xSentenceED)
{ return;
}
IMPL_LINK( SpellDialog, ExtClickHdl, weld::Button&, rBtn, void )
{ if (m_xOptionsPB.get() == &rBtn)
StartSpellOptDlg_Impl(); elseif (m_xAutoCorrPB.get() == &rBtn)
{ //get the currently selected wrong word
OUString sCurrentErrorText = m_xSentenceED->GetErrorText(); //get the wrong word from the XSpellAlternative
SpellErrorDescription aSpellErrorDescription; bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription); if (bSpellErrorDescription)
{
OUString sWrong(aSpellErrorDescription.sErrorText); //if the word has not been edited in the MultiLineEdit then //the current suggestion should be used //if it's not the 'no suggestions' entry if(sWrong == sCurrentErrorText &&
m_xSuggestionLB->get_sensitive() && m_xSuggestionLB->get_selected_index() != -1 &&
m_sNoSuggestionsST != m_xSuggestionLB->get_selected_text())
{
sCurrentErrorText = m_xSuggestionLB->get_selected_text();
} if(sWrong != sCurrentErrorText)
{
SvxPrepareAutoCorrect( sWrong, sCurrentErrorText );
LanguageType eLang = GetSelectedLang_Impl();
rParent.AddAutoCorrection( sWrong, sCurrentErrorText, eLang ); //correct the word immediately
ChangeHdl(*m_xAutoCorrPB);
}
}
}
}
//dots are sometimes part of the spelled word but they are not necessarily part of the replacement bool bEndsWithDot = aString != "." && aString.endsWith(".");
/* tdf#132822 start an undo group in ctor and close it in the dtor. This can then be passed to SpellContinue_Impl which can delete it in advance of its natural scope to force closing the undo group if SpellContinue_Impl needs to fetch a new paragraph and discard all undo information which can only be
done properly if there are no open undo groups */ class UndoChangeGroupGuard
{ private:
SentenceEditWindow_Impl& m_rSentenceED; public:
UndoChangeGroupGuard(SentenceEditWindow_Impl& rSentenceED)
: m_rSentenceED(rSentenceED)
{
m_rSentenceED.UndoActionStart(SPELLUNDO_CHANGE_GROUP);
}
~UndoChangeGroupGuard()
{
m_rSentenceED.UndoActionEnd();
}
};
IMPL_LINK( SpellDialog, DialogUndoHdl, SpellUndoAction_Impl&, rAction, void )
{ switch(rAction.GetId())
{ case SPELLUNDO_CHANGE_TEXTENGINE:
{ if(rAction.IsEnableChangePB())
m_xChangePB->set_sensitive(false); if(rAction.IsEnableChangeAllPB())
m_xChangeAllPB->set_sensitive(false);
} break; case SPELLUNDO_CHANGE_NEXTERROR:
{
m_xSentenceED->MoveErrorMarkTo(static_cast<sal_Int32>(rAction.GetOldErrorStart()), static_cast<sal_Int32>(rAction.GetOldErrorEnd()), false); if(rAction.IsErrorLanguageSelected())
{
UpdateBoxes_Impl();
}
} break; case SPELLUNDO_CHANGE_ADD_TO_DICTIONARY:
{ if(rAction.GetDictionary().is())
rAction.GetDictionary()->remove(rAction.GetAddedWord());
} break; case SPELLUNDO_MOVE_ERROREND :
{ if(rAction.GetOffset() != 0)
m_xSentenceED->MoveErrorEnd(rAction.GetOffset());
} break; case SPELLUNDO_UNDO_EDIT_MODE :
{ //refill the dialog with the currently spelled sentence - throw away all changes
SpellContinue_Impl(nullptr, true);
} break; case SPELLUNDO_ADD_IGNORE_RULE: //undo of ignored rules is not supported break;
}
}
void SpellDialog::Impl_Restore(bool bUseSavedSentence)
{ //clear the "ChangeAllList"
LinguMgr::GetChangeAllList()->clear(); //get a new sentence
m_xSentenceED->SetText(OUString());
m_xSentenceED->ResetModified(); //Resolves: fdo#39348 refill the dialog with the currently spelled sentence
SpellContinue_Impl(nullptr, bUseSavedSentence);
m_xIgnorePB->set_label(m_sIgnoreOnceST);
}
IMPL_LINK_NOARG(SpellDialog, IgnoreHdl, weld::Button&, void)
{ if (m_sResumeST == m_xIgnorePB->get_label())
{
Impl_Restore(false);
} else
{ //in case the error has been changed manually it has to be restored, // since the users choice now was to ignore the error
m_xSentenceED->RestoreCurrentError();
// the word is being ignored
SpellContinue_Impl(nullptr, false, true);
}
}
void SpellDialog::Close()
{ if (IsClosing()) return;
// We have to call ToggleChildWindow directly; calling SfxDispatcher's // Execute() does not work here when we are in a document with protected // section - in that case, the cursor can move from the editable field to // the protected area, and the slots get disabled because of // SfxDisableFlags::SwOnProtectedCursor (see FN_SPELL_GRAMMAR_DIALOG in .sdi). if (SfxViewFrame* pViewFrame = SfxViewFrame::Current())
pViewFrame->ToggleChildWindow(rParent.GetType());
}
IMPL_LINK_NOARG(SpellDialog, LanguageSelectHdl, weld::ComboBox&, void)
{ //If selected language changes, then add->list should be regenerated to //match
InitUserDicts();
//if currently an error is selected then search for alternatives for //this word and fill the alternatives ListBox accordingly
OUString sError = m_xSentenceED->GetErrorText();
m_xSuggestionLB->clear(); if (!sError.isEmpty())
{
LanguageType eLanguage = m_xLanguageLB->get_active_id();
Reference <XSpellAlternatives> xAlt = xSpell->spell( sError, static_cast<sal_uInt16>(eLanguage),
Sequence< PropertyValue >() ); if( xAlt.is() )
m_xSentenceED->SetAlternatives( xAlt ); else
{
m_xSentenceED->ChangeMarkedWord( sError, eLanguage );
SpellContinue_Impl();
}
int SpellDialog::InitUserDicts()
{ const LanguageType nLang = m_xLanguageLB->get_active_id();
// get list of dictionaries
Reference< XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() ); if (xDicList.is())
{ // add active, positive dictionary to dic-list (if not already done). // This is to ensure that there is at least on dictionary to which // words could be added.
Reference< XDictionary > xDic( LinguMgr::GetStandardDic() ); if (xDic.is())
xDic->setActive( true );
pImpl->aDics = xDicList->getDictionaries();
}
SvtLinguConfig aCfg;
// list suitable dictionaries bool bEnable = false;
m_xAddToDictMB->clear();
m_aDictIdToName.clear();
sal_uInt16 nItemId = 1; // menu items should be enumerated from 1 and not 0 for (auto& xDicTmp : pImpl->aDics)
{ if (!xDicTmp.is() || LinguMgr::GetIgnoreAllList() == xDicTmp) continue;
IMPL_LINK_NOARG(SpellDialog, CancelHdl, weld::Button&, void)
{ //apply changes and ignored text parts first - if there are any if (m_xSentenceED->IsModified())
{
rParent.ApplyChangedSentence(m_xSentenceED->CreateSpellPortions(), false);
}
Close();
}
void SpellDialog::ToplevelFocusChanged()
{ /* #i38338# * FIXME: LoseFocus and GetFocus are signals from vcl that * a window actually got/lost the focus, it never should be * forwarded from another window, that is simply wrong. * FIXME: overriding the virtual methods GetFocus and LoseFocus * in SpellDialogChildWindow by making them pure is at least questionable. * The only sensible thing would be to call the new Method differently, * e.g. DialogGot/LostFocus or so.
*/ if (!m_xDialog->get_visible() || bFocusLocked) return;
if (m_xDialog->has_toplevel_focus())
{ //notify the child window of the focus change
rParent.GetFocus();
} else
{ //notify the child window of the focus change
rParent.LoseFocus();
}
}
bool SpellDialog::GetNextSentence_Impl(std::unique_ptr<UndoChangeGroupGuard>* pGuard, bool bUseSavedSentence, bool bRecheck)
{ bool bRet = false; if(!bUseSavedSentence)
{ //apply changes and ignored text parts
rParent.ApplyChangedSentence(m_xSentenceED->CreateSpellPortions(), bRecheck);
}
m_xSentenceED->ResetIgnoreErrorsAt();
m_xSentenceED->ResetModified();
SpellPortions aSentence = bUseSavedSentence ? m_aSavedSentence : rParent.GetNextWrongSentence( bRecheck ); if(!bUseSavedSentence)
m_aSavedSentence = aSentence; bool bHasReplaced = false; while(!aSentence.empty())
{ //apply all changes that are already part of the "ChangeAllList" //returns true if the list still contains errors after the changes have been applied
if(!aSentence.empty())
{
OUStringBuffer sText; for (autoconst& elem : aSentence)
{ // hidden text has to be ignored if(!elem.bIsHidden)
sText.append(elem.sText);
} // tdf#132822 fire undo-stack UndoActionEnd to close undo stack because we're about to throw away the paragraph entirely if (pGuard)
pGuard->reset();
m_xSentenceED->SetText(sText.makeStringAndClear());
sal_Int32 nStartPosition = 0;
sal_Int32 nEndPosition = 0;
for (autoconst& elem : aSentence)
{ // hidden text has to be ignored if(!elem.bIsHidden)
{
nEndPosition += elem.sText.getLength(); if(elem.xAlternatives.is())
{
SpellErrorDescription aDesc( false, elem.xAlternatives->getWord(),
elem.xAlternatives->getLocale(), elem.xAlternatives->getAlternatives(), nullptr);
SfxGrabBagItem aSpellErrorDescription(EE_CHAR_GRABBAG,
std::map<OUString, css::uno::Any>{{ u"SpellErrorDescription"_ustr, uno::Any(aDesc.toSequence()) }});
m_xSentenceED->SetAttrib(aSpellErrorDescription, nStartPosition, nEndPosition);
} elseif(elem.bIsGrammarError )
{
beans::PropertyValues aProperties = elem.aGrammarError.aProperties;
OUString sFullCommentURL;
sal_Int32 i = 0; while ( sFullCommentURL.isEmpty() && i < aProperties.getLength() )
{ if ( aProperties[i].Name == "FullCommentURL" )
{
uno::Any aValue = aProperties[i].Value;
aValue >>= sFullCommentURL;
}
++i;
}
void SentenceEditWindow_Impl::DoScroll()
{ if (m_xEditView)
{ auto currentDocPos = m_xEditView->GetVisArea().Top(); auto nDiff = currentDocPos - m_xScrolledWindow->vadjustment_get_value(); // we expect SetScrollBarRange callback to be triggered by Scroll // to set where we ended up
m_xEditView->Scroll(0, nDiff);
}
}
void SentenceEditWindow_Impl::EditViewScrollStateChange()
{ // editengine height has changed or editview scroll pos has changed
SetScrollBarRange();
}
void SentenceEditWindow_Impl::SetScrollBarRange()
{
EditEngine *pEditEngine = GetEditEngine(); if (!pEditEngine) return; if (!m_xScrolledWindow) return;
EditView* pEditView = GetEditView(); if (!pEditView) return;
int nVUpper = pEditEngine->GetTextHeight(); int nVCurrentDocPos = pEditView->GetVisArea().Top(); const Size aOut(pEditView->GetOutputArea().GetSize()); int nVStepIncrement = aOut.Height() * 2 / 10; int nVPageIncrement = aOut.Height() * 8 / 10; int nVPageSize = aOut.Height();
/* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has effectively...
/*------------------------------------------------------------------------- The selection before inputting a key may have a range or not and it may be inside or outside of field or error attributes. A range may include the attribute partially, completely or together with surrounding text. It may also contain more than one attribute or no attribute at all. Depending on this starting conditions some actions are necessary: Attempts to delete a field are only allowed if the selection is the same as the field's selection. Otherwise the field has to be selected and the key input action has to be skipped. Input of text at the start of the field requires the field attribute to be corrected - it is not allowed to grow.
In case of errors the appending of text should grow the error attribute because that is what the user usually wants to do.
Backspace at the start of the attribute requires to find out if a field ends directly in front of the cursor position. In case of a field this attribute has to be selected otherwise the key input method is allowed.
All changes outside of the error attributes switch the dialog mode to a "Undo edit" state that removes all visible attributes and switches off further attribute checks. Undo in this restarts the dialog with a current sentence newly presented. All changes to the sentence are undone including the ones before the "Undo edit state" has been reached
We end up with 9 types of selection 1 (LEFT_NO) - no range, start of attribute - can also be 3 at the same time 2 (INSIDE_NO) - no range, inside of attribute 3 (RIGHT_NO) - no range, end of attribute - can also be 1 at the same time 4 (FULL) - range, same as attribute 5 (INSIDE_YES) - range, inside of the attribute 6 (BRACE)- range, from outside of the attribute to the inside or including the complete attribute and something outside, maybe more than one attribute 7 (OUTSIDE_NO) - no range, not at an attribute 8 (OUTSIDE_YES) - range, completely outside of all attributes
What has to be done depending on the attribute type involved possible actions: UE - Undo edit mode CO - Continue, no additional action is required FS - Field has to be completely selected EX - The attribute has to be expanded to include the added text
1 - backspace delete any other UE on field FS on error CO on field FS on error CO
2 - on field FS on error C 3 - backspace delete any other on field FS on error CO UE on field UE on error EX
if 1 and 3 happen to apply both then backspace and other handling is 1 delete is 3
4 - on field UE and on error CO 5 - on field FS and on error CO 6 - on field FS and on error UE 7 - UE 8 - UE
-----------------------------------------------------------------------*/ #define INVALID 0 #define LEFT_NO 1 #define INSIDE_NO 2 #define RIGHT_NO 3 #define FULL 4 #define INSIDE_YES 5 #define BRACE 6 #define OUTSIDE_NO 7 #define OUTSIDE_YES 8
//check previous position if this exists //that is a redundant in the case the attribute found above already is on the left cursor side //but it's o.k. for two errors/fields side by side if (nCursor)
{
--nCursor;
pBackAttrLeft = FindCharAttrib(nCursor, EE_CHAR_BKGCOLOR, aAttribList);
pErrorAttrLeft = FindCharAttrib(nCursor, EE_CHAR_GRABBAG, aAttribList);
bHasFieldLeft = pBackAttrLeft !=nullptr;
bHasErrorLeft = pErrorAttrLeft != nullptr;
++nCursor;
}
} //Here we have to determine if the error found is the one currently active bool bIsErrorActive = (pErrorAttr && pErrorAttr->nStart == m_nErrorStart) ||
(pErrorAttrLeft && pErrorAttrLeft->nStart == m_nErrorStart);
SAL_WARN_IF(
nSelectionType == INVALID, "cui.dialogs", "selection type not set");
sal_Int8 nAction = ACTION_CONTINUE; switch(nSelectionType)
{ // 1 - backspace delete any other // UE on field FS on error CO on field FS on error CO case LEFT_NO : if(bBackspace)
{
nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_UNDOEDIT; //to force the use of pBackAttrLeft
pBackAttr = nullptr;
} elseif(bDelete)
nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE; else
nAction = bHasError && !nCursor ? ACTION_CONTINUE :
bHasError ? ACTION_EXPAND : bHasErrorLeft ? ACTION_CONTINUE : ACTION_UNDOEDIT; break; // 2 - on field FS on error C case INSIDE_NO :
nAction = bHasField ? ACTION_SELECTFIELD :
bIsErrorActive ? ACTION_CONTINUE : ACTION_UNDOEDIT; break; // 3 - backspace delete any other // on field FS on error CO UE on field UE on error EX case RIGHT_NO : if(bBackspace)
nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_CONTINUE; elseif(bDelete)
nAction = bHasFieldLeft && bHasError ? ACTION_CONTINUE : ACTION_UNDOEDIT; else
nAction = bHasFieldLeft && bHasError ? ACTION_EXPAND :
bHasError ? ACTION_CONTINUE : bHasErrorLeft ? ACTION_EXPAND :ACTION_UNDOEDIT; break; // 4 - on field UE and on error CO case FULL :
nAction = ACTION_UNDOEDIT; break; // 5 - on field FS and on error CO case INSIDE_YES :
nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE; break; // 6 - on field FS and on error UE case BRACE :
nAction = bHasField ? ACTION_SELECTFIELD : ACTION_UNDOEDIT; break; // 7 - UE // 8 - UE case OUTSIDE_NO : case OUTSIDE_YES:
nAction = ACTION_UNDOEDIT; break;
} //save the current paragraph
sal_Int32 nCurrentLen = m_xEditEngine->GetText().getLength(); if (nAction != ACTION_SELECTFIELD)
{
m_xEditView->PostKeyEvent(rKeyEvt);
} else
{ const EECharAttrib* pCharAttr = pBackAttr ? pBackAttr : pBackAttrLeft; if (pCharAttr)
m_xEditView->SetSelection(ESelection(0, pCharAttr->nStart, 0, pCharAttr->nEnd));
} if(nAction == ACTION_EXPAND)
{
DBG_ASSERT(pErrorAttrLeft || pErrorAttr, "where is the error"); //text has been added on the right and only the 'error attribute has to be corrected if (pErrorAttrLeft)
{
SpellErrorDescription aSpellErrorDescription;
ExtractErrorDescription(*pErrorAttrLeft, aSpellErrorDescription);
std::unique_ptr<SfxPoolItem> xNewError(pErrorAttrLeft->pAttr->Clone());
sal_Int32 nStart = pErrorAttrLeft->nStart;
sal_Int32 nEnd = pErrorAttrLeft->nEnd + 1;
m_xEditEngine->RemoveAttribs(ESelection(0, nStart, 0, nEnd), false, EE_CHAR_GRABBAG);
SetAttrib(*xNewError, nStart, nEnd); //only active errors move the mark if (bIsErrorActive)
{ bool bGrammar = aSpellErrorDescription.bIsGrammarError;
MoveErrorMarkTo(nStart, nEnd, bGrammar);
}
} //text has been added on the left then the error attribute has to be expanded and the //field attribute on the right - if any - has to be contracted elseif (pErrorAttr)
{
SpellErrorDescription aSpellErrorDescription;
ExtractErrorDescription(*pErrorAttr, aSpellErrorDescription);
//determine the change
sal_Int32 nAddedChars = m_xEditEngine->GetText().getLength() - nCurrentLen;
std::unique_ptr<SfxPoolItem> xNewError(pErrorAttr->pAttr->Clone());
sal_Int32 nStart = pErrorAttr->nStart + nAddedChars;
sal_Int32 nEnd = pErrorAttr->nEnd + nAddedChars;
m_xEditEngine->RemoveAttribs(ESelection(0, nStart, 0, nEnd), false, EE_CHAR_GRABBAG);
nStart = pErrorAttr->nStart;
SetAttrib(*xNewError, nStart, nEnd); //only if the error is active the mark is moved here if (bIsErrorActive)
{ bool bGrammar = aSpellErrorDescription.bIsGrammarError;
MoveErrorMarkTo(nStart, nEnd, bGrammar);
}
xNewError.reset();
if (pBackAttrLeft)
{
std::unique_ptr<SfxPoolItem> xNewBack(pBackAttrLeft->pAttr->Clone());
sal_Int32 _nStart = pBackAttrLeft->nStart + nAddedChars;
sal_Int32 _nEnd = pBackAttrLeft->nEnd + nAddedChars;
m_xEditEngine->RemoveAttribs(ESelection(0, _nStart, 0, _nEnd), false, EE_CHAR_BKGCOLOR);
_nStart = pBackAttrLeft->nStart;
SetAttrib(*xNewBack, _nStart, _nEnd);
}
}
} elseif(nAction == ACTION_UNDOEDIT)
{
SetUndoEditMode(true);
} //make sure the error positions are correct after text changes //the old attribute may have been deleted //all changes inside of the current error leave the error attribute at the current //start position if (!IsUndoEditMode() && bIsErrorActive)
{
aAttribList.clear();
m_xEditEngine->GetCharAttribs(0, aAttribList); const EECharAttrib* pFontColor = FindCharAttrib(nCursor, EE_CHAR_COLOR, aAttribList); const EECharAttrib* pErrorAttrib = FindCharAttrib(m_nErrorStart, EE_CHAR_GRABBAG, aAttribList); if (pFontColor && pErrorAttrib)
{
m_nErrorStart = pFontColor->nStart;
m_nErrorEnd = pFontColor->nEnd; if (pErrorAttrib->nStart != m_nErrorStart || pErrorAttrib->nEnd != m_nErrorEnd)
{
std::unique_ptr<SfxPoolItem> xNewError(pErrorAttrib->pAttr->Clone());
assert(pErrorAttr);
m_xEditEngine->RemoveAttribs(ESelection(0, pErrorAttr->nStart, 0, pErrorAttr->nEnd), false, EE_CHAR_GRABBAG);
SetAttrib(*xNewError, m_nErrorStart, m_nErrorEnd);
}
}
} //this is not a modification anymore if(nAction != ACTION_SELECTFIELD && !m_bIsUndoEditMode)
CallModifyLink();
} else
bConsumed = m_xEditView->PostKeyEvent(rKeyEvt);
if (m_nErrorEnd >= nTextLen - 1) returnfalse; //if it's not already modified the modified flag has to be reset at the end of the marking bool bModified = IsModified(); bool bRet = false; const sal_Int32 nOldErrorStart = m_nErrorStart; const sal_Int32 nOldErrorEnd = m_nErrorEnd;
//create a cursor behind the end of the last error //- or at 0 at the start of the sentence
sal_Int32 nCursor(m_nErrorEnd ? m_nErrorEnd + 1 : 0);
//search for SpellErrorDescription
SpellErrorDescription aSpellErrorDescription;
//iterate over the text and search for the next error that maybe has //to be replace by a ChangeAllList replacement bool bGrammarError = false; while (nCursor < nTextLen)
{ const SpellErrorDescription* pSpellErrorDescription = nullptr; const EECharAttrib* pEECharAttrib = nullptr;
nCursor = std::max(nCursor, nMinPos); // move forward if possible
// maybe the error found here is already in the ChangeAllList and has to be replaced
Reference<XDictionary> xChangeAll = LinguMgr::GetChangeAllList();
Reference<XDictionaryEntry> xEntry;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.