/* -*- 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 .
*/
#include <hintids.hxx>
#include <fmtinfmt.hxx>
#include <editsh.hxx>
#include <doc.hxx>
#include <pam.hxx>
#include <unocrsr.hxx>
#include <txatbase.hxx>
#include <txtfrm.hxx>
#include <ndtxt.hxx>
#include <acorrect.hxx>
#include <shellio.hxx>
#include <swundo.hxx>
#include <viscrs.hxx>
#include <com/sun/star/linguistic2/XHyphenator.hpp>
#include <com/sun/star/linguistic2/XHyphenatedWord.hpp>
#include <osl/diagnose.h>
#include <svl/numformat.hxx>
#include <editeng/acorrcfg.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <rootfrm.hxx>
using namespace ::com::sun::star;
namespace {
class PaMIntoCursorShellRing
{
SwPaM &m_rDelPam, &m_rCursor;
SwPaM* m_pPrevDelPam;
SwPaM* m_pPrevCursor;
static void RemoveFromRing( SwPaM& rPam, SwPaM const * pPrev );
public:
PaMIntoCursorShellRing( SwCursorShell& rSh, SwPaM& rCursor, SwPaM& rPam );
~PaMIntoCursorShellRing();
};
}
PaMIntoCursorShellRing::PaMIntoCursorShellRing(SwCursorShell& rCSh, SwPaM& rShCursor, SwPaM& rPam)
: m_rDelPam(rPam)
, m_rCursor(rShCursor)
{
SwPaM* pShCursor = rCSh.GetCursor_();
m_pPrevDelPam = m_rDelPam.GetPrev();
m_pPrevCursor = m_rCursor.GetPrev();
m_rDelPam.GetRingContainer().merge(pShCursor->GetRingContainer());
m_rCursor.GetRingContainer().merge(pShCursor->GetRingContainer());
}
PaMIntoCursorShellRing::~PaMIntoCursorShellRing()
{
// and take out the Pam again:
RemoveFromRing(m_rDelPam, m_pPrevDelPam);
RemoveFromRing(m_rCursor, m_pPrevCursor);
}
void PaMIntoCursorShellRing::RemoveFromRing( SwPaM& rPam, SwPaM const * pPrev )
{
SwPaM* p;
SwPaM* pNext = &rPam;
do {
p = pNext;
pNext = p->GetNext();
p->MoveTo( &rPam );
} while( p != pPrev );
}
SwAutoCorrDoc::SwAutoCorrDoc( SwEditShell& rEditShell, SwPaM& rPam,
sal_Unicode cIns )
: m_rEditSh( rEditShell ), m_rCursor( rPam )
, m_nEndUndoCounter(0)
, m_bUndoIdInitialized( cIns == 0 )
{
}
SwAutoCorrDoc::~SwAutoCorrDoc()
{
for (int i = 0; i < m_nEndUndoCounter; ++i)
{
m_rEditSh.EndUndo();
}
}
void SwAutoCorrDoc::DeleteSel( SwPaM& rDelPam )
{
// this should work with plain SwPaM as well because start and end
// are always in same node, but since there is GetRanges already...
std::vector<std::shared_ptr<SwUnoCursor>> ranges;
if (sw::GetRanges(ranges, *m_rEditSh.GetDoc(), rDelPam))
{
DeleteSelImpl(rDelPam);
}
else
{
for (auto const& pCursor : ranges)
{
DeleteSelImpl(*pCursor);
}
}
}
void SwAutoCorrDoc::DeleteSelImpl(SwPaM & rDelPam)
{
SwDoc* pDoc = m_rEditSh.GetDoc();
if( pDoc->IsAutoFormatRedline() )
{
// so that also the DelPam be moved, include it in the
// Shell-Cursr-Ring !!
// ??? is that really necessary - this should never join nodes, so Update should be enough?
// PaMIntoCursorShellRing aTmp( rEditSh, rCursor, rDelPam );
assert(rDelPam.GetPoint()->GetNode() == rDelPam.GetMark()->GetNode());
pDoc->getIDocumentContentOperations().DeleteAndJoin( rDelPam );
}
else
{
pDoc->getIDocumentContentOperations().DeleteRange( rDelPam );
}
}
bool SwAutoCorrDoc::Delete( sal_Int32 nStt, sal_Int32 nEnd )
{
SwTextNode const*const pTextNd = m_rCursor.GetPointNode().GetTextNode();
SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
pTextNd->getLayoutFrame(m_rEditSh.GetLayout())));
assert(pFrame);
SwPaM aSel(pFrame->MapViewToModelPos(TextFrameIndex(nStt)),
pFrame->MapViewToModelPos(TextFrameIndex(nEnd)));
DeleteSel( aSel );
if( m_bUndoIdInitialized )
m_bUndoIdInitialized = true;
return true;
}
bool SwAutoCorrDoc::Insert( sal_Int32 nPos, const OUString& rText )
{
SwTextNode const*const pTextNd = m_rCursor.GetPointNode().GetTextNode();
SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
pTextNd->getLayoutFrame(m_rEditSh.GetLayout())));
assert(pFrame);
SwPaM aPam(pFrame->MapViewToModelPos(TextFrameIndex(nPos)));
m_rEditSh.GetDoc()->getIDocumentContentOperations().InsertString( aPam, rText );
if( !m_bUndoIdInitialized )
{
m_bUndoIdInitialized = true;
if( 1 == rText.getLength() )
{
m_rEditSh.StartUndo( SwUndoId::AUTOCORRECT );
++m_nEndUndoCounter;
}
}
return true;
}
bool SwAutoCorrDoc::Replace( sal_Int32 nPos, const OUString& rText )
{
return ReplaceRange( nPos, rText.getLength(), rText );
}
bool SwAutoCorrDoc::ReplaceRange( sal_Int32 nPos, sal_Int32 nSourceLength, const OUString& rText )
{
assert(nSourceLength == 1); // sw_redlinehide: this is currently the case,
// and ensures that the replace range cannot *contain* delete redlines,
// so we don't need something along the lines of:
// if (sw::GetRanges(ranges, *rEditSh.GetDoc(), aPam))
// ReplaceImpl(...)
// else
// ReplaceImpl(ranges.begin())
// for (ranges.begin() + 1; ranges.end(); )
// DeleteImpl(*it)
SwTextNode * const pNd = m_rCursor.GetPointNode().GetTextNode();
if ( !pNd )
{
return false;
}
SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
pNd->getLayoutFrame(m_rEditSh.GetLayout())));
assert(pFrame);
std::pair<SwTextNode *, sal_Int32> const pos(pFrame->MapViewToModel(TextFrameIndex(nPos)));
SwPaM* pPam = &m_rCursor;
if (pPam->GetPoint()->GetNode() != *pos.first
|| pPam->GetPoint()->GetContentIndex() != pos.second)
{
pPam = new SwPaM(*pos.first, pos.second);
}
// text attributes with dummy characters must not be replaced!
bool bDoReplace = true;
sal_Int32 const nLen = rText.getLength();
for (sal_Int32 n = 0; n < nLen && n + nPos < pFrame->GetText().getLength(); ++n)
{
sal_Unicode const Char = pFrame->GetText()[n + nPos];
if (CH_TXTATR_BREAKWORD == Char || CH_TXTATR_INWORD == Char)
{
assert(pFrame->MapViewToModel(TextFrameIndex(n+nPos)).first->GetTextAttrForCharAt(pFrame->MapViewToModel(TextFrameIndex(n+nPos)).second));
bDoReplace = false;
break;
}
}
// tdf#83419 avoid bad autocorrect with visible redlines
// e.g. replacing the first letter of the tracked deletion
// with its capitalized (and not deleted) version.
if ( bDoReplace && !pFrame->getRootFrame()->IsHideRedlines() &&
m_rEditSh.GetDoc()->getIDocumentRedlineAccess().HasRedline( *pPam, RedlineType::Delete, /*bStartOrEndInRange=*/false ) )
{
bDoReplace = false;
}
if ( bDoReplace )
{
SwDoc* pDoc = m_rEditSh.GetDoc();
if( pDoc->IsAutoFormatRedline() )
{
if (nPos == pFrame->GetText().getLength()) // at the End do an Insert
{
pDoc->getIDocumentContentOperations().InsertString( *pPam, rText );
}
else
{
assert(pos.second != pos.first->Len()); // must be _before_ char
PaMIntoCursorShellRing aTmp( m_rEditSh, m_rCursor, *pPam );
pPam->SetMark();
pPam->GetPoint()->SetContent( std::min<sal_Int32>(
pos.first->GetText().getLength(), pos.second + nSourceLength) );
pDoc->getIDocumentContentOperations().ReplaceRange( *pPam, rText, false );
pPam->Exchange();
pPam->DeleteMark();
}
}
else
{
pPam->SetMark();
pPam->GetPoint()->SetContent( std::min<sal_Int32>(
pos.first->GetText().getLength(), pos.second + nSourceLength) );
pDoc->getIDocumentContentOperations().ReplaceRange( *pPam, rText, false );
pPam->Exchange();
pPam->DeleteMark();
}
if( m_bUndoIdInitialized )
{
m_bUndoIdInitialized = true;
if( 1 == rText.getLength() )
{
m_rEditSh.StartUndo( SwUndoId::AUTOCORRECT );
++m_nEndUndoCounter;
}
}
}
if( pPam != &m_rCursor )
delete pPam;
return true;
}
void SwAutoCorrDoc::SetAttr( sal_Int32 nStt, sal_Int32 nEnd, sal_uInt16 nSlotId,
SfxPoolItem& rItem )
{
SwTextNode const*const pTextNd = m_rCursor.GetPointNode().GetTextNode();
SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
pTextNd->getLayoutFrame(m_rEditSh.GetLayout())));
assert(pFrame);
SwPaM aPam(pFrame->MapViewToModelPos(TextFrameIndex(nStt)),
pFrame->MapViewToModelPos(TextFrameIndex(nEnd)));
SfxItemPool& rPool = m_rEditSh.GetDoc()->GetAttrPool();
sal_uInt16 nWhich = rPool.GetWhichIDFromSlotID( nSlotId, false );
if( nWhich )
{
rItem.SetWhich( nWhich );
SfxItemSet aSet( rPool, aCharFormatSetRange );
SetAllScriptItem( aSet, rItem );
m_rEditSh.GetDoc()->SetFormatItemByAutoFormat( aPam, aSet );
if( m_bUndoIdInitialized )
m_bUndoIdInitialized = true;
}
}
bool SwAutoCorrDoc::SetINetAttr( sal_Int32 nStt, sal_Int32 nEnd, const OUString& rURL )
{
SwTextNode const*const pTextNd = m_rCursor.GetPointNode().GetTextNode();
SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
pTextNd->getLayoutFrame(m_rEditSh.GetLayout())));
assert(pFrame);
SwPaM aPam(pFrame->MapViewToModelPos(TextFrameIndex(nStt)),
pFrame->MapViewToModelPos(TextFrameIndex(nEnd)));
SfxItemSetFixed<RES_TXTATR_INETFMT, RES_TXTATR_INETFMT>
aSet( m_rEditSh.GetDoc()->GetAttrPool() );
aSet.Put( SwFormatINetFormat( rURL, OUString() ));
m_rEditSh.GetDoc()->SetFormatItemByAutoFormat( aPam, aSet );
if( m_bUndoIdInitialized )
m_bUndoIdInitialized = true;
return true;
}
/** Return the text of a previous paragraph
*
* @param bAtNormalPos If <true> before the normal insert position; if <false> in which the
* corrected word was inserted. (Doesn't need to be the same paragraph!)
* @return text or 0, if previous paragraph does not exists or there are only blankness
*/
OUString const* SwAutoCorrDoc::GetPrevPara(bool const bAtNormalPos)
{
OUString const* pStr(nullptr);
if( bAtNormalPos || !m_oIndex )
{
m_oIndex.emplace(m_rCursor.GetPoint()->GetNode());
}
sw::GotoPrevLayoutTextFrame(*m_oIndex, m_rEditSh.GetLayout());
SwTextFrame const* pFrame(nullptr);
for (SwTextNode * pTextNd = m_oIndex->GetNode().GetTextNode();
pTextNd; pTextNd = m_oIndex->GetNode().GetTextNode())
{
pFrame = static_cast<SwTextFrame const*>(
pTextNd->getLayoutFrame(m_rEditSh.GetLayout()));
if (pFrame && !pFrame->GetText().isEmpty())
{
break;
}
sw::GotoPrevLayoutTextFrame(*m_oIndex, m_rEditSh.GetLayout());
}
if (pFrame && !pFrame->GetText().isEmpty() &&
0 == pFrame->GetTextNodeForParaProps()->GetAttrOutlineLevel())
{
pStr = & pFrame->GetText();
}
if( m_bUndoIdInitialized )
m_bUndoIdInitialized = true;
return pStr;
}
bool SwAutoCorrDoc::ChgAutoCorrWord( sal_Int32& rSttPos, sal_Int32 nEndPos,
SvxAutoCorrect& rACorrect,
OUString* pPara )
{
if( m_bUndoIdInitialized )
m_bUndoIdInitialized = true;
// Found a beginning of a paragraph or a Blank,
// search for the word Kuerzel (Shortcut) in the Auto
SwTextNode* pTextNd = m_rCursor.GetPointNode().GetTextNode();
OSL_ENSURE( pTextNd, "where is the TextNode?" );
bool bRet = false;
if( nEndPos == rSttPos )
return bRet;
LanguageType eLang = GetLanguage(nEndPos);
if(LANGUAGE_SYSTEM == eLang)
eLang = GetAppLanguage();
LanguageTag aLanguageTag( eLang);
SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
pTextNd->getLayoutFrame(m_rEditSh.GetLayout())));
assert(pFrame);
OUString sFrameText = pFrame->GetText();
sal_Int32 sttPos = rSttPos;
auto pStatus = rACorrect.SearchWordsInList(sFrameText, sttPos, nEndPos,
*this, aLanguageTag);
SwDoc* pDoc = m_rEditSh.GetDoc();
if( pStatus )
{
sal_Int32 minSttPos = sttPos;
do {
const SvxAutocorrWord* pFnd = pStatus->GetAutocorrWord();
// replace also last colon of keywords surrounded by colons
// (for example, ":name:")
const bool replaceLastChar = sFrameText.getLength() > nEndPos
&& pFnd->GetShort()[0] == ':'
&& pFnd->GetShort().endsWith(":");
SwPosition aStartPos( pFrame->MapViewToModelPos(TextFrameIndex(sttPos)) );
SwPosition aEndPos( pFrame->MapViewToModelPos(TextFrameIndex(nEndPos + (replaceLastChar ? 1 : 0))) );
SwPaM aPam(aStartPos, aEndPos);
// don't replace, if a redline starts or ends within the original text
if ( pDoc->getIDocumentRedlineAccess().HasRedline( aPam, RedlineType::Any, /*bStartOrEndInRange=*/true ) )
{
return bRet;
}
if( pFnd->IsTextOnly() )
{
//JP 22.04.99: Bug 63883 - Special treatment for dots.
const bool bLastCharIsPoint
= nEndPos < sFrameText.getLength() && ('.' == sFrameText[nEndPos]);
if( !bLastCharIsPoint || pFnd->GetLong().isEmpty() ||
'.' != pFnd->GetLong()[ pFnd->GetLong().getLength() - 1 ] )
{
// replace the selection
std::vector<std::shared_ptr<SwUnoCursor>> ranges;
bool noRedlines = sw::GetRanges(ranges,
*m_rEditSh.GetDoc(), aPam);
OSL_ENSURE(noRedlines, "redlines should have been blocked.");
OSL_ENSURE(ranges.empty(), "no redlines expected here.");
pDoc->getIDocumentContentOperations().ReplaceRange(
aPam, pFnd->GetLong(), false);
nEndPos = sttPos + pFnd->GetLong().getLength();
bRet = true;
// tdf#83260 After calling sw::DocumentContentOperationsManager::ReplaceRange
// pTextNd may become invalid when change tracking is on and Edit -> Track Changes -> Show == OFF.
// ReplaceRange shows changes, this moves deleted nodes from special section to document.
// Then Show mode is disabled again. As a result pTextNd may be invalidated.
pTextNd = m_rCursor.GetPointNode().GetTextNode();
}
}
else
{
SwTextBlocks aTBlks( rACorrect.GetAutoCorrFileName( aLanguageTag, false, true ));
sal_uInt16 nPos = aTBlks.GetIndex( pFnd->GetShort() );
if( USHRT_MAX != nPos && aTBlks.BeginGetDoc( nPos ) )
{
DeleteSel( aPam );
pDoc->DontExpandFormat( *aPam.GetPoint() );
if( pPara )
{
OSL_ENSURE( !m_oIndex, "who has not deleted his Index?" );
m_oIndex.emplace(m_rCursor.GetPoint()->GetNode());
sw::GotoPrevLayoutTextFrame(*m_oIndex, m_rEditSh.GetLayout());
}
SwDoc* pAutoDoc = aTBlks.GetDoc();
SwNodeIndex aSttIdx( pAutoDoc->GetNodes().GetEndOfExtras(), 1 );
SwContentNode* pContentNd = SwNodes::GoNext(&aSttIdx);
SwPaM aCpyPam( aSttIdx );
const SwTableNode* pTableNd = pContentNd->FindTableNode();
if( pTableNd )
{
aCpyPam.GetPoint()->Assign( *pTableNd );
}
aCpyPam.SetMark();
// then until the end of the Nodes Array
aCpyPam.GetPoint()->Assign( pAutoDoc->GetNodes().GetEndOfContent(), SwNodeOffset(-1) );
pContentNd = aCpyPam.GetPointContentNode();
if (pContentNd)
aCpyPam.GetPoint()->SetContent( pContentNd->Len() );
SwDontExpandItem aExpItem;
aExpItem.SaveDontExpandItems( *aPam.GetPoint() );
pAutoDoc->getIDocumentContentOperations().CopyRange(aCpyPam, *aPam.GetPoint(), SwCopyFlags::CheckPosInFly);
aExpItem.RestoreDontExpandItems( *aPam.GetPoint() );
if( pPara )
{
sw::GotoNextLayoutTextFrame(*m_oIndex, m_rEditSh.GetLayout());
pTextNd = m_oIndex->GetNode().GetTextNode();
}
// hmm... the inserted text can have multiple text nodes
// - not sure what the "pos" should point to, but pFrame
// is not changed so try the first node?
nEndPos = sttPos + aCpyPam.GetMark()->GetContentIndex();
bRet = true;
}
aTBlks.EndGetDoc();
}
if( sttPos < minSttPos) {
minSttPos = sttPos;
}
sttPos = rSttPos;
sFrameText = pFrame->GetText();
} while( SvxAutoCorrect::SearchWordsNext(sFrameText, sttPos, nEndPos,
*pStatus) );
rSttPos = minSttPos;
}
if( bRet && pPara && pTextNd )
{
SwTextFrame const*const pNewFrame(static_cast<SwTextFrame const*>(
pTextNd->getLayoutFrame(m_rEditSh.GetLayout())));
*pPara = pNewFrame->GetText();
}
return bRet;
}
bool SwAutoCorrDoc::TransliterateRTLWord( sal_Int32& rSttPos, sal_Int32 nEndPos, bool bApply )
{
if( m_bUndoIdInitialized )
m_bUndoIdInitialized = true;
SwTextNode* pTextNd = m_rCursor.GetPointNode().GetTextNode();
OSL_ENSURE( pTextNd, "where is the TextNode?" );
bool bRet = false;
if( nEndPos == rSttPos )
return bRet;
LanguageType eLang = GetLanguage(nEndPos);
if(LANGUAGE_SYSTEM == eLang)
eLang = GetAppLanguage();
LanguageTag aLanguageTag(eLang);
SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
pTextNd->getLayoutFrame(m_rEditSh.GetLayout())));
assert(pFrame);
const OUString sFrameText = pFrame->GetText();
SwDoc* pDoc = m_rEditSh.GetDoc();
if ( pFrame->IsRightToLeft() || bApply )
{
// transliterate to Old Hungarian using Numbertext via NatNum12 number format modifier
OUString sWord(sFrameText.copy(rSttPos, nEndPos - rSttPos));
// Consonant disambiguation using hyphenation
uno::Reference< linguistic2::XHyphenator > xHyph;
xHyph = ::GetHyphenator();
OUStringBuffer sDisambiguatedWord;
const ::css::uno::Sequence< ::css::beans::PropertyValue > aProperties;
css::uno::Reference< css::linguistic2::XHyphenatedWord > xHyphWord;
for (int i = 0; i+1 < sWord.getLength(); i++ )
{
xHyphWord = xHyph->hyphenate( sWord,
aLanguageTag.getLocale(),
i,
aProperties );
// insert ZWSP at a hyphenation point, if it's not an alternative one (i.e. ssz->sz-sz)
if (xHyphWord.is() && xHyphWord->getHyphenationPos()+1 == i && !xHyphWord->isAlternativeSpelling())
{
sDisambiguatedWord.append(CHAR_ZWSP);
}
sDisambiguatedWord.append(sWord[i]);
}
sDisambiguatedWord.append(sWord[sWord.getLength()-1]);
SvNumberFormatter* pFormatter = pDoc->GetNumberFormatter();
OUString sConverted;
if (pFormatter && !sWord.isEmpty())
{
const Color* pColor = nullptr;
// Send text as NatNum12 prefix: "word" -> "[NatNum12 word]0"
// Closing bracket doesn't allowed in NatNum parameters, remove it from transliteration:
// "[word]" -> "[NatNum12 [word]0"
bool bHasBracket = sWord.endsWith("]");
if ( !bHasBracket )
sDisambiguatedWord.append("]");
OUString sPrefix("[NatNum12 " + sDisambiguatedWord + "0");
if (pFormatter->GetPreviewString(sPrefix, 0, sConverted, &pColor, LANGUAGE_USER_HUNGARIAN_ROVAS))
{
if ( bHasBracket )
sConverted = sConverted + "]";
bRet = true;
}
}
SwPaM aPam(pFrame->MapViewToModelPos(TextFrameIndex(rSttPos)),
pFrame->MapViewToModelPos(TextFrameIndex(nEndPos)));
if (bRet && nEndPos <= sFrameText.getLength())
pDoc->getIDocumentContentOperations().ReplaceRange(aPam, sConverted, false);
}
return bRet;
}
// Called by the functions:
// - FnCapitalStartWord
// - FnCapitalStartSentence
// after the exchange of characters. Then the words, if necessary, can be inserted
// into the exception list.
void SwAutoCorrDoc::SaveCpltSttWord( ACFlags nFlag, sal_Int32 nPos,
const OUString& rExceptWord,
sal_Unicode cChar )
{
SwNodeOffset nNode = m_oIndex ? m_oIndex->GetIndex() : m_rCursor.GetPoint()->GetNodeIndex();
LanguageType eLang = GetLanguage(nPos);
m_rEditSh.GetDoc()->SetAutoCorrExceptWord( std::make_unique<SwAutoCorrExceptWord>( nFlag,
nNode, nPos, rExceptWord, cChar, eLang ));
}
LanguageType SwAutoCorrDoc::GetLanguage( sal_Int32 nPos ) const
{
LanguageType eRet = LANGUAGE_SYSTEM;
SwTextNode* pNd = m_rCursor.GetPoint()->GetNode().GetTextNode();
if( pNd )
{
SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
pNd->getLayoutFrame(m_rEditSh.GetLayout())));
assert(pFrame);
eRet = pFrame->GetLangOfChar(TextFrameIndex(nPos), 0, true);
}
if(LANGUAGE_SYSTEM == eRet)
eRet = GetAppLanguage();
return eRet;
}
void SwAutoCorrExceptWord::CheckChar( const SwPosition& rPos, sal_Unicode cChr )
{
// test only if this is an improvement.
// If yes, then add the word to the list.
if (m_cChar == cChr && rPos.GetNodeIndex() == m_nNode && rPos.GetContentIndex() == m_nContent)
{
// get the current autocorrection:
SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get().GetAutoCorrect();
// then add to the list:
if (ACFlags::CapitalStartWord & m_nFlags)
pACorr->AddWordStartException(m_sWord, m_eLanguage);
else if (ACFlags::CapitalStartSentence & m_nFlags)
pACorr->AddCplSttException(m_sWord, m_eLanguage);
}
}
bool SwAutoCorrExceptWord::CheckDelChar( const SwPosition& rPos )
{
bool bRet = false;
if (!m_bDeleted && rPos.GetNodeIndex() == m_nNode && rPos.GetContentIndex() == m_nContent)
m_bDeleted = bRet = true;
return bRet;
}
SwDontExpandItem::~SwDontExpandItem()
{
}
void SwDontExpandItem::SaveDontExpandItems( const SwPosition& rPos )
{
const SwTextNode* pTextNd = rPos.GetNode().GetTextNode();
if( pTextNd )
{
m_pDontExpandItems.reset( new SfxItemSet( const_cast<SwDoc&>(pTextNd->GetDoc()).GetAttrPool(),
aCharFormatSetRange ) );
const sal_Int32 n = rPos.GetContentIndex();
if (!pTextNd->GetParaAttr( *m_pDontExpandItems, n, n,
n != pTextNd->GetText().getLength() ))
{
m_pDontExpandItems.reset();
}
}
}
void SwDontExpandItem::RestoreDontExpandItems( const SwPosition& rPos )
{
SwTextNode* pTextNd = rPos.GetNode().GetTextNode();
if( !pTextNd )
return;
const sal_Int32 nStart = rPos.GetContentIndex();
if( nStart == pTextNd->GetText().getLength() )
pTextNd->FormatToTextAttr( pTextNd );
if( !(pTextNd->GetpSwpHints() && pTextNd->GetpSwpHints()->Count()) )
return;
const size_t nSize = pTextNd->GetpSwpHints()->Count();
sal_Int32 nAttrStart;
for( size_t n = 0; n < nSize; ++n )
{
SwTextAttr* pHt = pTextNd->GetpSwpHints()->Get( n );
nAttrStart = pHt->GetStart();
if( nAttrStart > nStart ) // beyond the area
break;
const sal_Int32* pAttrEnd;
if( nullptr != ( pAttrEnd = pHt->End() ) &&
( ( nAttrStart < nStart &&
( pHt->DontExpand() ? nStart < *pAttrEnd
: nStart <= *pAttrEnd )) ||
( nStart == nAttrStart &&
( nAttrStart == *pAttrEnd || !nStart ))) )
{
const SfxPoolItem* pItem;
if( !m_pDontExpandItems || SfxItemState::SET != m_pDontExpandItems->
GetItemState( pHt->Which(), false, &pItem ) ||
*pItem != pHt->GetAttr() )
{
// The attribute was not previously set in this form in the
// paragraph, so it can only be created through insert/copy
// Because of that it is a candidate for DontExpand
pHt->SetDontExpand( true );
}
}
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V678 An object is used as an argument to its own method. Consider checking the first actual argument of the 'FormatToTextAttr' function.
↑ V1048 The 'm_bUndoIdInitialized' variable was assigned the same value.
↑ V1048 The 'm_bUndoIdInitialized' variable was assigned the same value.
↑ V1048 The 'm_bUndoIdInitialized' variable was assigned the same value.
↑ V1048 The 'm_bUndoIdInitialized' variable was assigned the same value.
↑ V1048 The 'm_bUndoIdInitialized' variable was assigned the same value.
↑ V1048 The 'm_bUndoIdInitialized' variable was assigned the same value.
↑ V1048 The 'm_bUndoIdInitialized' variable was assigned the same value.