/* -*- 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 .
*/
// for the UI: void Start_( SwEditShell *pSh, SwDocPositions eStart,
SwDocPositions eEnd ); void End_(bool bRestoreSelection = true);
};
// #i18881# to be able to identify the positions of the changed words // the content positions of each portion need to be saved struct SpellContentPosition
{
sal_Int32 nLeft;
sal_Int32 nRight;
};
class SwHyphIter : public SwLinguIter
{ // With that we save a GetFrame() in Hyphenate //TODO: does it actually matter? const SwTextNode *m_pLastNode;
SwTextFrame *m_pLastFrame; friend SwTextFrame * sw::SwHyphIterCacheLastTextFrame(SwTextNode const * pNode, const sw::Creator& rCreator);
void SwLinguIter::End_(bool bRestoreSelection)
{ if (!m_pSh) return;
OSL_ENSURE(m_oEnd, "SwLinguIter::End_ without end?"); if(bRestoreSelection)
{ while (m_nCursorCount--)
m_pSh->Pop(SwCursorShell::PopMode::DeleteCurrent);
// This method is the origin of SwEditShell::SpellContinue()
uno::Any SwSpellIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
{ //!! //!! Please check SwConvIter also when modifying this //!!
// call function to find next text portion to be converted
uno::Reference< linguistic2::XSpellChecker1 > xEmpty;
pMySh->GetDoc()->Spell(*pMySh->GetCursor(), xEmpty, pPageCnt, pPageSt, false,
pMySh->GetLayout(), &m_rArgs)
>>= aConvText;
void SwHyphIter::ShowSelection()
{
SwEditShell *pMySh = GetSh(); if( pMySh )
{
pMySh->StartAction(); // Caution! Due to EndAction() formatting is started which can lead to the fact that new // words are added to/set in the Hyphenator. Thus: save!
pMySh->EndAction();
}
}
// nothing to do (at least not in the way as in the "else" part)
m_bOldIdle = pShell->GetViewOptions()->IsIdle();
pShell->GetViewOptions()->SetIdle( false );
Start_( pShell, eStart, eEnd );
}
constbool bAuto = IsAuto();
uno::Reference< XHyphenatedWord > xHyphWord; bool bGoOn = false; do {
SwPaM *pCursor; do {
OSL_ENSURE( m_oEnd, "SwHyphIter::Continue without Start?" );
pCursor = pMySh->GetCursor(); if ( !pCursor->HasMark() )
pCursor->SetMark(); if ( *pCursor->GetPoint() < *pCursor->GetMark() )
{
pCursor->Exchange();
pCursor->SetMark();
}
if ( *pCursor->End() <= *m_oEnd )
{
*pCursor->GetMark() = *m_oEnd;
// Do we need to break the word at the current cursor position? const Point aCursorPos( pMySh->GetCharRect().Pos() );
xHyphWord = pMySh->GetDoc()->Hyphenate( pCursor, aCursorPos,
pPageCnt, pPageSt );
}
bool SwEditShell::HasLastSentenceGotGrammarChecked()
{ bool bTextWasGrammarChecked = false; if (g_pSpellIter)
{ const svx::SpellPortions& aLastPortions( g_pSpellIter->GetLastPortions() ); for (size_t i = 0; i < aLastPortions.size() && !bTextWasGrammarChecked; ++i)
{ // bIsGrammarError is also true if the text was only checked but no // grammar error was found. (That is if a ProofreadingResult was obtained in // SwDoc::Spell and in turn bIsGrammarError was set in SwSpellIter::CreatePortion) if (aLastPortions[i].bIsGrammarError)
bTextWasGrammarChecked = true;
}
} return bTextWasGrammarChecked;
}
// do not spell if interactive spelling is active elsewhere if (!pConvArgs && !g_pSpellIter)
{
g_pSpellIter = new SwSpellIter;
pLinguIter = g_pSpellIter;
} // do not do text conversion if it is active elsewhere if (pConvArgs && !g_pConvIter)
{
g_pConvIter = new SwConvIter( *pConvArgs );
pLinguIter = g_pConvIter;
}
if (pLinguIter)
{
SwCursor* pSwCursor = GetCursor();
OSL_ENSURE( pConvArgs || g_pSpellIter, "SpellIter missing" );
OSL_ENSURE( !pConvArgs || g_pConvIter, "ConvIter missing" ); //JP 18.07.95: prevent displaying selection on error messages. NO StartAction so that all // Paints are also disabled.
++mnStartAction;
OUString aRet;
uno::Reference< uno::XInterface > xRet; if (pConvArgs)
{
g_pConvIter->Continue( pPageCnt, pPageSt ) >>= aRet;
aRes <<= aRet;
} else
{
g_pSpellIter->Continue( pPageCnt, pPageSt ) >>= xRet;
aRes <<= xRet;
}
--mnStartAction;
if( !aRet.isEmpty() || xRet.is() )
{ // then make awt::Selection again visible
StartAction();
EndAction();
} return aRes;
}
/* Interactive Hyphenation (BP 10.03.93) * * 1) HyphStart * - Revoke all Selections * - Save current Cursor * - if no selections existent: * - create new selection reaching until document end * 2) HyphContinue * - add nLastHyphLen onto SelectionStart * - iterate over all selected areas * - pDoc->Hyphenate() iterates over all Nodes of a selection * - pTextNode->Hyphenate() calls SwTextFrame::Hyphenate of the EditShell * - SwTextFrame:Hyphenate() iterates over all rows of the Pam * - LineIter::Hyphenate() sets the Hyphenator and the Pam based on * the to be separated word. * - Returns true if there is a hyphenation and false if the Pam is processed. * - If true, show the selected word and set nLastHyphLen. * - If false, delete current selection and select next one. Returns HYPH_OK if no more. * 3) InsertSoftHyph (might be called by UI if needed) * - Place current cursor and add attribute. * 4) HyphEnd * - Restore old cursor, EndAction
*/ void SwEditShell::HyphStart( SwDocPositions eStart, SwDocPositions eEnd )
{ // do not hyphenate if interactive hyphenation is active elsewhere if (!g_pHyphIter)
{
g_pHyphIter = new SwHyphIter;
g_pHyphIter->Start( this, eStart, eEnd );
}
}
/// @returns HYPH_CONTINUE if hyphenation, HYPH_OK if selected area was processed.
uno::Reference< uno::XInterface >
SwEditShell::HyphContinue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
{
assert(g_pHyphIter); if (g_pHyphIter->GetSh() != this) return nullptr;
if( pPageCnt && !*pPageCnt && !*pPageSt )
{
sal_uInt16 nEndPage = GetLayout()->GetPageNum();
nEndPage += nEndPage * 10 / 100; if( nEndPage > 14 )
{
*pPageCnt = nEndPage;
::StartProgress( STR_STATSTR_HYPHEN, 0, nEndPage, GetDoc()->GetDocShell());
} else// here we once and for all suppress StatLineStartPercent
*pPageSt = 1;
}
//JP 18.07.95: prevent displaying selection on error messages. NO StartAction so that all // Paints are also disabled.
++mnStartAction;
uno::Reference< uno::XInterface > xRet;
g_pHyphIter->Continue( pPageCnt, pPageSt ) >>= xRet;
--mnStartAction;
if( xRet.is() )
g_pHyphIter->ShowSelection();
return xRet;
}
/** Insert soft hyphen * * @param nHyphPos Offset in the to be separated word
*/ void SwEditShell::InsertSoftHyph( const sal_Int32 nHyphPos )
{
assert(g_pHyphIter);
g_pHyphIter->InsertSoftHyph( nHyphPos );
}
/// ignore hyphenation void SwEditShell::HyphIgnore()
{
assert(g_pHyphIter); //JP 18.07.95: prevent displaying selection on error messages. NO StartAction so that all // Paints are also disabled.
++mnStartAction;
g_pHyphIter->Ignore();
--mnStartAction;
g_pHyphIter->ShowSelection();
}
void SwEditShell::HandleCorrectionError(const OUString& aText, SwPosition aPos, sal_Int32 nBegin,
sal_Int32 nLen, const Point* pPt,
SwRect& rSelectRect)
{ // save the start and end positions of the line and the starting point
SwNode const& rNode(GetCursor()->GetPoint()->GetNode());
Push();
LeftMargin(); const sal_Int32 nLineStart = &rNode == &GetCursor()->GetPoint()->GetNode()
? GetCursor()->GetPoint()->GetContentIndex()
: 0;
RightMargin(); const sal_Int32 nLineEnd = &rNode == &GetCursor()->GetPoint()->GetNode()
? GetCursor()->GetPoint()->GetContentIndex()
: rNode.GetTextNode()->Len();
Pop(PopMode::DeleteCurrent);
// make sure the selection build later from the data below does // not "in word" character to the left and right in order to // preserve those. Therefore count those "in words" in order to // modify the selection accordingly. const sal_Unicode* pChar = aText.getStr();
sal_Int32 nLeft = 0; while (*pChar++ == CH_TXTATR_INWORD)
++nLeft;
pChar = aText.getLength() ? aText.getStr() + aText.getLength() - 1 : nullptr;
sal_Int32 nRight = 0; while (pChar && *pChar-- == CH_TXTATR_INWORD)
++nRight;
aPos.SetContent( nBegin + nLeft );
SwPaM* pCursor = GetCursor();
*pCursor->GetPoint() = std::move(aPos);
pCursor->SetMark();
ExtendSelection( true, nLen - nLeft - nRight ); // don't determine the rectangle in the current line const sal_Int32 nWordStart = (nBegin + nLeft) < nLineStart ? nLineStart : nBegin + nLeft; // take one less than the line end - otherwise the next line would be calculated const sal_Int32 nWordEnd = (nBegin + nLen - nLeft - nRight) > nLineEnd
? nLineEnd : (nBegin + nLen - nLeft - nRight);
Push();
pCursor->DeleteMark();
SwPosition& rPtPos = *GetCursor()->GetPoint();
rPtPos.SetContent(nWordStart);
SwRect aStartRect;
SwCursorMoveState aState;
aState.m_bRealWidth = true;
SwContentNode* pContentNode = pCursor->GetPointContentNode();
std::pair<Point, bool> tmp; if (pPt)
{
tmp.first = *pPt;
tmp.second = false;
}
SwContentFrame *const pContentFrame = pContentNode->getLayoutFrame(GetLayout(), pCursor->GetPoint(), pPt ? &tmp : nullptr);
/** Get a list of potential corrections for misspelled word. * * If empty, word is unknown but there are no corrections available. * If NULL then the word is not misspelled but correct. * * @brief SwEditShell::GetCorrection * @return list or NULL pointer
*/
uno::Reference< XSpellAlternatives >
SwEditShell::GetCorrection( const Point* pPt, SwRect& rSelectRect )
{
uno::Reference< XSpellAlternatives > xSpellAlt;
uno::Reference< XSpellChecker1 > xSpell( ::GetSpellChecker() ); if( xSpell.is() )
{
LanguageType eActLang = pNode->GetLang( nBegin, nLen ); if( xSpell->hasLanguage( static_cast<sal_uInt16>(eActLang) ))
{ // restrict the maximal number of suggestions displayed // in the context menu. // Note: That could of course be done by clipping the // resulting sequence but the current third party // implementations result differs greatly if the number of // suggestions to be returned gets changed. Statistically // it gets much better if told to return e.g. only 7 strings // than returning e.g. 16 suggestions and using only the // first 7. Thus we hand down the value to use to that // implementation here by providing an additional parameter.
Sequence< PropertyValue > aPropVals ( { comphelper::makePropertyValue( UPN_MAX_NUMBER_OF_SUGGESTIONS, sal_Int16(7)) } );
bool SwEditShell::GetGrammarCorrection(
linguistic2::ProofreadingResult /*out*/ &rResult, // the complete result
sal_Int32 /*out*/ &rErrorPosInText, // offset of error position in string that was grammar checked...
sal_Int32 /*out*/ &rErrorIndexInResult, // index of error in rResult.aGrammarErrors
uno::Sequence< OUString > /*out*/ &rSuggestions, // suggestions to be used for the error found const Point *pPt, SwRect &rSelectRect )
{ bool bRes = false;
if( IsTableMode() ) return bRes;
SwPaM* pCursor = GetCursor();
SwPosition aPos( *pCursor->GetPoint() );
SwCursorMoveState eTmpState( CursorMoveState::SetOnlyText );
eTmpState.m_bPosMatchesBounds = true; // treat last half of character same as first half
SwTextNode *pNode = nullptr;
SwGrammarMarkUp *pWrong = nullptr; if (pPt && GetLayout()->GetModelPositionForViewPoint( &aPos, *const_cast<Point*>(pPt), &eTmpState ))
pNode = aPos.GetNode().GetTextNode(); if (nullptr == pNode)
pNode = pCursor->GetPointNode().GetTextNode(); if (nullptr != pNode)
pWrong = pNode->GetGrammarCheck(); if (nullptr != pWrong && !pNode->IsInProtectSect())
{
sal_Int32 nBegin = aPos.GetContentIndex();
sal_Int32 nLen = 1; if (pWrong->InWrongWord(nBegin, nLen))
{ const OUString aText(pNode->GetText().copy(nBegin, nLen));
// get suggestions to use for the specific error position
rSuggestions.realloc( 0 ); // return suggestions for first error that includes the given error position auto pError = std::find_if(std::cbegin(rResult.aErrors), std::cend(rResult.aErrors),
[rErrorPosInText, nLen](const linguistic2::SingleProofreadingError &rError) { return rError.nErrorStart <= rErrorPosInText
&& rErrorPosInText + nLen <= rError.nErrorStart + rError.nErrorLength
&& (rError.aSuggestions.hasElements() || !rError.aShortComment.isEmpty()); }); if (pError != std::cend(rResult.aErrors))
{
rSuggestions = pError->aSuggestions;
rErrorIndexInResult = static_cast<sal_Int32>(std::distance(std::cbegin(rResult.aErrors), pError));
}
}
// make Selection visible - this should simply move the // cursor to the end of the sentence
StartAction();
EndAction(); return bRet;
}
///make SpellIter start with the current sentence when called next time void SwEditShell::PutSpellingToSentenceStart()
{
OSL_ENSURE( g_pSpellIter, "SpellIter missing" ); if (!g_pSpellIter) return;
g_pSpellIter->ToSentenceStart();
}
void SwEditShell::MoveContinuationPosToEndOfCheckedSentence()
{ // give hint that continuation position for spell/grammar checking is // at the end of this sentence if (g_pSpellIter)
{
g_pSpellIter->m_oCurr.emplace( *g_pSpellIter->m_oCurrX );
}
}
void SwEditShell::ApplyChangedSentence(const svx::SpellPortions& rNewPortions, bool bRecheck)
{ // Note: rNewPortions.size() == 0 is valid and happens when the whole // sentence got removed in the dialog
OSL_ENSURE( g_pSpellIter, "SpellIter missing" ); if (!g_pSpellIter ||
g_pSpellIter->GetLastPortions().empty()) // no portions -> no text to be changed return;
const SpellPortions& rLastPortions = g_pSpellIter->GetLastPortions(); const SpellContentPositions rLastPositions = g_pSpellIter->GetLastPositions();
OSL_ENSURE(!rLastPortions.empty() &&
rLastPortions.size() == rLastPositions.size(), "last vectors of spelling results are not set or not equal");
// iterate over the new portions, beginning at the end to take advantage of the previously // saved content positions
SwPaM *pCursor = GetCursor(); // save cursor position (which should be at the end of the current sentence) // for later restoration
Push();
sal_uInt32 nRedlinePortions = lcl_CountRedlines(rLastPortions); if((rLastPortions.size() - nRedlinePortions) == rNewPortions.size())
{
OSL_ENSURE( !rNewPortions.empty(), "rNewPortions should not be empty here" );
OSL_ENSURE( !rLastPortions.empty(), "rLastPortions should not be empty here" );
OSL_ENSURE( !rLastPositions.empty(), "rLastPositions should not be empty here" );
// the simple case: the same number of elements on both sides // each changed element has to be applied to the corresponding source element
svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.end();
SpellPortions::const_iterator aCurrentOldPortion = rLastPortions.end();
SpellContentPositions::const_iterator aCurrentOldPosition = rLastPositions.end(); do
{
--aCurrentNewPortion;
--aCurrentOldPortion;
--aCurrentOldPosition; //jump over redline portions while(aCurrentOldPortion->bIsHidden)
{ if (aCurrentOldPortion != rLastPortions.begin() &&
aCurrentOldPosition != rLastPositions.begin())
{
--aCurrentOldPortion;
--aCurrentOldPosition;
} else
{
OSL_FAIL("ApplyChangedSentence: iterator positions broken" ); break;
}
} if ( !pCursor->HasMark() )
pCursor->SetMark();
pCursor->GetPoint()->SetContent( aCurrentOldPosition->nLeft );
pCursor->GetMark()->SetContent( aCurrentOldPosition->nRight );
sal_uInt16 nScriptType = SvtLanguageOptions::GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage );
sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE; switch(nScriptType)
{ case css::i18n::ScriptType::ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break; case css::i18n::ScriptType::COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
} if(aCurrentNewPortion->sText != aCurrentOldPortion->sText)
{ // change text ... // ... and apply language if necessary if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
SetAttrItem( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId) );
// if there is a comment inside the original word, don't delete it: // but keep it at the end of the replacement
ReplaceKeepComments(aCurrentNewPortion->sText);
} elseif(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
{ // apply language
SetAttrItem( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId) );
} elseif( aCurrentNewPortion->bIgnoreThisError )
{ // add the 'ignore' markup to the TextNode's grammar ignore markup list
IgnoreGrammarErrorAt( *pCursor );
OSL_FAIL("TODO: add ignore mark to text node");
}
} while(aCurrentNewPortion != rNewPortions.begin());
} else
{
OSL_ENSURE( !rLastPositions.empty(), "rLastPositions should not be empty here" );
// delete the sentence completely
mxDoc->getIDocumentContentOperations().DeleteAndJoin(*pCursor); for(constauto& rCurrentNewPortion : rNewPortions)
{ // set the language attribute
SvtScriptType nScriptType = GetScriptType();
sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE; switch(nScriptType)
{ case SvtScriptType::ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break; case SvtScriptType::COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break; default: break;
}
SfxItemSet aSet(GetAttrPool(), nLangWhichId, nLangWhichId);
GetCurAttr( aSet ); const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId)); if(rLang.GetLanguage() != rCurrentNewPortion.eLanguage)
SetAttrItem( SvxLanguageItem(rCurrentNewPortion.eLanguage, nLangWhichId) ); // insert the new string
mxDoc->getIDocumentContentOperations().InsertString(*pCursor, rCurrentNewPortion.sText);
// set the cursor to the end of the inserted string
*pCursor->Start() = *pCursor->End();
}
}
// restore cursor to the end of the sentence // (will work also if the sentence length has changed, // since cursors get updated automatically!)
Pop(PopMode::DeleteCurrent);
// collapse cursor to the end of the modified sentence
*pCursor->Start() = *pCursor->End(); if (bRecheck)
{ // in grammar check the current sentence has to be checked again
GoStartSentence();
} // set continuation position for spell/grammar checking to the end of this sentence
g_pSpellIter->m_oCurr.emplace( *pCursor->Start() );
if(xSpellRet.is() || bGrammarErrorFound)
{ // an error has been found // To fill the spell portions the beginning of the sentence has to be found
SwPaM *pCursor = pMySh->GetCursor(); // set the mark to the right if necessary if ( *pCursor->GetPoint() > *pCursor->GetMark() )
pCursor->Exchange(); // the cursor has to be collapsed on the left to go to the start of the sentence - if sentence ends inside of the error
pCursor->DeleteMark();
pCursor->SetMark(); bool bStartSent = pMySh->GoStartSentence();
SpellContentPositions aDeletedRedlines = lcl_CollectDeletedRedlines(pMySh); if(bStartSent)
{ // create a portion from the start part
AddPortion(nullptr, nullptr, aDeletedRedlines);
} // Set the cursor to the error already found
*pCursor->GetPoint() = *m_oCurrX;
*pCursor->GetMark() = *m_oCurr;
AddPortion(xSpellRet, &aGrammarResult, aDeletedRedlines);
// save the end position of the error to continue from here
SwPosition aSaveStartPos = *pCursor->End(); // determine the end of the current sentence if ( *pCursor->GetPoint() < *pCursor->GetMark() )
pCursor->Exchange(); // again collapse to start marking after the end of the error
pCursor->DeleteMark();
pCursor->SetMark();
lcl_CutRedlines( aDeletedRedlines, pMySh ); // save the 'global' end of the spellchecking const SwPosition aSaveEndPos = *m_oEnd; // set the sentence end as 'local' end
m_oEnd.emplace( *pCursor->End() );
*pCursor->GetPoint() = aSaveStartPos;
*pCursor->GetMark() = *m_oEnd; // now the rest of the sentence has to be searched for errors // for each error the non-error text between the current and the last error has // to be added to the portions - if necessary broken into same-language-portions if( !bGrammarErrorFound ) //in grammar check there's only one error returned
{ do
{
xSpellRet = nullptr; // don't search for grammar errors here anymore!
pMySh->GetDoc()->Spell(*pCursor, m_xSpeller, nullptr, nullptr, false,
pMySh->GetLayout())
>>= xSpellRet; if ( *pCursor->GetPoint() > *pCursor->GetMark() )
pCursor->Exchange();
m_oCurr.emplace( *pCursor->GetPoint() );
m_oCurrX.emplace( *pCursor->GetMark() );
// if an error has been found go back to the text preceding the error if(xSpellRet.is())
{
*pCursor->GetPoint() = aSaveStartPos;
*pCursor->GetMark() = *m_oCurr;
} // add the portion
AddPortion(nullptr, nullptr, aDeletedRedlines);
if(xSpellRet.is())
{
*pCursor->GetPoint() = *m_oCurr;
*pCursor->GetMark() = *m_oCurrX;
AddPortion(xSpellRet, nullptr, aDeletedRedlines); // move the cursor to the end of the error string
*pCursor->GetPoint() = *m_oCurrX; // and save the end of the error as new start position
aSaveStartPos = *m_oCurrX; // and the end of the sentence
*pCursor->GetMark() = *m_oEnd;
} // if the end of the sentence has already been reached then break here if(*m_oCurrX >= *m_oEnd) break;
} while(xSpellRet.is());
} else
{ // go to the end of sentence as the grammar check returned it // at this time the Point is behind the grammar error // and the mark points to the sentence end as if ( *pCursor->GetPoint() < *pCursor->GetMark() )
pCursor->Exchange();
}
// the part between the last error and the end of the sentence has to be added
*pMySh->GetCursor()->GetPoint() = *m_oEnd; if(*m_oCurrX < *m_oEnd)
{
AddPortion(nullptr, nullptr, aDeletedRedlines);
} // set the shell cursor to the end of the sentence to prevent a visible selection
*pCursor->GetMark() = *m_oEnd; if( !bIsGrammarCheck )
{ // set the current position to the end of the sentence
m_oCurr.emplace( *m_oEnd );
} // restore the 'global' end
m_oEnd.emplace( aSaveEndPos );
rPortions = m_aLastPortions;
bRet = true;
} else
{ // if no error could be found the selection has to be corrected - at least if it's not in the body
*pMySh->GetCursor()->GetPoint() = *m_oEnd;
pMySh->GetCursor()->DeleteMark();
}
if(xAlt.is() || pGrammarResult != nullptr)
{
CreatePortion(xAlt, pGrammarResult, false, false);
} else
{
SwPaM *pCursor = GetSh()->GetCursor(); if ( *pCursor->GetPoint() > *pCursor->GetMark() )
pCursor->Exchange(); // save the start and end positions
SwPosition aStart(*pCursor->GetPoint());
SwPosition aEnd(*pCursor->GetMark()); // iterate over the text to find changes in language // set the mark equal to the point
*pCursor->GetMark() = aStart;
SwTextNode* pTextNode = pCursor->GetPointNode().GetTextNode();
LanguageType eStartLanguage = lcl_GetLanguage(*GetSh());
SpellContentPosition aNextRedline = lcl_FindNextDeletedRedline(
rDeletedRedlines, aStart.GetContentIndex() ); if( aNextRedline.nLeft == aStart.GetContentIndex() )
{ // select until the end of the current redline const sal_Int32 nEnd = aEnd.GetContentIndex() < aNextRedline.nRight ?
aEnd.GetContentIndex() : aNextRedline.nRight;
pCursor->GetPoint()->SetContent( nEnd );
CreatePortion(xAlt, pGrammarResult, false, true);
aStart = *pCursor->End(); // search for next redline
aNextRedline = lcl_FindNextDeletedRedline(
rDeletedRedlines, aStart.GetContentIndex() );
} while(*pCursor->GetPoint() < aEnd)
{ // #125786 in table cell with fixed row height the cursor might not move forward if(!GetSh()->Right(1, SwCursorSkipMode::Cells)) break;
bool bField = false; // read the character at the current position to check if it's a field
sal_Unicode const cChar =
pTextNode->GetText()[pCursor->GetMark()->GetContentIndex()]; if( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar)
{ const SwTextAttr* pTextAttr = pTextNode->GetTextAttrForCharAt(
pCursor->GetMark()->GetContentIndex() ); const sal_uInt16 nWhich = pTextAttr
? pTextAttr->Which()
: RES_TXTATR_END; switch (nWhich)
{ case RES_TXTATR_FIELD: case RES_TXTATR_ANNOTATION: case RES_TXTATR_FTN: case RES_TXTATR_FLYCNT:
bField = true; break;
}
} elseif (cChar == CH_TXT_ATR_FORMELEMENT)
{
SwPosition aPos(*pCursor->GetMark());
bField = pMySh->GetDoc()->getIDocumentMarkAccess()->getDropDownFor(aPos);
}
LanguageType eCurLanguage = lcl_GetLanguage(*GetSh()); bool bRedline = aNextRedline.nLeft == pCursor->GetPoint()->GetContentIndex(); // create a portion if the next character // - is a field, // - is at the beginning of a deleted redline // - has a different language if(bField || bRedline || eCurLanguage != eStartLanguage)
{
eStartLanguage = eCurLanguage; // go one step back - the cursor currently selects the first character // with a different language // in the case of redlining it's different if(eCurLanguage != eStartLanguage || bField)
*pCursor->GetPoint() = *pCursor->GetMark(); // set to the last start
*pCursor->GetMark() = aStart; // create portion should only be called if a selection exists // there's no selection if there's a field at the beginning if(*pCursor->Start() != *pCursor->End())
CreatePortion(xAlt, pGrammarResult, false, false);
aStart = *pCursor->End(); // now export the field - if there is any if(bField)
{
*pCursor->GetMark() = *pCursor->GetPoint();
GetSh()->Right(1, SwCursorSkipMode::Cells);
CreatePortion(xAlt, pGrammarResult, true, false);
aStart = *pCursor->End();
}
} // if a redline start then create a portion for it if(bRedline)
{
*pCursor->GetMark() = *pCursor->GetPoint(); // select until the end of the current redline const sal_Int32 nEnd = aEnd.GetContentIndex() < aNextRedline.nRight ?
aEnd.GetContentIndex() : aNextRedline.nRight;
pCursor->GetPoint()->SetContent( nEnd );
CreatePortion(xAlt, pGrammarResult, false, true);
aStart = *pCursor->End(); // search for next redline
aNextRedline = lcl_FindNextDeletedRedline(
rDeletedRedlines, aStart.GetContentIndex() );
}
*pCursor->GetMark() = *pCursor->GetPoint();
}
pCursor->SetMark();
*pCursor->GetMark() = std::move(aStart);
CreatePortion(xAlt, pGrammarResult, false, false);
}
}
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.