/* -*- 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 <memory>
#include <sal/macros.h>
#include <vcl/image.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/dialog.hxx>
#include <vcl/svapp.hxx>
#include <com/sun/star/i18n/WordType.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <vcl/metric.hxx>
#include <i18nlangtag/languagetag.hxx>
#include <i18nlangtag/mslangid.hxx>
#include <svl/languageoptions.hxx>
#include <svtools/ctrltool.hxx>
#include <svtools/langtab.hxx>
#include <vcl/graphicfilter.hxx>
#include <svl/srchitem.hxx>
#include "impedit.hxx"
#include <editeng/editeng.hxx>
#include <editeng/editview.hxx>
#include <editeng/flditem.hxx>
#include <editeng/svxacorr.hxx>
#include <editeng/langitem.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/eerdll.hxx>
#include <eerdll2.hxx>
#include <editeng/editrids.hrc>
#include <editeng.hxx>
#include <helpids.h>
#include <i18nlangtag/lang.h>
#include <vcl/menu.hxx>
#include <vcl/window.hxx>
#include <editeng/acorrcfg.hxx>
#include <editeng/unolingu.hxx>
#include <editeng/fontitem.hxx>
#include <unotools/lingucfg.hxx>
#include <osl/file.hxx>
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/beans/PropertyValues.hpp>
#include <com/sun/star/lang/Locale.hpp>
#include <linguistic/lngprops.hxx>
#include <vcl/settings.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <comphelper/lok.hxx>
#include <sfx2/viewsh.hxx>
#include <com/sun/star/lang/XServiceInfo.hpp>
using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::beans;
// static
LanguageType EditView::CheckLanguage(
const OUString &rText,
const Reference< linguistic2::XSpellChecker1 >& xSpell,
const Reference< linguistic2::XLanguageGuessing >& xLangGuess,
bool bIsParaText )
{
LanguageType nLang = LANGUAGE_NONE;
if (bIsParaText) // check longer texts with language-guessing...
{
if (!xLangGuess.is())
return nLang;
LanguageTag aGuessTag( xLangGuess->guessPrimaryLanguage( rText, 0, rText.getLength()) );
// If the result from language guessing does not provide a 'Country'
// part, try to get it by looking up the locale setting of the office,
// "Tools/Options - Language Settings - Languages: Locale setting", if
// the language matches.
if ( aGuessTag.getCountry().isEmpty() )
{
const LanguageTag& rAppLocaleTag = Application::GetSettings().GetLanguageTag();
if (rAppLocaleTag.getLanguage() == aGuessTag.getLanguage())
nLang = rAppLocaleTag.getLanguageType();
}
if (nLang == LANGUAGE_NONE) // language not found by looking up the system language...
nLang = aGuessTag.makeFallback().getLanguageType(); // best known locale match
if (nLang == LANGUAGE_SYSTEM)
nLang = Application::GetSettings().GetLanguageTag().getLanguageType();
if (nLang == LANGUAGE_DONTKNOW)
nLang = LANGUAGE_NONE;
}
else // check single word
{
if (!xSpell.is())
return nLang;
// build list of languages to check
LanguageType aLangList[4];
const AllSettings& rSettings = Application::GetSettings();
SvtLinguOptions aLinguOpt;
SvtLinguConfig().GetOptions( aLinguOpt );
// The default document language from "Tools/Options - Language Settings - Languages: Western"
aLangList[0] = MsLangId::resolveSystemLanguageByScriptType( aLinguOpt.nDefaultLanguage,
css::i18n::ScriptType::LATIN);
// The one from "Tools/Options - Language Settings - Languages: User interface"
aLangList[1] = rSettings.GetUILanguageTag().getLanguageType();
// The one from "Tools/Options - Language Settings - Languages: Locale setting"
aLangList[2] = rSettings.GetLanguageTag().getLanguageType();
// en-US
aLangList[3] = LANGUAGE_ENGLISH_US;
#ifdef DEBUG
lang::Locale a0( LanguageTag::convertToLocale( aLangList[0] ) );
lang::Locale a1( LanguageTag::convertToLocale( aLangList[1] ) );
lang::Locale a2( LanguageTag::convertToLocale( aLangList[2] ) );
lang::Locale a3( LanguageTag::convertToLocale( aLangList[3] ) );
#endif
sal_Int32 const nCount = SAL_N_ELEMENTS(aLangList);
for (sal_Int32 i = 0; i < nCount; i++)
{
LanguageType nTmpLang = aLangList[i];
if (nTmpLang != LANGUAGE_NONE && nTmpLang != LANGUAGE_DONTKNOW)
{
if (xSpell->hasLanguage( static_cast<sal_uInt16>(nTmpLang) ) &&
xSpell->isValid( rText, static_cast<sal_uInt16>(nTmpLang), Sequence< PropertyValue >() ))
{
nLang = nTmpLang;
break;
}
}
}
}
return nLang;
}
// class EditViewCallbacks
EditViewCallbacks::~EditViewCallbacks()
{
}
// class EditView
EditView::EditView( EditEngine* pEng, vcl::Window* pWindow )
{
pImpEditView.reset( new ImpEditView( this, pEng, pWindow ) );
}
EditView::~EditView()
{
}
void EditView::setEditViewCallbacks(const EditViewCallbacks* pEditViewCallbacks)
{
pImpEditView->setEditViewCallbacks(pEditViewCallbacks);
}
bool EditView::hasEditViewCallbacks() const
{
return pImpEditView->hasEditViewCallbacks();
}
ImpEditEngine* EditView::GetImpEditEngine() const
{
return pImpEditView->pEditEngine->pImpEditEngine.get();
}
EditEngine* EditView::GetEditEngine() const
{
return pImpEditView->pEditEngine;
}
tools::Rectangle EditView::GetInvalidateRect() const
{
if ( !pImpEditView->DoInvalidateMore() )
return pImpEditView->aOutArea;
else
{
tools::Rectangle aRect( pImpEditView->aOutArea );
long nMore = pImpEditView->GetWindow()->PixelToLogic( Size( pImpEditView->GetInvalidateMore(), 0 ) ).Width();
aRect.AdjustLeft( -nMore );
aRect.AdjustRight(nMore );
aRect.AdjustTop( -nMore );
aRect.AdjustBottom(nMore );
return aRect;
}
}
void EditView::InvalidateWindow(const tools::Rectangle& rClipRect)
{
if (pImpEditView->hasEditViewCallbacks())
{
// do not invalidate and trigger a global repaint, but forward
// the need for change to the applied EditViewCallback, can e.g.
// be used to visualize the active edit text in an OverlayObject
pImpEditView->mpEditViewCallbacks->EditViewInvalidate();
}
else
{
// classic mode: invalidate and trigger full repaint
// of the changed area
GetWindow()->Invalidate(rClipRect);
}
}
void EditView::InvalidateOtherViewWindows( const tools::Rectangle& rInvRect )
{
if (comphelper::LibreOfficeKit::isActive())
{
for (auto& pWin : pImpEditView->aOutWindowSet)
{
if (pWin)
pWin->Invalidate( rInvRect );
}
}
}
void EditView::Invalidate()
{
const tools::Rectangle& rInvRect = GetInvalidateRect();
pImpEditView->GetWindow()->Invalidate( rInvRect );
InvalidateOtherViewWindows( rInvRect );
}
void EditView::SetReadOnly( bool bReadOnly )
{
pImpEditView->bReadOnly = bReadOnly;
}
bool EditView::IsReadOnly() const
{
return pImpEditView->bReadOnly;
}
void EditView::SetSelection( const ESelection& rESel )
{
// If someone has just left an empty attribute, and then the outliner manipulates the
// selection, call the CursorMoved method so that empty attributes get cleaned up.
if ( !HasSelection() )
{
// tdf#113591 Get node from EditDoc, as the selection might have a pointer to an
// already deleted node.
const ContentNode* pNode = pImpEditView->pEditEngine->GetEditDoc().GetEndPaM().GetNode();
pImpEditView->pEditEngine->CursorMoved( pNode );
}
EditSelection aNewSelection( pImpEditView->pEditEngine->pImpEditEngine->ConvertSelection(
rESel.nStartPara, rESel.nStartPos, rESel.nEndPara, rESel.nEndPos ) );
// If the selection is manipulated after a KeyInput:
pImpEditView->pEditEngine->CheckIdleFormatter();
// Selection may not start/end at an invisible paragraph:
const ParaPortion* pPortion = pImpEditView->pEditEngine->FindParaPortion( aNewSelection.Min().GetNode() );
if ( !pPortion->IsVisible() )
{
pPortion = pImpEditView->pEditEngine->GetPrevVisPortion( pPortion );
ContentNode* pNode = pPortion ? pPortion->GetNode() : pImpEditView->pEditEngine->GetEditDoc().GetObject( 0 );
aNewSelection.Min() = EditPaM( pNode, pNode->Len() );
}
pPortion = pImpEditView->pEditEngine->FindParaPortion( aNewSelection.Max().GetNode() );
if ( !pPortion->IsVisible() )
{
pPortion = pImpEditView->pEditEngine->GetPrevVisPortion( pPortion );
ContentNode* pNode = pPortion ? pPortion->GetNode() : pImpEditView->pEditEngine->GetEditDoc().GetObject( 0 );
aNewSelection.Max() = EditPaM( pNode, pNode->Len() );
}
pImpEditView->DrawSelectionXOR();
pImpEditView->SetEditSelection( aNewSelection );
pImpEditView->DrawSelectionXOR();
bool bGotoCursor = pImpEditView->DoAutoScroll();
ShowCursor( bGotoCursor );
}
ESelection EditView::GetSelection() const
{
ESelection aSelection;
aSelection.nStartPara = pImpEditView->pEditEngine->GetEditDoc().GetPos( pImpEditView->GetEditSelection().Min().GetNode() );
aSelection.nEndPara = pImpEditView->pEditEngine->GetEditDoc().GetPos( pImpEditView->GetEditSelection().Max().GetNode() );
aSelection.nStartPos = pImpEditView->GetEditSelection().Min().GetIndex();
aSelection.nEndPos = pImpEditView->GetEditSelection().Max().GetIndex();
return aSelection;
}
bool EditView::HasSelection() const
{
return pImpEditView->HasSelection();
}
void EditView::DeleteSelected()
{
pImpEditView->DeleteSelected();
}
SvtScriptType EditView::GetSelectedScriptType() const
{
return pImpEditView->pEditEngine->GetScriptType( pImpEditView->GetEditSelection() );
}
void EditView::GetSelectionRectangles(std::vector<tools::Rectangle>& rLogicRects) const
{
return pImpEditView->GetSelectionRectangles(pImpEditView->GetEditSelection(), rLogicRects);
}
void EditView::Paint( const tools::Rectangle& rRect, OutputDevice* pTargetDevice )
{
pImpEditView->pEditEngine->pImpEditEngine->Paint( pImpEditView.get(), rRect, pTargetDevice );
}
void EditView::SetEditEngine( EditEngine* pEditEng )
{
pImpEditView->pEditEngine = pEditEng;
EditSelection aStartSel;
aStartSel = pImpEditView->pEditEngine->GetEditDoc().GetStartPaM();
pImpEditView->SetEditSelection( aStartSel );
}
void EditView::SetWindow( vcl::Window* pWin )
{
pImpEditView->pOutWin = pWin;
pImpEditView->pEditEngine->pImpEditEngine->GetSelEngine().Reset();
}
vcl::Window* EditView::GetWindow() const
{
return pImpEditView->pOutWin;
}
bool EditView::HasOtherViewWindow( vcl::Window* pWin )
{
OutWindowSet& rOutWindowSet = pImpEditView->aOutWindowSet;
auto found = std::find(rOutWindowSet.begin(), rOutWindowSet.end(), pWin);
return (found != rOutWindowSet.end());
}
bool EditView::AddOtherViewWindow( vcl::Window* pWin )
{
if (HasOtherViewWindow(pWin))
return false;
pImpEditView->aOutWindowSet.emplace_back(pWin);
return true;
}
bool EditView::RemoveOtherViewWindow( vcl::Window* pWin )
{
OutWindowSet& rOutWindowSet = pImpEditView->aOutWindowSet;
auto found = std::find(rOutWindowSet.begin(), rOutWindowSet.end(), pWin);
if (found == rOutWindowSet.end())
return false;
rOutWindowSet.erase(found);
return true;
}
void EditView::SetVisArea( const tools::Rectangle& rRect )
{
pImpEditView->SetVisDocStartPos( rRect.TopLeft() );
}
const tools::Rectangle& EditView::GetVisArea() const
{
// Change return value to Rectangle in next incompatible build !!!
static tools::Rectangle aRect;
aRect = pImpEditView->GetVisDocArea();
return aRect;
}
void EditView::SetOutputArea( const tools::Rectangle& rRect )
{
pImpEditView->SetOutputArea( rRect );
// the rest here only if it is an API call:
pImpEditView->CalcAnchorPoint();
if ( pImpEditView->pEditEngine->pImpEditEngine->GetStatus().AutoPageSize() )
pImpEditView->RecalcOutputArea();
pImpEditView->ShowCursor( false, false );
}
const tools::Rectangle& EditView::GetOutputArea() const
{
return pImpEditView->GetOutputArea();
}
const Pointer& EditView::GetPointer() const
{
return pImpEditView->GetPointer();
}
vcl::Cursor* EditView::GetCursor() const
{
return pImpEditView->pCursor.get();
}
void EditView::InsertText( const OUString& rStr, bool bSelect )
{
EditEngine* pEE = pImpEditView->pEditEngine;
pImpEditView->DrawSelectionXOR();
EditPaM aPaM1;
if ( bSelect )
{
EditSelection aTmpSel( pImpEditView->GetEditSelection() );
aTmpSel.Adjust( pEE->GetEditDoc() );
aPaM1 = aTmpSel.Min();
}
pEE->UndoActionStart( EDITUNDO_INSERT );
EditPaM aPaM2( pEE->InsertText( pImpEditView->GetEditSelection(), rStr ) );
pEE->UndoActionEnd();
if ( bSelect )
{
DBG_ASSERT( !aPaM1.DbgIsBuggy( pEE->GetEditDoc() ), "Insert: PaM broken" );
pImpEditView->SetEditSelection( EditSelection( aPaM1, aPaM2 ) );
}
else
pImpEditView->SetEditSelection( EditSelection( aPaM2, aPaM2 ) );
pEE->FormatAndUpdate( this );
}
bool EditView::PostKeyEvent( const KeyEvent& rKeyEvent, vcl::Window const * pFrameWin )
{
return pImpEditView->PostKeyEvent( rKeyEvent, pFrameWin );
}
bool EditView::MouseButtonUp( const MouseEvent& rMouseEvent )
{
return pImpEditView->MouseButtonUp( rMouseEvent );
}
void EditView::ReleaseMouse()
{
return pImpEditView->ReleaseMouse();
}
bool EditView::MouseButtonDown( const MouseEvent& rMouseEvent )
{
return pImpEditView->MouseButtonDown( rMouseEvent );
}
bool EditView::MouseMove( const MouseEvent& rMouseEvent )
{
return pImpEditView->MouseMove( rMouseEvent );
}
void EditView::Command( const CommandEvent& rCEvt )
{
pImpEditView->Command( rCEvt );
}
void EditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor, bool bActivate )
{
if ( pImpEditView->pEditEngine->HasView( this ) )
{
// The control word is more important:
if ( !pImpEditView->DoAutoScroll() )
bGotoCursor = false;
pImpEditView->ShowCursor( bGotoCursor, bForceVisCursor );
if (pImpEditView->mpViewShell && !bActivate)
{
OString aPayload = OString::boolean(true);
pImpEditView->mpViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CURSOR_VISIBLE, aPayload.getStr());
pImpEditView->mpViewShell->NotifyOtherViews(LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", aPayload);
}
}
}
void EditView::HideCursor(bool bDeactivate)
{
pImpEditView->GetCursor()->Hide();
if (pImpEditView->mpViewShell && !bDeactivate)
{
OString aPayload = OString::boolean(false);
pImpEditView->mpViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CURSOR_VISIBLE, aPayload.getStr());
pImpEditView->mpViewShell->NotifyOtherViews(LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", aPayload);
}
}
Pair EditView::Scroll( long ndX, long ndY, ScrollRangeCheck nRangeCheck )
{
return pImpEditView->Scroll( ndX, ndY, nRangeCheck );
}
const SfxItemSet& EditView::GetEmptyItemSet()
{
return pImpEditView->pEditEngine->GetEmptyItemSet();
}
void EditView::SetAttribs( const SfxItemSet& rSet )
{
DBG_ASSERT( !pImpEditView->aEditSelection.IsInvalid(), "Blind Selection in ...." );
pImpEditView->DrawSelectionXOR();
pImpEditView->pEditEngine->SetAttribs( pImpEditView->GetEditSelection(), rSet, SetAttribsMode::WholeWord );
pImpEditView->pEditEngine->FormatAndUpdate( this );
}
void EditView::RemoveAttribsKeepLanguages( bool bRemoveParaAttribs )
{
pImpEditView->DrawSelectionXOR();
pImpEditView->pEditEngine->UndoActionStart( EDITUNDO_RESETATTRIBS );
EditSelection aSelection( pImpEditView->GetEditSelection() );
for (sal_uInt16 nWID = EE_ITEMS_START; nWID <= EE_ITEMS_END; ++nWID)
{
bool bIsLang = EE_CHAR_LANGUAGE == nWID ||
EE_CHAR_LANGUAGE_CJK == nWID ||
EE_CHAR_LANGUAGE_CTL == nWID;
if (!bIsLang)
pImpEditView->pEditEngine->RemoveCharAttribs( aSelection, bRemoveParaAttribs, nWID );
}
pImpEditView->pEditEngine->UndoActionEnd();
pImpEditView->pEditEngine->FormatAndUpdate( this );
}
void EditView::RemoveAttribs( bool bRemoveParaAttribs, sal_uInt16 nWhich )
{
pImpEditView->DrawSelectionXOR();
pImpEditView->pEditEngine->UndoActionStart( EDITUNDO_RESETATTRIBS );
pImpEditView->pEditEngine->RemoveCharAttribs( pImpEditView->GetEditSelection(), bRemoveParaAttribs, nWhich );
pImpEditView->pEditEngine->UndoActionEnd();
pImpEditView->pEditEngine->FormatAndUpdate( this );
}
void EditView::RemoveCharAttribs( sal_Int32 nPara, sal_uInt16 nWhich )
{
pImpEditView->pEditEngine->UndoActionStart( EDITUNDO_RESETATTRIBS );
pImpEditView->pEditEngine->RemoveCharAttribs( nPara, nWhich );
pImpEditView->pEditEngine->UndoActionEnd();
pImpEditView->pEditEngine->FormatAndUpdate( this );
}
SfxItemSet EditView::GetAttribs()
{
DBG_ASSERT( !pImpEditView->aEditSelection.IsInvalid(), "Blind Selection in ...." );
return pImpEditView->pEditEngine->pImpEditEngine->GetAttribs( pImpEditView->GetEditSelection() );
}
void EditView::Undo()
{
pImpEditView->pEditEngine->Undo( this );
}
void EditView::Redo()
{
pImpEditView->pEditEngine->Redo( this );
}
ErrCode EditView::Read( SvStream& rInput, EETextFormat eFormat, SvKeyValueIterator* pHTTPHeaderAttrs )
{
EditSelection aOldSel( pImpEditView->GetEditSelection() );
pImpEditView->DrawSelectionXOR();
pImpEditView->pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_READ );
EditPaM aEndPaM = pImpEditView->pEditEngine->pImpEditEngine->Read( rInput, "", eFormat, aOldSel, pHTTPHeaderAttrs );
pImpEditView->pEditEngine->pImpEditEngine->UndoActionEnd();
EditSelection aNewSel( aEndPaM, aEndPaM );
pImpEditView->SetEditSelection( aNewSel );
bool bGotoCursor = pImpEditView->DoAutoScroll();
ShowCursor( bGotoCursor );
return rInput.GetError();
}
void EditView::Cut()
{
Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard());
pImpEditView->CutCopy( aClipBoard, true );
}
css::uno::Reference< css::datatransfer::XTransferable > EditView::GetTransferable()
{
uno::Reference< datatransfer::XTransferable > xData =
GetEditEngine()->CreateTransferable( pImpEditView->GetEditSelection() );
return xData;
}
void EditView::Copy()
{
Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard());
pImpEditView->CutCopy( aClipBoard, false );
}
void EditView::Paste()
{
Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard());
pImpEditView->Paste( aClipBoard );
}
void EditView::PasteSpecial()
{
Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard());
pImpEditView->Paste(aClipBoard, true );
}
Point EditView::GetWindowPosTopLeft( sal_Int32 nParagraph )
{
Point aDocPos( pImpEditView->pEditEngine->GetDocPosTopLeft( nParagraph ) );
return pImpEditView->GetWindowPos( aDocPos );
}
void EditView::SetSelectionMode( EESelectionMode eMode )
{
pImpEditView->SetSelectionMode( eMode );
}
OUString EditView::GetSelected()
{
return pImpEditView->pEditEngine->pImpEditEngine->GetSelected( pImpEditView->GetEditSelection() );
}
void EditView::MoveParagraphs( Range aParagraphs, sal_Int32 nNewPos )
{
pImpEditView->pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_MOVEPARAS );
pImpEditView->pEditEngine->pImpEditEngine->MoveParagraphs( aParagraphs, nNewPos, this );
pImpEditView->pEditEngine->pImpEditEngine->UndoActionEnd();
}
void EditView::MoveParagraphs( long nDiff )
{
ESelection aSel = GetSelection();
Range aRange( aSel.nStartPara, aSel.nEndPara );
aRange.Justify();
long nDest = ( nDiff > 0 ? aRange.Max() : aRange.Min() ) + nDiff;
if ( nDiff > 0 )
nDest++;
DBG_ASSERT( ( nDest >= 0 ) && ( nDest <= pImpEditView->pEditEngine->GetParagraphCount() ), "MoveParagraphs - wrong Parameters!" );
MoveParagraphs( aRange, sal::static_int_cast< sal_Int32 >( nDest ) );
}
void EditView::SetBackgroundColor( const Color& rColor )
{
pImpEditView->SetBackgroundColor( rColor );
}
Color const & EditView::GetBackgroundColor() const
{
return pImpEditView->GetBackgroundColor();
}
void EditView::RegisterViewShell(OutlinerViewShell* pViewShell)
{
pImpEditView->RegisterViewShell(pViewShell);
}
void EditView::RegisterOtherShell(OutlinerViewShell* pOtherShell)
{
pImpEditView->RegisterOtherShell(pOtherShell);
}
void EditView::SetControlWord( EVControlBits nWord )
{
pImpEditView->nControl = nWord;
}
EVControlBits EditView::GetControlWord() const
{
return pImpEditView->nControl;
}
std::unique_ptr<EditTextObject> EditView::CreateTextObject()
{
return pImpEditView->pEditEngine->pImpEditEngine->CreateTextObject( pImpEditView->GetEditSelection() );
}
void EditView::InsertText( const EditTextObject& rTextObject )
{
pImpEditView->DrawSelectionXOR();
pImpEditView->pEditEngine->UndoActionStart( EDITUNDO_INSERT );
EditSelection aTextSel( pImpEditView->pEditEngine->InsertText( rTextObject, pImpEditView->GetEditSelection() ) );
pImpEditView->pEditEngine->UndoActionEnd();
aTextSel.Min() = aTextSel.Max(); // Selection not retained.
pImpEditView->SetEditSelection( aTextSel );
pImpEditView->pEditEngine->FormatAndUpdate( this );
}
void EditView::InsertText( css::uno::Reference< css::datatransfer::XTransferable > const & xDataObj, const OUString& rBaseURL, bool bUseSpecial )
{
pImpEditView->pEditEngine->UndoActionStart( EDITUNDO_INSERT );
pImpEditView->DeleteSelected();
EditSelection aTextSel =
pImpEditView->pEditEngine->InsertText(xDataObj, rBaseURL, pImpEditView->GetEditSelection().Max(), bUseSpecial);
pImpEditView->pEditEngine->UndoActionEnd();
aTextSel.Min() = aTextSel.Max(); // Selection not retained.
pImpEditView->SetEditSelection( aTextSel );
pImpEditView->pEditEngine->FormatAndUpdate( this );
}
void EditView::SetEditEngineUpdateMode( bool bUpdate )
{
pImpEditView->pEditEngine->pImpEditEngine->SetUpdateMode( bUpdate, this );
}
void EditView::ForceUpdate()
{
pImpEditView->pEditEngine->pImpEditEngine->SetUpdateMode( true, this, true );
}
SfxStyleSheet* EditView::GetStyleSheet()
{
EditSelection aSel( pImpEditView->GetEditSelection() );
aSel.Adjust( pImpEditView->pEditEngine->GetEditDoc() );
sal_Int32 nStartPara = pImpEditView->pEditEngine->GetEditDoc().GetPos( aSel.Min().GetNode() );
sal_Int32 nEndPara = pImpEditView->pEditEngine->GetEditDoc().GetPos( aSel.Max().GetNode() );
SfxStyleSheet* pStyle = nullptr;
for ( sal_Int32 n = nStartPara; n <= nEndPara; n++ )
{
SfxStyleSheet* pTmpStyle = pImpEditView->pEditEngine->GetStyleSheet( n );
if ( ( n != nStartPara ) && ( pStyle != pTmpStyle ) )
return nullptr; // Not unique.
pStyle = pTmpStyle;
}
return pStyle;
}
const SfxStyleSheet* EditView::GetStyleSheet() const
{
return const_cast< EditView* >( this )->GetStyleSheet();
}
bool EditView::IsInsertMode() const
{
return pImpEditView->IsInsertMode();
}
void EditView::SetInsertMode( bool bInsert )
{
pImpEditView->SetInsertMode( bInsert );
}
void EditView::SetAnchorMode( EEAnchorMode eMode )
{
pImpEditView->SetAnchorMode( eMode );
}
EEAnchorMode EditView::GetAnchorMode() const
{
return pImpEditView->GetAnchorMode();
}
void EditView::TransliterateText( TransliterationFlags nTransliterationMode )
{
EditSelection aOldSel( pImpEditView->GetEditSelection() );
EditSelection aNewSel = pImpEditView->pEditEngine->TransliterateText( pImpEditView->GetEditSelection(), nTransliterationMode );
if ( aNewSel != aOldSel )
{
pImpEditView->DrawSelectionXOR();
pImpEditView->SetEditSelection( aNewSel );
pImpEditView->DrawSelectionXOR();
}
}
void EditView::CompleteAutoCorrect( vcl::Window const * pFrameWin )
{
if ( !HasSelection() && pImpEditView->pEditEngine->pImpEditEngine->GetStatus().DoAutoCorrect() )
{
pImpEditView->DrawSelectionXOR();
EditSelection aSel = pImpEditView->GetEditSelection();
aSel = pImpEditView->pEditEngine->EndOfWord( aSel.Max() );
aSel = pImpEditView->pEditEngine->pImpEditEngine->AutoCorrect( aSel, 0, !IsInsertMode(), pFrameWin );
pImpEditView->SetEditSelection( aSel );
if ( pImpEditView->pEditEngine->IsModified() )
pImpEditView->pEditEngine->FormatAndUpdate( this );
}
}
EESpellState EditView::StartSpeller( bool bMultipleDoc )
{
if ( !pImpEditView->pEditEngine->pImpEditEngine->GetSpeller().is() )
return EESpellState::NoSpeller;
return pImpEditView->pEditEngine->pImpEditEngine->Spell( this, bMultipleDoc );
}
EESpellState EditView::StartThesaurus()
{
if ( !pImpEditView->pEditEngine->pImpEditEngine->GetSpeller().is() )
return EESpellState::NoSpeller;
return pImpEditView->pEditEngine->pImpEditEngine->StartThesaurus( this );
}
void EditView::StartTextConversion(
LanguageType nSrcLang, LanguageType nDestLang, const vcl::Font *pDestFont,
sal_Int32 nOptions, bool bIsInteractive, bool bMultipleDoc )
{
pImpEditView->pEditEngine->pImpEditEngine->Convert( this, nSrcLang, nDestLang, pDestFont, nOptions, bIsInteractive, bMultipleDoc );
}
sal_Int32 EditView::StartSearchAndReplace( const SvxSearchItem& rSearchItem )
{
return pImpEditView->pEditEngine->pImpEditEngine->StartSearchAndReplace( this, rSearchItem );
}
bool EditView::IsCursorAtWrongSpelledWord()
{
bool bIsWrong = false;
if ( !HasSelection() )
{
EditPaM aPaM = pImpEditView->GetEditSelection().Max();
bIsWrong = pImpEditView->IsWrongSpelledWord( aPaM, false/*bMarkIfWrong*/ );
}
return bIsWrong;
}
bool EditView::IsWrongSpelledWordAtPos( const Point& rPosPixel, bool bMarkIfWrong )
{
Point aPos ( pImpEditView->GetWindow()->PixelToLogic( rPosPixel ) );
aPos = pImpEditView->GetDocPos( aPos );
EditPaM aPaM = pImpEditView->pEditEngine->GetPaM(aPos, false);
return pImpEditView->IsWrongSpelledWord( aPaM , bMarkIfWrong );
}
void EditView::ExecuteSpellPopup( const Point& rPosPixel, Link<SpellCallbackInfo&,void> const * pCallBack )
{
Point aPos ( pImpEditView->GetWindow()->PixelToLogic( rPosPixel ) );
aPos = pImpEditView->GetDocPos( aPos );
EditPaM aPaM = pImpEditView->pEditEngine->GetPaM(aPos, false);
Reference< linguistic2::XSpellChecker1 > xSpeller( pImpEditView->pEditEngine->pImpEditEngine->GetSpeller() );
ESelection aOldSel = GetSelection();
if ( xSpeller.is() && pImpEditView->IsWrongSpelledWord( aPaM, true ) )
{
VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "editeng/ui/spellmenu.ui", "");
VclPtr<PopupMenu> aPopupMenu(aBuilder.get_menu("menu"));
const sal_uInt16 nAutoCorrId = aPopupMenu->GetItemId("autocorrect");
PopupMenu *pAutoMenu = aPopupMenu->GetPopupMenu(nAutoCorrId);
const sal_uInt16 nInsertId = aPopupMenu->GetItemId("insert");
PopupMenu *pInsertMenu = aPopupMenu->GetPopupMenu(nInsertId); // add word to user-dictionaries
pInsertMenu->SetMenuFlags( MenuFlags::NoAutoMnemonics ); //! necessary to retrieve the correct dictionary names later
const sal_uInt16 nAddId = aPopupMenu->GetItemId("add");
const sal_uInt16 nIgnoreId = aPopupMenu->GetItemId("ignore");
const sal_uInt16 nCheckId = aPopupMenu->GetItemId("check");
const sal_uInt16 nAutoCorrectDlgId = aPopupMenu->GetItemId("autocorrectdlg");
EditPaM aPaM2( aPaM );
aPaM2.SetIndex( aPaM2.GetIndex()+1 );
// Are there any replace suggestions?
OUString aSelected( GetSelected() );
// 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(1);
PropertyValue &rVal = aPropVals.getArray()[0];
rVal.Name = UPN_MAX_NUMBER_OF_SUGGESTIONS;
rVal.Value <<= sal_Int16(7);
// Are there any replace suggestions?
Reference< linguistic2::XSpellAlternatives > xSpellAlt =
xSpeller->spell( aSelected, static_cast<sal_uInt16>(pImpEditView->pEditEngine->pImpEditEngine->GetLanguage( aPaM2 )), aPropVals );
Reference< linguistic2::XLanguageGuessing > xLangGuesser( EditDLL::Get().GetGlobalData()->GetLanguageGuesser() );
// check if text might belong to a different language...
LanguageType nGuessLangWord = LANGUAGE_NONE;
LanguageType nGuessLangPara = LANGUAGE_NONE;
if (xSpellAlt.is() && xLangGuesser.is())
{
OUString aParaText;
ContentNode *pNode = aPaM.GetNode();
if (pNode)
{
aParaText = pNode->GetString();
}
else
{
OSL_FAIL( "content node is NULL" );
}
nGuessLangWord = CheckLanguage( xSpellAlt->getWord(), xSpeller, xLangGuesser, false );
nGuessLangPara = CheckLanguage( aParaText, xSpeller, xLangGuesser, true );
}
if (nGuessLangWord != LANGUAGE_NONE || nGuessLangPara != LANGUAGE_NONE)
{
// make sure LANGUAGE_NONE gets not used as menu entry
if (nGuessLangWord == LANGUAGE_NONE)
nGuessLangWord = nGuessLangPara;
if (nGuessLangPara == LANGUAGE_NONE)
nGuessLangPara = nGuessLangWord;
aPopupMenu->InsertSeparator();
OUString aTmpWord( SvtLanguageTable::GetLanguageString( nGuessLangWord ) );
OUString aTmpPara( SvtLanguageTable::GetLanguageString( nGuessLangPara ) );
OUString aWordStr( EditResId( RID_STR_WORD ) );
aWordStr = aWordStr.replaceFirst( "%x", aTmpWord );
OUString aParaStr( EditResId( RID_STR_PARAGRAPH ) );
aParaStr = aParaStr.replaceFirst( "%x", aTmpPara );
aPopupMenu->InsertItem( MN_WORDLANGUAGE, aWordStr );
aPopupMenu->SetHelpId( MN_WORDLANGUAGE, HID_EDITENG_SPELLER_WORDLANGUAGE );
aPopupMenu->InsertItem( MN_PARALANGUAGE, aParaStr );
aPopupMenu->SetHelpId( MN_PARALANGUAGE, HID_EDITENG_SPELLER_PARALANGUAGE );
}
// ## Create mnemonics here
aPopupMenu->CreateAutoMnemonics();
aPopupMenu->SetMenuFlags(aPopupMenu->GetMenuFlags() | MenuFlags::NoAutoMnemonics);
// Replace suggestions...
Sequence< OUString > aAlt;
if (xSpellAlt.is())
aAlt = xSpellAlt->getAlternatives();
const OUString *pAlt = aAlt.getConstArray();
sal_uInt16 nWords = static_cast<sal_uInt16>(aAlt.getLength());
if ( nWords )
{
for ( sal_uInt16 nW = 0; nW < nWords; nW++ )
{
OUString aAlternate( pAlt[nW] );
aPopupMenu->InsertItem( MN_ALTSTART+nW, aAlternate, MenuItemBits::NONE, OString(), nW );
pAutoMenu->InsertItem( MN_AUTOSTART+nW, aAlternate, MenuItemBits::NONE, OString(), nW );
}
aPopupMenu->InsertSeparator(OString(), nWords);
}
else
aPopupMenu->RemoveItem(nAutoCorrId); // delete?
SvtLinguConfig aCfg;
Reference< linguistic2::XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() );
Sequence< Reference< linguistic2::XDictionary > > aDics;
if (xDicList.is())
{
const Reference< linguistic2::XDictionary > *pDic = nullptr;
// add the default positive dictionary to dic-list (if not already done).
// This is to ensure that there is at least one dictionary to which
// words could be added.
uno::Reference< linguistic2::XDictionary > xDic( LinguMgr::GetStandardDic() );
if (xDic.is())
xDic->setActive( true );
aDics = xDicList->getDictionaries();
pDic = aDics.getConstArray();
LanguageType nCheckedLanguage = pImpEditView->pEditEngine->pImpEditEngine->GetLanguage( aPaM2 );
sal_uInt16 nDicCount = static_cast<sal_uInt16>(aDics.getLength());
for (sal_uInt16 i = 0; i < nDicCount; i++)
{
uno::Reference< linguistic2::XDictionary > xDicTmp( pDic[i], uno::UNO_QUERY );
if (!xDicTmp.is() || LinguMgr::GetIgnoreAllList() == xDicTmp)
continue;
uno::Reference< frame::XStorable > xStor( xDicTmp, uno::UNO_QUERY );
LanguageType nActLanguage = LanguageTag( xDicTmp->getLocale() ).getLanguageType();
if( xDicTmp->isActive()
&& xDicTmp->getDictionaryType() != linguistic2::DictionaryType_NEGATIVE
&& (nCheckedLanguage == nActLanguage || LANGUAGE_NONE == nActLanguage )
&& (!xStor.is() || !xStor->isReadonly()) )
{
// the extra 1 is because of the (possible) external
// linguistic entry above
sal_uInt16 nPos = MN_DICTSTART + i;
pInsertMenu->InsertItem( nPos, xDicTmp->getName() );
aDicNameSingle = xDicTmp->getName();
uno::Reference< lang::XServiceInfo > xSvcInfo( xDicTmp, uno::UNO_QUERY );
if (xSvcInfo.is())
{
OUString aDictionaryImageUrl( aCfg.GetSpellAndGrammarContextDictionaryImage(
xSvcInfo->getImplementationName()) );
if (!aDictionaryImageUrl.isEmpty() )
{
Image aImage( aDictionaryImageUrl );
pInsertMenu->SetItemImage( nPos, aImage );
}
}
}
}
}
if (pInsertMenu->GetItemCount() != 1)
aPopupMenu->EnableItem(nAddId, false);
if (pInsertMenu->GetItemCount() < 2)
aPopupMenu->EnableItem(nInsertId, false);
aPopupMenu->RemoveDisabledEntries( true, true );
tools::Rectangle aTempRect = pImpEditView->pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, GetCursorFlags::TextOnly );
Point aScreenPos = pImpEditView->GetWindowPos( aTempRect.TopLeft() );
aScreenPos = pImpEditView->GetWindow()->OutputToScreenPixel( aScreenPos );
aTempRect = pImpEditView->GetWindow()->LogicToPixel( tools::Rectangle(aScreenPos, aTempRect.GetSize() ));
//tdf#106123 store and restore the EditPaM around the menu Execute
//because the loss of focus in the current editeng causes writer
//annotations to save their contents, making the pContent of the
//current EditPams invalid
EPaM aP = pImpEditView->pEditEngine->pImpEditEngine->CreateEPaM(aPaM);
EPaM aP2 = pImpEditView->pEditEngine->pImpEditEngine->CreateEPaM(aPaM2);
if (comphelper::LibreOfficeKit::isActive())
aPopupMenu->SetLOKNotifier(SfxViewShell::Current());
sal_uInt16 nId = aPopupMenu->Execute(pImpEditView->GetWindow(), aTempRect, PopupMenuFlags::NoMouseUpClose);
aPaM2 = pImpEditView->pEditEngine->pImpEditEngine->CreateEditPaM(aP2);
aPaM = pImpEditView->pEditEngine->pImpEditEngine->CreateEditPaM(aP);
if (nId == nIgnoreId)
{
OUString aWord = pImpEditView->SpellIgnoreWord();
if ( pCallBack )
{
SpellCallbackInfo aInf( SpellCallbackCommand::IGNOREWORD, aWord );
pCallBack->Call( aInf );
}
SetSelection( aOldSel );
}
else if ( ( nId == MN_WORDLANGUAGE ) || ( nId == MN_PARALANGUAGE ) )
{
LanguageType nLangToUse = (nId == MN_WORDLANGUAGE) ? nGuessLangWord : nGuessLangPara;
SvtScriptType nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( nLangToUse );
SfxItemSet aAttrs = GetEditEngine()->GetEmptyItemSet();
if (nScriptType == SvtScriptType::LATIN)
aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE ) );
if (nScriptType == SvtScriptType::COMPLEX)
aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE_CTL ) );
if (nScriptType == SvtScriptType::ASIAN)
aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE_CJK ) );
if ( nId == MN_PARALANGUAGE )
{
ESelection aSel = GetSelection();
aSel.nStartPos = 0;
aSel.nEndPos = EE_TEXTPOS_ALL;
SetSelection( aSel );
}
SetAttribs( aAttrs );
pImpEditView->pEditEngine->pImpEditEngine->StartOnlineSpellTimer();
if ( pCallBack )
{
SpellCallbackInfo aInf( ( nId == MN_WORDLANGUAGE ) ? SpellCallbackCommand::WORDLANGUAGE : SpellCallbackCommand::PARALANGUAGE );
pCallBack->Call( aInf );
}
SetSelection( aOldSel );
}
else if (nId == nCheckId)
{
if ( !pCallBack )
{
// Set Cursor before word...
EditPaM aCursor = pImpEditView->GetEditSelection().Min();
pImpEditView->DrawSelectionXOR();
pImpEditView->SetEditSelection( EditSelection( aCursor, aCursor ) );
pImpEditView->DrawSelectionXOR();
// Crashes when no SfxApp
pImpEditView->pEditEngine->pImpEditEngine->Spell( this, false );
}
else
{
SpellCallbackInfo aInf( SpellCallbackCommand::STARTSPELLDLG, OUString() );
pCallBack->Call( aInf );
}
}
else if (nId == nAutoCorrectDlgId && pCallBack)
{
SpellCallbackInfo aInf( SpellCallbackCommand::AUTOCORRECT_OPTIONS, OUString() );
pCallBack->Call( aInf );
}
else if ( nId >= MN_DICTSTART || nId == nAddId)
{
OUString aDicName;
if (nId >= MN_DICTSTART)
aDicName = pInsertMenu->GetItemText(nId);
else
aDicName = aDicNameSingle;
uno::Reference< linguistic2::XDictionary > xDic;
if (xDicList.is())
xDic = xDicList->getDictionaryByName( aDicName );
if (xDic.is())
xDic->add( aSelected, false, OUString() );
// save modified user-dictionary if it is persistent
Reference< frame::XStorable > xSavDic( xDic, UNO_QUERY );
if (xSavDic.is())
xSavDic->store();
aPaM.GetNode()->GetWrongList()->ResetInvalidRange(0, aPaM.GetNode()->Len());
pImpEditView->pEditEngine->pImpEditEngine->StartOnlineSpellTimer();
if ( pCallBack )
{
SpellCallbackInfo aInf( SpellCallbackCommand::ADDTODICTIONARY, aSelected );
pCallBack->Call( aInf );
}
SetSelection( aOldSel );
}
else if ( nId >= MN_AUTOSTART )
{
DBG_ASSERT(nId - MN_AUTOSTART < aAlt.getLength(), "index out of range");
OUString aWord = pAlt[nId - MN_AUTOSTART];
SvxAutoCorrect* pAutoCorrect = SvxAutoCorrCfg::Get().GetAutoCorrect();
if ( pAutoCorrect )
pAutoCorrect->PutText( aSelected, aWord, pImpEditView->pEditEngine->pImpEditEngine->GetLanguage( aPaM2 ) );
InsertText( aWord );
}
else if ( nId >= MN_ALTSTART ) // Replace
{
DBG_ASSERT(nId - MN_ALTSTART < aAlt.getLength(), "index out of range");
OUString aWord = pAlt[nId - MN_ALTSTART];
InsertText( aWord );
}
else
{
SetSelection( aOldSel );
}
}
}
void EditView::SelectCurrentWord( sal_Int16 nWordType )
{
EditSelection aCurSel( pImpEditView->GetEditSelection() );
pImpEditView->DrawSelectionXOR();
aCurSel = pImpEditView->pEditEngine->SelectWord(aCurSel.Max(), nWordType);
pImpEditView->SetEditSelection( aCurSel );
pImpEditView->DrawSelectionXOR();
ShowCursor( true, false );
}
void EditView::InsertParaBreak()
{
pImpEditView->pEditEngine->UndoActionStart(EDITUNDO_INSERT);
pImpEditView->DeleteSelected();
EditPaM aPaM(pImpEditView->pEditEngine->InsertParaBreak(pImpEditView->GetEditSelection()));
pImpEditView->pEditEngine->UndoActionEnd();
pImpEditView->SetEditSelection(EditSelection(aPaM, aPaM));
pImpEditView->pEditEngine->FormatAndUpdate(this);
}
void EditView::InsertField( const SvxFieldItem& rFld )
{
EditEngine* pEE = pImpEditView->pEditEngine;
pImpEditView->DrawSelectionXOR();
pEE->UndoActionStart( EDITUNDO_INSERT );
EditPaM aPaM( pEE->InsertField( pImpEditView->GetEditSelection(), rFld ) );
pEE->UndoActionEnd();
pImpEditView->SetEditSelection( EditSelection( aPaM, aPaM ) );
pEE->UpdateFields();
pEE->FormatAndUpdate( this );
}
const SvxFieldItem* EditView::GetFieldUnderMousePointer() const
{
sal_Int32 nPara;
sal_Int32 nPos;
return GetFieldUnderMousePointer( nPara, nPos );
}
const SvxFieldItem* EditView::GetField( const Point& rPos, sal_Int32* pPara, sal_Int32* pPos ) const
{
return pImpEditView->GetField( rPos, pPara, pPos );
}
const SvxFieldItem* EditView::GetFieldUnderMousePointer( sal_Int32& nPara, sal_Int32& nPos ) const
{
Point aPos = pImpEditView->GetWindow()->GetPointerPosPixel();
aPos = pImpEditView->GetWindow()->PixelToLogic( aPos );
return GetField( aPos, &nPara, &nPos );
}
const SvxFieldItem* EditView::GetFieldAtSelection() const
{
EditSelection aSel( pImpEditView->GetEditSelection() );
aSel.Adjust( pImpEditView->pEditEngine->GetEditDoc() );
// Only when cursor is in font of field, no selection,
// or only selecting field
if ( ( aSel.Min().GetNode() == aSel.Max().GetNode() ) &&
( ( aSel.Max().GetIndex() == aSel.Min().GetIndex() ) ||
( aSel.Max().GetIndex() == aSel.Min().GetIndex()+1 ) ) )
{
EditPaM aPaM = aSel.Min();
const CharAttribList::AttribsType& rAttrs = aPaM.GetNode()->GetCharAttribs().GetAttribs();
const sal_Int32 nXPos = aPaM.GetIndex();
for (size_t nAttr = rAttrs.size(); nAttr; )
{
const EditCharAttrib& rAttr = *rAttrs[--nAttr].get();
if (rAttr.GetStart() == nXPos)
if (rAttr.Which() == EE_FEATURE_FIELD)
{
DBG_ASSERT(dynamic_cast<const SvxFieldItem* >(rAttr.GetItem() ) != nullptr, "No FieldItem...");
return static_cast<const SvxFieldItem*>(rAttr.GetItem());
}
}
}
return nullptr;
}
void EditView::SetInvalidateMore( sal_uInt16 nPixel )
{
pImpEditView->SetInvalidateMore( nPixel );
}
sal_uInt16 EditView::GetInvalidateMore() const
{
return pImpEditView->GetInvalidateMore();
}
static void ChangeFontSizeImpl( EditView* pEditView, bool bGrow, const ESelection& rSel, const FontList* pFontList )
{
pEditView->SetSelection( rSel );
SfxItemSet aSet( pEditView->GetAttribs() );
if( EditView::ChangeFontSize( bGrow, aSet, pFontList ) )
{
SfxItemSet aNewSet( pEditView->GetEmptyItemSet() );
aNewSet.Put( aSet.Get( EE_CHAR_FONTHEIGHT ) );
aNewSet.Put( aSet.Get( EE_CHAR_FONTHEIGHT_CJK ) );
aNewSet.Put( aSet.Get( EE_CHAR_FONTHEIGHT_CTL ) );
pEditView->SetAttribs( aNewSet );
}
}
void EditView::ChangeFontSize( bool bGrow, const FontList* pFontList )
{
EditEngine& rEditEngine = *pImpEditView->pEditEngine;
ESelection aSel( GetSelection() );
ESelection aOldSelection( aSel );
aSel.Adjust();
if( !aSel.HasRange() )
{
aSel = rEditEngine.GetWord( aSel, css::i18n::WordType::DICTIONARY_WORD );
}
if( aSel.HasRange() )
{
for( sal_Int32 nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++ )
{
std::vector<sal_Int32> aPortions;
rEditEngine.GetPortions( nPara, aPortions );
if( aPortions.empty() )
aPortions.push_back( rEditEngine.GetTextLen(nPara) );
const sal_Int32 nBeginPos = (nPara == aSel.nStartPara) ? aSel.nStartPos : 0;
const sal_Int32 nEndPos = (nPara == aSel.nEndPara) ? aSel.nEndPos : EE_TEXTPOS_ALL;
for ( size_t nPos = 0; nPos < aPortions.size(); ++nPos )
{
sal_Int32 nPortionEnd = aPortions[ nPos ];
sal_Int32 nPortionStart = nPos > 0 ? aPortions[ nPos - 1 ] : 0;
if( (nPortionEnd < nBeginPos) || (nPortionStart > nEndPos) )
continue;
if( nPortionStart < nBeginPos )
nPortionStart = nBeginPos;
if( nPortionEnd > nEndPos )
nPortionEnd = nEndPos;
if( nPortionStart == nPortionEnd )
continue;
ESelection aPortionSel( nPara, nPortionStart, nPara, nPortionEnd );
ChangeFontSizeImpl( this, bGrow, aPortionSel, pFontList );
}
}
}
else
{
ChangeFontSizeImpl( this, bGrow, aSel, pFontList );
}
SetSelection( aOldSelection );
}
bool EditView::ChangeFontSize( bool bGrow, SfxItemSet& rSet, const FontList* pFontList )
{
static const sal_uInt16 gFontSizeWichMap[] = { EE_CHAR_FONTHEIGHT, EE_CHAR_FONTHEIGHT_CJK, EE_CHAR_FONTHEIGHT_CTL, 0 };
const SvxFontItem* pFontItem = &rSet.Get( EE_CHAR_FONTINFO );
if( !pFontItem || !pFontList )
return false;
bool bRet = false;
const sal_uInt16* pWhich = gFontSizeWichMap;
while( *pWhich )
{
SvxFontHeightItem aFontHeightItem( static_cast<const SvxFontHeightItem&>(rSet.Get( *pWhich )) );
long nHeight = aFontHeightItem.GetHeight();
const MapUnit eUnit = rSet.GetPool()->GetMetric( *pWhich );
nHeight = OutputDevice::LogicToLogic(nHeight * 10, eUnit, MapUnit::MapPoint);
FontMetric aFontMetric = pFontList->Get( pFontItem->GetFamilyName(), pFontItem->GetStyleName() );
const sal_IntPtr* pAry = pFontList->GetSizeAry( aFontMetric );
if( bGrow )
{
while( *pAry )
{
if( *pAry > nHeight )
{
nHeight = *pAry;
break;
}
pAry++;
}
if( *pAry == 0 )
{
nHeight += (nHeight + 5) / 10;
if( nHeight > 9999 )
nHeight = 9999;
}
}
else if( *pAry )
{
bool bFound = false;
if( *pAry < nHeight )
{
pAry++;
while( *pAry )
{
if( *pAry >= nHeight )
{
nHeight = pAry[-1];
bFound = true;
break;
}
pAry++;
}
}
if( !bFound )
{
nHeight -= (nHeight + 5) / 10;
if( nHeight < 2 )
nHeight = 2;
}
}
if( (nHeight >= 2) && (nHeight <= 9999 ) )
{
nHeight = OutputDevice::LogicToLogic( nHeight, MapUnit::MapPoint, eUnit ) / 10;
if( nHeight != static_cast<long>(aFontHeightItem.GetHeight()) )
{
aFontHeightItem.SetHeight( nHeight );
std::unique_ptr<SfxPoolItem> pNewItem(aFontHeightItem.CloneSetWhich(*pWhich));
rSet.Put( *pNewItem );
bRet = true;
}
}
pWhich++;
}
return bRet;
}
OUString EditView::GetSurroundingText() const
{
EditSelection aSel( pImpEditView->GetEditSelection() );
aSel.Adjust( pImpEditView->pEditEngine->GetEditDoc() );
if( HasSelection() )
{
OUString aStr = pImpEditView->pEditEngine->GetSelected(aSel);
// Stop reconversion if the selected text includes a line break.
if ( aStr.indexOf( 0x0A ) == -1 )
return aStr;
else
return OUString();
}
else
{
aSel.Min().SetIndex( 0 );
aSel.Max().SetIndex( aSel.Max().GetNode()->Len() );
return pImpEditView->pEditEngine->GetSelected(aSel);
}
}
Selection EditView::GetSurroundingTextSelection() const
{
ESelection aSelection( GetSelection() );
aSelection.Adjust();
if( HasSelection() )
{
EditSelection aSel( pImpEditView->GetEditSelection() );
aSel.Adjust( pImpEditView->pEditEngine->GetEditDoc() );
OUString aStr = pImpEditView->pEditEngine->GetSelected(aSel);
// Stop reconversion if the selected text includes a line break.
if ( aStr.indexOf( 0x0A ) == -1 )
return Selection( 0, aSelection.nEndPos - aSelection.nStartPos );
else
return Selection( 0, 0 );
}
else
{
return Selection( aSelection.nStartPos, aSelection.nEndPos );
}
}
void EditView::SetCursorLogicPosition(const Point& rPosition, bool bPoint, bool bClearMark)
{
Point aDocPos(pImpEditView->GetDocPos(rPosition));
EditPaM aPaM = pImpEditView->pEditEngine->GetPaM(aDocPos);
EditSelection aSelection(pImpEditView->GetEditSelection());
// Explicitly create or delete the selection.
if (bClearMark)
{
pImpEditView->DeselectAll();
aSelection = pImpEditView->GetEditSelection();
}
else
pImpEditView->CreateAnchor();
if (bPoint)
aSelection.Max() = aPaM;
else
aSelection.Min() = aPaM;
if (pImpEditView->GetEditSelection().Min() != aSelection.Min())
pImpEditView->pEditEngine->CursorMoved(pImpEditView->GetEditSelection().Min().GetNode());
pImpEditView->DrawSelectionXOR(aSelection);
if (pImpEditView->GetEditSelection() != aSelection)
pImpEditView->SetEditSelection(aSelection);
ShowCursor(/*bGotoCursor=*/false);
}
void EditView::DrawSelectionXOR(OutlinerViewShell* pOtherShell)
{
pImpEditView->RegisterOtherShell(pOtherShell);
pImpEditView->DrawSelectionXOR();
pImpEditView->RegisterOtherShell(nullptr);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V560 A part of conditional expression is always false: !pFontItem.