diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /vcl/source/edit/vclmedit.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vcl/source/edit/vclmedit.cxx')
-rw-r--r-- | vcl/source/edit/vclmedit.cxx | 1509 |
1 files changed, 1509 insertions, 0 deletions
diff --git a/vcl/source/edit/vclmedit.cxx b/vcl/source/edit/vclmedit.cxx new file mode 100644 index 0000000000..d519735859 --- /dev/null +++ b/vcl/source/edit/vclmedit.cxx @@ -0,0 +1,1509 @@ +/* -*- 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 <i18nlangtag/languagetag.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/builder.hxx> +#include <vcl/decoview.hxx> +#include <vcl/event.hxx> +#include <vcl/menu.hxx> +#include <vcl/specialchars.hxx> +#include <vcl/timer.hxx> +#include <vcl/vclevent.hxx> +#include <vcl/xtextedt.hxx> +#include <vcl/textview.hxx> +#include <vcl/ptrstyle.hxx> + +#include <svl/undo.hxx> +#include <svl/lstner.hxx> +#include <vcl/uitest/uiobject.hxx> + +#include <vcl/settings.hxx> +#include <vcl/toolkit/scrbar.hxx> +#include <vcl/toolkit/vclmedit.hxx> +#include <vcl/weld.hxx> +#include <osl/diagnose.h> +#include <tools/json_writer.hxx> +#include <strings.hrc> +#include <svdata.hxx> + +class ImpVclMEdit : public SfxListener +{ +private: + VclPtr<VclMultiLineEdit> pVclMultiLineEdit; + + VclPtr<TextWindow> mpTextWindow; + VclPtr<ScrollBar> mpHScrollBar; + VclPtr<ScrollBar> mpVScrollBar; + VclPtr<ScrollBarBox> mpScrollBox; + + tools::Long mnTextWidth; + mutable Selection maSelection; + +protected: + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override; + void ImpUpdateScrollBarVis( WinBits nWinStyle ); + void ImpInitScrollBars(); + void ImpSetScrollBarRanges(); + void ImpSetHScrollBarThumbPos(); + DECL_LINK( ScrollHdl, ScrollBar*, void ); + +public: + ImpVclMEdit( VclMultiLineEdit* pVclMultiLineEdit, WinBits nWinStyle ); + virtual ~ImpVclMEdit() override; + + void SetModified( bool bMod ); + + void SetReadOnly( bool bRdOnly ); + bool IsReadOnly() const; + + void SetMaxTextLen(sal_Int32 nLen); + sal_Int32 GetMaxTextLen() const; + + void SetMaxTextWidth(tools::Long nMaxWidth); + + void InsertText( const OUString& rStr ); + OUString GetSelected() const; + OUString GetSelected( LineEnd aSeparator ) const; + + void SetSelection( const Selection& rSelection ); + const Selection& GetSelection() const; + + void Cut(); + void Copy(); + void Paste(); + + void SetText( const OUString& rStr ); + OUString GetText() const; + OUString GetText( LineEnd aSeparator ) const; + OUString GetTextLines( LineEnd aSeparator ) const; + + void Resize(); + void GetFocus(); + + bool HandleCommand( const CommandEvent& rCEvt ); + + void Enable( bool bEnable ); + + Size CalcMinimumSize() const; + Size CalcBlockSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const; + void GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const; + + void SetAlign( WinBits nWinStyle ); + + void InitFromStyle( WinBits nWinStyle ); + + TextWindow* GetTextWindow() { return mpTextWindow; } + ScrollBar& GetHScrollBar() { return *mpHScrollBar; } + ScrollBar& GetVScrollBar() { return *mpVScrollBar; } +}; + +ImpVclMEdit::ImpVclMEdit( VclMultiLineEdit* pEdt, WinBits nWinStyle ) + : pVclMultiLineEdit(pEdt) + , mpTextWindow(VclPtr<TextWindow>::Create(pEdt)) + , mpHScrollBar(VclPtr<ScrollBar>::Create(pVclMultiLineEdit, WB_HSCROLL|WB_DRAG)) + , mpVScrollBar(VclPtr<ScrollBar>::Create(pVclMultiLineEdit, WB_VSCROLL|WB_DRAG)) + , mpScrollBox(VclPtr<ScrollBarBox>::Create(pVclMultiLineEdit, WB_SIZEABLE)) + , mnTextWidth(0) +{ + mpVScrollBar->SetScrollHdl( LINK( this, ImpVclMEdit, ScrollHdl ) ); + mpHScrollBar->SetScrollHdl( LINK( this, ImpVclMEdit, ScrollHdl ) ); + mpTextWindow->Show(); + InitFromStyle( nWinStyle ); + StartListening( *mpTextWindow->GetTextEngine() ); +} + +void ImpVclMEdit::ImpUpdateScrollBarVis( WinBits nWinStyle ) +{ + const bool bHaveVScroll = mpVScrollBar->IsVisible(); + const bool bHaveHScroll = mpHScrollBar->IsVisible(); + const bool bHaveScrollBox = mpScrollBox->IsVisible(); + + bool bNeedVScroll = ( nWinStyle & WB_VSCROLL ) == WB_VSCROLL; + const bool bNeedHScroll = ( nWinStyle & WB_HSCROLL ) == WB_HSCROLL; + + const bool bAutoVScroll = ( nWinStyle & WB_AUTOVSCROLL ) == WB_AUTOVSCROLL; + if ( !bNeedVScroll && bAutoVScroll ) + { + TextEngine& rEngine( *mpTextWindow->GetTextEngine() ); + tools::Long nOverallTextHeight(0); + for ( sal_uInt32 i=0; i<rEngine.GetParagraphCount(); ++i ) + nOverallTextHeight += rEngine.GetTextHeight( i ); + if ( nOverallTextHeight > mpTextWindow->GetOutputSizePixel().Height() ) + bNeedVScroll = true; + } + + const bool bNeedScrollBox = bNeedVScroll && bNeedHScroll; + + bool bScrollbarsChanged = false; + if ( bHaveVScroll != bNeedVScroll ) + { + mpVScrollBar->Show(bNeedVScroll); + bScrollbarsChanged = true; + } + + if ( bHaveHScroll != bNeedHScroll ) + { + mpHScrollBar->Show(bNeedHScroll); + bScrollbarsChanged = true; + } + + if ( bHaveScrollBox != bNeedScrollBox ) + { + mpScrollBox->Show(bNeedScrollBox); + } + + if ( bScrollbarsChanged ) + { + ImpInitScrollBars(); + Resize(); + } +} + +void ImpVclMEdit::InitFromStyle( WinBits nWinStyle ) +{ + ImpUpdateScrollBarVis( nWinStyle ); + SetAlign( nWinStyle ); + + if ( nWinStyle & WB_NOHIDESELECTION ) + mpTextWindow->SetAutoFocusHide( false ); + else + mpTextWindow->SetAutoFocusHide( true ); + + if ( nWinStyle & WB_READONLY ) + mpTextWindow->GetTextView()->SetReadOnly( true ); + else + mpTextWindow->GetTextView()->SetReadOnly( false ); + + if ( nWinStyle & WB_IGNORETAB ) + { + mpTextWindow->SetIgnoreTab( true ); + } + else + { + mpTextWindow->SetIgnoreTab( false ); + // #103667# VclMultiLineEdit has the flag, but focusable window also needs this flag + WinBits nStyle = mpTextWindow->GetStyle(); + nStyle |= WB_NODIALOGCONTROL; + mpTextWindow->SetStyle( nStyle ); + } +} + +ImpVclMEdit::~ImpVclMEdit() +{ + EndListening( *mpTextWindow->GetTextEngine() ); + mpTextWindow.disposeAndClear(); + mpHScrollBar.disposeAndClear(); + mpVScrollBar.disposeAndClear(); + mpScrollBox.disposeAndClear(); + pVclMultiLineEdit.disposeAndClear(); +} + +void ImpVclMEdit::ImpSetScrollBarRanges() +{ + const tools::Long nTextHeight = mpTextWindow->GetTextEngine()->GetTextHeight(); + mpVScrollBar->SetRange( Range( 0, nTextHeight-1 ) ); + + mpHScrollBar->SetRange( Range( 0, mnTextWidth-1 ) ); +} + +void ImpVclMEdit::ImpInitScrollBars() +{ + static const sal_Unicode sampleChar = { 'x' }; + + ImpSetScrollBarRanges(); + + Size aCharBox; + aCharBox.setWidth( mpTextWindow->GetTextWidth( OUString(sampleChar) ) ); + aCharBox.setHeight( mpTextWindow->GetTextHeight() ); + Size aOutSz = mpTextWindow->GetOutputSizePixel(); + + mpHScrollBar->SetVisibleSize( aOutSz.Width() ); + mpHScrollBar->SetPageSize( aOutSz.Width() * 8 / 10 ); + mpHScrollBar->SetLineSize( aCharBox.Width()*10 ); + ImpSetHScrollBarThumbPos(); + + mpVScrollBar->SetVisibleSize( aOutSz.Height() ); + mpVScrollBar->SetPageSize( aOutSz.Height() * 8 / 10 ); + mpVScrollBar->SetLineSize( aCharBox.Height() ); + mpVScrollBar->SetThumbPos( mpTextWindow->GetTextView()->GetStartDocPos().Y() ); +} + +void ImpVclMEdit::ImpSetHScrollBarThumbPos() +{ + tools::Long nX = mpTextWindow->GetTextView()->GetStartDocPos().X(); + if ( !mpTextWindow->GetTextEngine()->IsRightToLeft() ) + mpHScrollBar->SetThumbPos( nX ); + else + mpHScrollBar->SetThumbPos( mnTextWidth - mpHScrollBar->GetVisibleSize() - nX ); + +} + +IMPL_LINK( ImpVclMEdit, ScrollHdl, ScrollBar*, pCurScrollBar, void ) +{ + tools::Long nDiffX = 0, nDiffY = 0; + + if ( pCurScrollBar == mpVScrollBar ) + nDiffY = mpTextWindow->GetTextView()->GetStartDocPos().Y() - pCurScrollBar->GetThumbPos(); + else if ( pCurScrollBar == mpHScrollBar ) + nDiffX = mpTextWindow->GetTextView()->GetStartDocPos().X() - pCurScrollBar->GetThumbPos(); + + mpTextWindow->GetTextView()->Scroll( nDiffX, nDiffY ); + // mpTextWindow->GetTextView()->ShowCursor( false, true ); +} + +void ImpVclMEdit::SetAlign( WinBits nWinStyle ) +{ + bool bRTL = AllSettings::GetLayoutRTL(); + mpTextWindow->GetTextEngine()->SetRightToLeft( bRTL ); + + if ( nWinStyle & WB_CENTER ) + mpTextWindow->GetTextEngine()->SetTextAlign( TxtAlign::Center ); + else if ( nWinStyle & WB_RIGHT ) + mpTextWindow->GetTextEngine()->SetTextAlign( !bRTL ? TxtAlign::Right : TxtAlign::Left ); + else if ( nWinStyle & WB_LEFT ) + mpTextWindow->GetTextEngine()->SetTextAlign( !bRTL ? TxtAlign::Left : TxtAlign::Right ); +} + +void ImpVclMEdit::SetModified( bool bMod ) +{ + mpTextWindow->GetTextEngine()->SetModified( bMod ); +} + +void ImpVclMEdit::SetReadOnly( bool bRdOnly ) +{ + mpTextWindow->GetTextView()->SetReadOnly( bRdOnly ); + // TODO: Adjust color? +} + +bool ImpVclMEdit::IsReadOnly() const +{ + return mpTextWindow->GetTextView()->IsReadOnly(); +} + +void ImpVclMEdit::SetMaxTextLen(sal_Int32 nLen) +{ + mpTextWindow->GetTextEngine()->SetMaxTextLen(nLen); +} + +sal_Int32 ImpVclMEdit::GetMaxTextLen() const +{ + return mpTextWindow->GetTextEngine()->GetMaxTextLen(); +} + +void ImpVclMEdit::InsertText( const OUString& rStr ) +{ + mpTextWindow->GetTextView()->InsertText( rStr ); +} + +OUString ImpVclMEdit::GetSelected() const +{ + return mpTextWindow->GetTextView()->GetSelected(); +} + +OUString ImpVclMEdit::GetSelected( LineEnd aSeparator ) const +{ + return mpTextWindow->GetTextView()->GetSelected( aSeparator ); +} + +void ImpVclMEdit::SetMaxTextWidth(tools::Long nMaxWidth) +{ + mpTextWindow->GetTextEngine()->SetMaxTextWidth(nMaxWidth); +} + +void ImpVclMEdit::Resize() +{ + int nIteration = 1; + do + { + WinBits nWinStyle( pVclMultiLineEdit->GetStyle() ); + if ( ( nWinStyle & WB_AUTOVSCROLL ) == WB_AUTOVSCROLL ) + ImpUpdateScrollBarVis( nWinStyle ); + + Size aSz = pVclMultiLineEdit->GetOutputSizePixel(); + Size aEditSize = aSz; + tools::Long nSBWidth = pVclMultiLineEdit->GetSettings().GetStyleSettings().GetScrollBarSize(); + nSBWidth = pVclMultiLineEdit->CalcZoom( nSBWidth ); + + if (mpHScrollBar->IsVisible()) + aSz.AdjustHeight( -(nSBWidth+1) ); + if (mpVScrollBar->IsVisible()) + aSz.AdjustWidth( -(nSBWidth+1) ); + + if (!mpHScrollBar->IsVisible()) + mpTextWindow->GetTextEngine()->SetMaxTextWidth( aSz.Width() ); + else + mpHScrollBar->setPosSizePixel( 0, aEditSize.Height()-nSBWidth, aSz.Width(), nSBWidth ); + + Point aTextWindowPos; + if (mpVScrollBar->IsVisible()) + { + if( AllSettings::GetLayoutRTL() ) + { + mpVScrollBar->setPosSizePixel( 0, 0, nSBWidth, aSz.Height() ); + aTextWindowPos.AdjustX(nSBWidth ); + } + else + mpVScrollBar->setPosSizePixel( aEditSize.Width()-nSBWidth, 0, nSBWidth, aSz.Height() ); + } + + if (mpScrollBox->IsVisible()) + mpScrollBox->setPosSizePixel( aSz.Width(), aSz.Height(), nSBWidth, nSBWidth ); + + Size aTextWindowSize( aSz ); + if ( aTextWindowSize.Width() < 0 ) + aTextWindowSize.setWidth( 0 ); + if ( aTextWindowSize.Height() < 0 ) + aTextWindowSize.setHeight( 0 ); + + Size aOldTextWindowSize( mpTextWindow->GetSizePixel() ); + mpTextWindow->SetPosSizePixel( aTextWindowPos, aTextWindowSize ); + if ( aOldTextWindowSize == aTextWindowSize ) + break; + + // Changing the text window size might effectively have changed the need for + // scrollbars, so do another iteration. + ++nIteration; + OSL_ENSURE( nIteration < 3, "ImpVclMEdit::Resize: isn't this expected to terminate with the second iteration?" ); + + } while ( nIteration <= 3 ); // artificial break after four iterations + + ImpInitScrollBars(); +} + +void ImpVclMEdit::GetFocus() +{ + mpTextWindow->GrabFocus(); +} + +void ImpVclMEdit::Cut() +{ + if ( !mpTextWindow->GetTextView()->IsReadOnly() ) + mpTextWindow->GetTextView()->Cut(); +} + +void ImpVclMEdit::Copy() +{ + mpTextWindow->GetTextView()->Copy(); +} + +void ImpVclMEdit::Paste() +{ + if ( !mpTextWindow->GetTextView()->IsReadOnly() ) + mpTextWindow->GetTextView()->Paste(); +} + +void ImpVclMEdit::SetText( const OUString& rStr ) +{ + bool bWasModified = mpTextWindow->GetTextEngine()->IsModified(); + mpTextWindow->GetTextEngine()->SetText( rStr ); + if ( !bWasModified ) + mpTextWindow->GetTextEngine()->SetModified( false ); + + mpTextWindow->GetTextView()->SetSelection( TextSelection() ); + + WinBits nWinStyle( pVclMultiLineEdit->GetStyle() ); + if ( ( nWinStyle & WB_AUTOVSCROLL ) == WB_AUTOVSCROLL ) + ImpUpdateScrollBarVis( nWinStyle ); +} + +OUString ImpVclMEdit::GetText() const +{ + return mpTextWindow->GetTextEngine()->GetText(); +} + +OUString ImpVclMEdit::GetText( LineEnd aSeparator ) const +{ + return mpTextWindow->GetTextEngine()->GetText( aSeparator ); +} + +OUString ImpVclMEdit::GetTextLines( LineEnd aSeparator ) const +{ + return mpTextWindow->GetTextEngine()->GetTextLines( aSeparator ); +} + +void ImpVclMEdit::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + const TextHint* pTextHint = dynamic_cast<const TextHint*>(&rHint); + if ( !pTextHint ) + return; + + switch (pTextHint->GetId()) + { + case SfxHintId::TextViewScrolled: + if (mpHScrollBar->IsVisible()) + ImpSetHScrollBarThumbPos(); + if (mpVScrollBar->IsVisible()) + mpVScrollBar->SetThumbPos( mpTextWindow->GetTextView()->GetStartDocPos().Y() ); + break; + + case SfxHintId::TextHeightChanged: + if ( mpTextWindow->GetTextView()->GetStartDocPos().Y() ) + { + tools::Long nOutHeight = mpTextWindow->GetOutputSizePixel().Height(); + tools::Long nTextHeight = mpTextWindow->GetTextEngine()->GetTextHeight(); + if ( nTextHeight < nOutHeight ) + mpTextWindow->GetTextView()->Scroll( 0, mpTextWindow->GetTextView()->GetStartDocPos().Y() ); + } + ImpSetScrollBarRanges(); + break; + + case SfxHintId::TextFormatted: + if (mpHScrollBar->IsVisible()) + { + const tools::Long nWidth = mpTextWindow->GetTextEngine()->CalcTextWidth(); + if ( nWidth != mnTextWidth ) + { + mnTextWidth = nWidth; + mpHScrollBar->SetRange( Range( 0, mnTextWidth-1 ) ); + ImpSetHScrollBarThumbPos(); + } + } + break; + + case SfxHintId::TextModified: + ImpUpdateScrollBarVis(pVclMultiLineEdit->GetStyle()); + pVclMultiLineEdit->Modify(); + break; + + case SfxHintId::TextViewSelectionChanged: + pVclMultiLineEdit->SelectionChanged(); + break; + + case SfxHintId::TextViewCaretChanged: + pVclMultiLineEdit->CaretChanged(); + break; + + default: break; + } +} + +void ImpVclMEdit::SetSelection( const Selection& rSelection ) +{ + OUString aText = mpTextWindow->GetTextEngine()->GetText(); + + Selection aNewSelection( rSelection ); + if ( aNewSelection.Min() < 0 ) + aNewSelection.Min() = 0; + else if ( aNewSelection.Min() > aText.getLength() ) + aNewSelection.Min() = aText.getLength(); + if ( aNewSelection.Max() < 0 ) + aNewSelection.Max() = 0; + else if ( aNewSelection.Max() > aText.getLength() ) + aNewSelection.Max() = aText.getLength(); + + tools::Long nEnd = std::max( aNewSelection.Min(), aNewSelection.Max() ); + TextSelection aTextSel; + sal_uInt32 nPara = 0; + sal_Int32 nChar = 0; + tools::Long x = 0; + while ( x <= nEnd ) + { + if ( x == aNewSelection.Min() ) + aTextSel.GetStart() = TextPaM( nPara, nChar ); + if ( x == aNewSelection.Max() ) + aTextSel.GetEnd() = TextPaM( nPara, nChar ); + + if ( ( x < aText.getLength() ) && ( aText[ x ] == '\n' ) ) + { + nPara++; + nChar = 0; + } + else + nChar++; + x++; + } + mpTextWindow->GetTextView()->SetSelection( aTextSel ); +} + +const Selection& ImpVclMEdit::GetSelection() const +{ + maSelection = Selection(); + TextSelection aTextSel( mpTextWindow->GetTextView()->GetSelection() ); + aTextSel.Justify(); + // flatten selection => every line-break a character + + ExtTextEngine* pExtTextEngine = mpTextWindow->GetTextEngine(); + // paragraphs before + for ( sal_uInt32 n = 0; n < aTextSel.GetStart().GetPara(); ++n ) + { + maSelection.Min() += pExtTextEngine->GetTextLen( n ); + maSelection.Min()++; + } + + // first paragraph with selection + maSelection.Max() = maSelection.Min(); + maSelection.Min() += aTextSel.GetStart().GetIndex(); + + for ( sal_uInt32 n = aTextSel.GetStart().GetPara(); n < aTextSel.GetEnd().GetPara(); ++n ) + { + maSelection.Max() += pExtTextEngine->GetTextLen( n ); + maSelection.Max()++; + } + + maSelection.Max() += aTextSel.GetEnd().GetIndex(); + + return maSelection; +} + +Size ImpVclMEdit::CalcMinimumSize() const +{ + Size aSz( mpTextWindow->GetTextEngine()->CalcTextWidth(), + mpTextWindow->GetTextEngine()->GetTextHeight() ); + + if (mpHScrollBar->IsVisible()) + aSz.AdjustHeight(mpHScrollBar->GetSizePixel().Height() ); + if (mpVScrollBar->IsVisible()) + aSz.AdjustWidth(mpVScrollBar->GetSizePixel().Width() ); + + return aSz; +} + +Size ImpVclMEdit::CalcBlockSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const +{ + static const sal_Unicode sampleChar = 'X'; + + Size aSz; + Size aCharSz; + aCharSz.setWidth( mpTextWindow->GetTextWidth( OUString(sampleChar) ) ); + aCharSz.setHeight( mpTextWindow->GetTextHeight() ); + + if ( nLines ) + aSz.setHeight( nLines*aCharSz.Height() ); + else + aSz.setHeight( mpTextWindow->GetTextEngine()->GetTextHeight() ); + + if ( nColumns ) + aSz.setWidth( nColumns*aCharSz.Width() ); + else + aSz.setWidth( mpTextWindow->GetTextEngine()->CalcTextWidth() ); + + if (mpHScrollBar->IsVisible()) + aSz.AdjustHeight(mpHScrollBar->GetSizePixel().Height() ); + if (mpVScrollBar->IsVisible()) + aSz.AdjustWidth(mpVScrollBar->GetSizePixel().Width() ); + + return aSz; +} + +void ImpVclMEdit::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const +{ + static const sal_Unicode sampleChar = { 'x' }; + Size aOutSz = mpTextWindow->GetOutputSizePixel(); + Size aCharSz( mpTextWindow->GetTextWidth( OUString(sampleChar) ), mpTextWindow->GetTextHeight() ); + rnCols = static_cast<sal_uInt16>(aOutSz.Width()/aCharSz.Width()); + rnLines = static_cast<sal_uInt16>(aOutSz.Height()/aCharSz.Height()); +} + +void ImpVclMEdit::Enable( bool bEnable ) +{ + mpTextWindow->Enable( bEnable ); + if (mpHScrollBar->IsVisible()) + mpHScrollBar->Enable( bEnable ); + if (mpVScrollBar->IsVisible()) + mpVScrollBar->Enable( bEnable ); +} + +bool ImpVclMEdit::HandleCommand( const CommandEvent& rCEvt ) +{ + bool bDone = false; + CommandEventId nCommand = rCEvt.GetCommand(); + if (nCommand == CommandEventId::Wheel || + nCommand == CommandEventId::StartAutoScroll || + nCommand == CommandEventId::AutoScroll || + nCommand == CommandEventId::GesturePan) + { + ScrollBar* pHScrollBar = mpHScrollBar->IsVisible() ? mpHScrollBar.get() : nullptr; + ScrollBar* pVScrollBar = mpVScrollBar->IsVisible() ? mpVScrollBar.get() : nullptr; + mpTextWindow->HandleScrollCommand(rCEvt, pHScrollBar, pVScrollBar); + bDone = true; + } + return bDone; +} + +TextWindow::TextWindow(Edit* pParent) + : Window(pParent) + , mxParent(pParent) +{ + mbInMBDown = false; + mbFocusSelectionHide = false; + mbIgnoreTab = false; + mbActivePopup = false; + mbSelectOnTab = true; + + SetPointer( PointerStyle::Text ); + + mpExtTextEngine.reset(new ExtTextEngine); + mpExtTextEngine->SetMaxTextLen(EDIT_NOLIMIT); + if( pParent->GetStyle() & WB_BORDER ) + mpExtTextEngine->SetLeftMargin( 2 ); + mpExtTextEngine->SetLocale( GetSettings().GetLanguageTag().getLocale() ); + mpExtTextView.reset(new TextView( mpExtTextEngine.get(), this )); + mpExtTextEngine->InsertView( mpExtTextView.get() ); + mpExtTextEngine->EnableUndo( true ); + mpExtTextView->ShowCursor(); + + Color aBackgroundColor = GetSettings().GetStyleSettings().GetWorkspaceColor(); + SetBackground( aBackgroundColor ); + pParent->SetBackground( aBackgroundColor ); +} + +TextWindow::~TextWindow() +{ + disposeOnce(); +} + +void TextWindow::dispose() +{ + mxParent.clear(); + mpExtTextView.reset(); + mpExtTextEngine.reset(); + Window::dispose(); +} + +void TextWindow::MouseMove( const MouseEvent& rMEvt ) +{ + mpExtTextView->MouseMove( rMEvt ); + Window::MouseMove( rMEvt ); +} + +void TextWindow::MouseButtonDown( const MouseEvent& rMEvt ) +{ + mbInMBDown = true; // so that GetFocus does not select everything + mpExtTextView->MouseButtonDown( rMEvt ); + GrabFocus(); + mbInMBDown = false; +} + +void TextWindow::MouseButtonUp( const MouseEvent& rMEvt ) +{ + mpExtTextView->MouseButtonUp( rMEvt ); +} + +void TextWindow::KeyInput( const KeyEvent& rKEvent ) +{ + bool bDone = false; + sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode(); + if ( nCode == css::awt::Key::SELECT_ALL || + ( (nCode == KEY_A) && rKEvent.GetKeyCode().IsMod1() && !rKEvent.GetKeyCode().IsMod2() ) + ) + { + mpExtTextView->SetSelection( TextSelection( TextPaM( 0, 0 ), TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ) ) ); + bDone = true; + } + else if ( (nCode == KEY_S) && rKEvent.GetKeyCode().IsShift() && rKEvent.GetKeyCode().IsMod1() ) + { + if ( vcl::GetGetSpecialCharsFunction() ) + { + // to maintain the selection + mbActivePopup = true; + OUString aChars = vcl::GetGetSpecialCharsFunction()(GetFrameWeld(), GetFont()); + if (!aChars.isEmpty()) + { + mpExtTextView->InsertText( aChars ); + mpExtTextView->GetTextEngine()->SetModified( true ); + } + mbActivePopup = false; + bDone = true; + } + } + else if ( nCode == KEY_TAB ) + { + if (!mbIgnoreTab) + { + if (!rKEvent.GetKeyCode().IsMod1()) + bDone = mpExtTextView->KeyInput(rKEvent); + else + { + // tdf#107625 make ctrl+tab act like tab when MultiLine Edit normally accepts tab as an input char + vcl::KeyCode aKeyCode(rKEvent.GetKeyCode().GetCode(), rKEvent.GetKeyCode().GetModifier() & ~KEY_MOD1); + KeyEvent aKEventWithoutMod1(rKEvent.GetCharCode(), aKeyCode, rKEvent.GetRepeat()); + Window::KeyInput(aKEventWithoutMod1); + bDone = true; + } + } + } + else + { + bDone = mpExtTextView->KeyInput( rKEvent ); + } + + if ( !bDone ) + Window::KeyInput( rKEvent ); +} + +void TextWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + mpExtTextView->Paint(rRenderContext, rRect); +} + +void TextWindow::Resize() +{ +} + +void TextWindow::Command( const CommandEvent& rCEvt ) +{ + if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) + { + VclPtr<PopupMenu> pPopup = mxParent->CreatePopupMenu(); + bool bEnableCut = true; + bool bEnableCopy = true; + bool bEnableDelete = true; + bool bEnablePaste = true; + bool bEnableSpecialChar = true; + bool bEnableUndo = true; + + if ( !mpExtTextView->HasSelection() ) + { + bEnableCut = false; + bEnableCopy = false; + bEnableDelete = false; + } + if ( mpExtTextView->IsReadOnly() ) + { + bEnableCut = false; + bEnablePaste = false; + bEnableDelete = false; + bEnableSpecialChar = false; + } + if ( !mpExtTextView->GetTextEngine()->HasUndoManager() || !mpExtTextView->GetTextEngine()->GetUndoManager().GetUndoActionCount() ) + { + bEnableUndo = false; + } + pPopup->EnableItem(pPopup->GetItemId(u"cut"), bEnableCut); + pPopup->EnableItem(pPopup->GetItemId(u"copy"), bEnableCopy); + pPopup->EnableItem(pPopup->GetItemId(u"delete"), bEnableDelete); + pPopup->EnableItem(pPopup->GetItemId(u"paste"), bEnablePaste); + pPopup->SetItemText(pPopup->GetItemId(u"specialchar"), + BuilderUtils::convertMnemonicMarkup(VclResId(STR_SPECIAL_CHARACTER_MENU_ENTRY))); + pPopup->EnableItem(pPopup->GetItemId(u"specialchar"), bEnableSpecialChar); + pPopup->EnableItem(pPopup->GetItemId(u"undo"), bEnableUndo); + pPopup->ShowItem(pPopup->GetItemId(u"specialchar"), !vcl::GetGetSpecialCharsFunction()); + + mbActivePopup = true; + Point aPos = rCEvt.GetMousePosPixel(); + if ( !rCEvt.IsMouseEvent() ) + { + // Sometime do show Menu centered in the selection !!! + Size aSize = GetOutputSizePixel(); + aPos = Point( aSize.Width()/2, aSize.Height()/2 ); + } + sal_uInt16 n = pPopup->Execute( this, aPos ); + OUString sCommand = pPopup->GetItemIdent(n); + if (sCommand == "undo") + { + mpExtTextView->Undo(); + mpExtTextEngine->SetModified( true ); + mpExtTextEngine->Broadcast( TextHint( SfxHintId::TextModified ) ); + } + else if (sCommand == "cut") + { + mpExtTextView->Cut(); + mpExtTextEngine->SetModified( true ); + mpExtTextEngine->Broadcast( TextHint( SfxHintId::TextModified ) ); + } + else if (sCommand == "copy") + { + mpExtTextView->Copy(); + } + else if (sCommand == "paste") + { + mpExtTextView->Paste(); + mpExtTextEngine->SetModified( true ); + mpExtTextEngine->Broadcast( TextHint( SfxHintId::TextModified ) ); + } + else if (sCommand == "delete") + { + mpExtTextView->DeleteSelected(); + mpExtTextEngine->SetModified( true ); + mpExtTextEngine->Broadcast( TextHint( SfxHintId::TextModified ) ); + } + else if (sCommand == "selectall") + { + mpExtTextView->SetSelection( TextSelection( TextPaM( 0, 0 ), TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ) ) ); + } + else if (sCommand == "specialchar") + { + OUString aChars = vcl::GetGetSpecialCharsFunction()(GetFrameWeld(), GetFont()); + if (!aChars.isEmpty()) + { + mpExtTextView->InsertText( aChars ); + mpExtTextEngine->SetModified( true ); + mpExtTextEngine->Broadcast( TextHint( SfxHintId::TextModified ) ); + } + } + pPopup.clear(); + mbActivePopup = false; + } + else + { + mpExtTextView->Command( rCEvt ); + } + Window::Command( rCEvt ); +} + +void TextWindow::GetFocus() +{ + Window::GetFocus(); + if ( mbActivePopup ) + return; + + bool bGotoCursor = !mpExtTextView->IsReadOnly(); + if ( mbFocusSelectionHide && IsReallyVisible() && mbSelectOnTab && !mbInMBDown ) + { + // select everything, but do not scroll + bool bAutoScroll = mpExtTextView->IsAutoScroll(); + mpExtTextView->SetAutoScroll( false ); + mpExtTextView->SetSelection( TextSelection( TextPaM( 0, 0 ), TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ) ) ); + mpExtTextView->SetAutoScroll( bAutoScroll ); + bGotoCursor = false; + } + mpExtTextView->SetPaintSelection( true ); + mpExtTextView->ShowCursor( bGotoCursor ); +} + +void TextWindow::LoseFocus() +{ + Window::LoseFocus(); + + if ( mbFocusSelectionHide && !mbActivePopup && mpExtTextView ) + mpExtTextView->SetPaintSelection( false ); +} + +VclMultiLineEdit::VclMultiLineEdit( vcl::Window* pParent, WinBits nWinStyle ) + : Edit( pParent, nWinStyle ) +{ + SetType( WindowType::MULTILINEEDIT ); + pImpVclMEdit.reset(new ImpVclMEdit( this, nWinStyle )); + ImplInitSettings( true ); + + SetCompoundControl( true ); + SetStyle( ImplInitStyle( nWinStyle ) ); +} + +VclMultiLineEdit::~VclMultiLineEdit() +{ + disposeOnce(); +} + +void VclMultiLineEdit::dispose() +{ + pImpVclMEdit.reset(); + Edit::dispose(); +} + +WinBits VclMultiLineEdit::ImplInitStyle( WinBits nStyle ) +{ + if ( !(nStyle & WB_NOTABSTOP) ) + nStyle |= WB_TABSTOP; + + if ( !(nStyle & WB_NOGROUP) ) + nStyle |= WB_GROUP; + + if ( !(nStyle & WB_IGNORETAB )) + nStyle |= WB_NODIALOGCONTROL; + + return nStyle; +} + +void VclMultiLineEdit::ApplySettings(vcl::RenderContext& rRenderContext) +{ + const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); + + // The Font has to be adjusted, as the TextEngine does not take care of + // TextColor/Background + + Color aTextColor = rStyleSettings.GetFieldTextColor(); + if (IsControlForeground()) + aTextColor = GetControlForeground(); + + if (!IsEnabled()) + aTextColor = rStyleSettings.GetDisableColor(); + + vcl::Font aFont = rStyleSettings.GetFieldFont(); + aFont.SetTransparent(IsPaintTransparent()); + ApplyControlFont(rRenderContext, aFont); + + vcl::Font theFont = rRenderContext.GetFont(); + theFont.SetColor(aTextColor); + if (IsPaintTransparent()) + theFont.SetFillColor(COL_TRANSPARENT); + else + theFont.SetFillColor(IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor()); + + pImpVclMEdit->GetTextWindow()->SetFont(theFont); + // FIXME: next call causes infinite invalidation loop, rethink how to properly fix this situation + // pImpVclMEdit->GetTextWindow()->GetTextEngine()->SetFont(theFont); + pImpVclMEdit->GetTextWindow()->SetTextColor(aTextColor); + + if (IsPaintTransparent()) + { + pImpVclMEdit->GetTextWindow()->SetPaintTransparent(true); + pImpVclMEdit->GetTextWindow()->SetBackground(); + pImpVclMEdit->GetTextWindow()->SetControlBackground(); + rRenderContext.SetBackground(); + SetControlBackground(); + } + else + { + if (IsControlBackground()) + pImpVclMEdit->GetTextWindow()->SetBackground(GetControlBackground()); + else + pImpVclMEdit->GetTextWindow()->SetBackground(rStyleSettings.GetFieldColor()); + // also adjust for VclMultiLineEdit as the TextComponent might hide Scrollbars + rRenderContext.SetBackground(pImpVclMEdit->GetTextWindow()->GetBackground()); + } +} + +void VclMultiLineEdit::ImplInitSettings(bool bBackground) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + // The Font has to be adjusted, as the TextEngine does not take care of + // TextColor/Background + + Color aTextColor = rStyleSettings.GetFieldTextColor(); + if (IsControlForeground()) + aTextColor = GetControlForeground(); + if (!IsEnabled()) + aTextColor = rStyleSettings.GetDisableColor(); + + vcl::Font aFont = rStyleSettings.GetFieldFont(); + aFont.SetTransparent(IsPaintTransparent()); + ApplyControlFont(*GetOutDev(), aFont); + + vcl::Font TheFont = GetFont(); + TheFont.SetColor(aTextColor); + if (IsPaintTransparent()) + TheFont.SetFillColor(COL_TRANSPARENT); + else + TheFont.SetFillColor(IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor()); + pImpVclMEdit->GetTextWindow()->SetFont(TheFont); + pImpVclMEdit->GetTextWindow()->GetTextEngine()->SetFont(TheFont); + pImpVclMEdit->GetTextWindow()->SetTextColor(aTextColor); + + if (!bBackground) + return; + + if (IsPaintTransparent()) + { + pImpVclMEdit->GetTextWindow()->SetPaintTransparent(true); + pImpVclMEdit->GetTextWindow()->SetBackground(); + pImpVclMEdit->GetTextWindow()->SetControlBackground(); + SetBackground(); + SetControlBackground(); + } + else + { + if (IsControlBackground()) + pImpVclMEdit->GetTextWindow()->SetBackground(GetControlBackground()); + else + pImpVclMEdit->GetTextWindow()->SetBackground(rStyleSettings.GetFieldColor()); + // also adjust for VclMultiLineEdit as the TextComponent might hide Scrollbars + SetBackground(pImpVclMEdit->GetTextWindow()->GetBackground()); + } +} + +void VclMultiLineEdit::Modify() +{ + aModifyHdlLink.Call( *this ); + + CallEventListeners( VclEventId::EditModify ); +} + +void VclMultiLineEdit::SelectionChanged() +{ + CallEventListeners(VclEventId::EditSelectionChanged); +} + +void VclMultiLineEdit::CaretChanged() +{ + CallEventListeners(VclEventId::EditCaretChanged); +} + +void VclMultiLineEdit::SetModifyFlag() +{ + pImpVclMEdit->SetModified( true ); +} + +void VclMultiLineEdit::SetReadOnly( bool bReadOnly ) +{ + pImpVclMEdit->SetReadOnly( bReadOnly ); + Edit::SetReadOnly( bReadOnly ); + + // #94921# ReadOnly can be overwritten in InitFromStyle() when WB not set. + WinBits nStyle = GetStyle(); + if ( bReadOnly ) + nStyle |= WB_READONLY; + else + nStyle &= ~WB_READONLY; + SetStyle( nStyle ); +} + +bool VclMultiLineEdit::IsReadOnly() const +{ + if (!pImpVclMEdit) // might be called from within the dtor, when pImpVclMEdit == NULL is a valid state + return true; + + return pImpVclMEdit->IsReadOnly(); +} + +void VclMultiLineEdit::SetMaxTextLen(sal_Int32 nMaxLen) +{ + pImpVclMEdit->SetMaxTextLen(nMaxLen); +} + +void VclMultiLineEdit::SetMaxTextWidth(tools::Long nMaxWidth) +{ + pImpVclMEdit->SetMaxTextWidth(nMaxWidth ); +} + +sal_Int32 VclMultiLineEdit::GetMaxTextLen() const +{ + return pImpVclMEdit->GetMaxTextLen(); +} + +void VclMultiLineEdit::ReplaceSelected( const OUString& rStr ) +{ + pImpVclMEdit->InsertText( rStr ); +} + +void VclMultiLineEdit::DeleteSelected() +{ + pImpVclMEdit->InsertText( OUString() ); +} + +OUString VclMultiLineEdit::GetSelected() const +{ + return pImpVclMEdit->GetSelected(); +} + +OUString VclMultiLineEdit::GetSelected( LineEnd aSeparator ) const +{ + return pImpVclMEdit->GetSelected( aSeparator ); +} + +void VclMultiLineEdit::Cut() +{ + pImpVclMEdit->Cut(); +} + +void VclMultiLineEdit::Copy() +{ + pImpVclMEdit->Copy(); +} + +void VclMultiLineEdit::Paste() +{ + pImpVclMEdit->Paste(); +} + +void VclMultiLineEdit::SetText( const OUString& rStr ) +{ + pImpVclMEdit->SetText( rStr ); +} + +OUString VclMultiLineEdit::GetText() const +{ + return pImpVclMEdit ? pImpVclMEdit->GetText() : OUString(); +} + +OUString VclMultiLineEdit::GetText( LineEnd aSeparator ) const +{ + return pImpVclMEdit ? pImpVclMEdit->GetText( aSeparator ) : OUString(); +} + +OUString VclMultiLineEdit::GetTextLines( LineEnd aSeparator ) const +{ + return pImpVclMEdit ? pImpVclMEdit->GetTextLines( aSeparator ) : OUString(); +} + +void VclMultiLineEdit::Resize() +{ + pImpVclMEdit->Resize(); +} + +void VclMultiLineEdit::GetFocus() +{ + if ( !pImpVclMEdit ) // might be called from within the dtor, when pImpVclMEdit == NULL is a valid state + return; + + pImpVclMEdit->GetFocus(); +} + +void VclMultiLineEdit::SetSelection( const Selection& rSelection ) +{ + pImpVclMEdit->SetSelection( rSelection ); +} + +const Selection& VclMultiLineEdit::GetSelection() const +{ + return pImpVclMEdit->GetSelection(); +} + +Size VclMultiLineEdit::CalcMinimumSize() const +{ + Size aSz = pImpVclMEdit->CalcMinimumSize(); + + sal_Int32 nLeft, nTop, nRight, nBottom; + static_cast<vcl::Window*>(const_cast<VclMultiLineEdit *>(this))->GetBorder( nLeft, nTop, nRight, nBottom ); + aSz.AdjustWidth(nLeft+nRight ); + aSz.AdjustHeight(nTop+nBottom ); + + return aSz; +} + +Size VclMultiLineEdit::CalcAdjustedSize( const Size& rPrefSize ) const +{ + Size aSz = rPrefSize; + sal_Int32 nLeft, nTop, nRight, nBottom; + static_cast<vcl::Window*>(const_cast<VclMultiLineEdit *>(this))->GetBorder( nLeft, nTop, nRight, nBottom ); + + // center vertically for whole lines + + tools::Long nHeight = aSz.Height() - nTop - nBottom; + tools::Long nLineHeight = pImpVclMEdit->CalcBlockSize( 1, 1 ).Height(); + tools::Long nLines = nHeight / nLineHeight; + if ( nLines < 1 ) + nLines = 1; + + aSz.setHeight( nLines * nLineHeight ); + aSz.AdjustHeight(nTop+nBottom ); + + return aSz; +} + +Size VclMultiLineEdit::CalcBlockSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const +{ + Size aSz = pImpVclMEdit->CalcBlockSize( nColumns, nLines ); + + sal_Int32 nLeft, nTop, nRight, nBottom; + static_cast<vcl::Window*>(const_cast<VclMultiLineEdit *>(this))->GetBorder( nLeft, nTop, nRight, nBottom ); + aSz.AdjustWidth(nLeft+nRight ); + aSz.AdjustHeight(nTop+nBottom ); + return aSz; +} + +void VclMultiLineEdit::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const +{ + pImpVclMEdit->GetMaxVisColumnsAndLines( rnCols, rnLines ); +} + +void VclMultiLineEdit::StateChanged( StateChangedType nType ) +{ + if( nType == StateChangedType::Enable ) + { + pImpVclMEdit->Enable( IsEnabled() ); + ImplInitSettings( false ); + } + else if( nType == StateChangedType::ReadOnly ) + { + pImpVclMEdit->SetReadOnly( IsReadOnly() ); + } + else if ( nType == StateChangedType::Zoom ) + { + pImpVclMEdit->GetTextWindow()->SetZoom( GetZoom() ); + ImplInitSettings( false ); + Resize(); + } + else if ( nType == StateChangedType::ControlFont ) + { + ImplInitSettings( false ); + Resize(); + Invalidate(); + } + else if ( nType == StateChangedType::ControlForeground ) + { + ImplInitSettings( false ); + Invalidate(); + } + else if ( nType == StateChangedType::ControlBackground ) + { + ImplInitSettings( true ); + Invalidate(); + } + else if ( nType == StateChangedType::Style ) + { + pImpVclMEdit->InitFromStyle( GetStyle() ); + SetStyle( ImplInitStyle( GetStyle() ) ); + } + else if ( nType == StateChangedType::InitShow ) + { + if( IsPaintTransparent() ) + { + pImpVclMEdit->GetTextWindow()->SetPaintTransparent( true ); + pImpVclMEdit->GetTextWindow()->SetBackground(); + pImpVclMEdit->GetTextWindow()->SetControlBackground(); + SetBackground(); + SetControlBackground(); + } + } + + Control::StateChanged( nType ); +} + +void VclMultiLineEdit::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + ImplInitSettings( true ); + Resize(); + Invalidate(); + } + else + Control::DataChanged( rDCEvt ); +} + +void VclMultiLineEdit::Draw( OutputDevice* pDev, const Point& rPos, SystemTextColorFlags nFlags ) +{ + ImplInitSettings(true); + + Point aPos = pDev->LogicToPixel( rPos ); + Size aSize = GetSizePixel(); + + vcl::Font aFont = pImpVclMEdit->GetTextWindow()->GetDrawPixelFont(pDev); + aFont.SetTransparent( true ); + + pDev->Push(); + pDev->SetMapMode(); + pDev->SetFont( aFont ); + pDev->SetTextFillColor(); + + // Border/Background + pDev->SetLineColor(); + pDev->SetFillColor(); + bool bBorder = (GetStyle() & WB_BORDER); + bool bBackground = IsControlBackground(); + if ( bBorder || bBackground ) + { + tools::Rectangle aRect( aPos, aSize ); + if ( bBorder ) + { + DecorationView aDecoView( pDev ); + aRect = aDecoView.DrawFrame( aRect, DrawFrameStyle::DoubleIn ); + } + if ( bBackground ) + { + pDev->SetFillColor( GetControlBackground() ); + pDev->DrawRect( aRect ); + } + } + + pDev->SetSystemTextColor(nFlags, IsEnabled()); + + OUString aText = GetText(); + Size aTextSz( pDev->GetTextWidth( aText ), pDev->GetTextHeight() ); + sal_uLong nLines = static_cast<sal_uLong>(aSize.Height() / aTextSz.Height()); + if ( !nLines ) + nLines = 1; + aTextSz.setHeight( nLines*aTextSz.Height() ); + tools::Long nOnePixel = GetDrawPixel( pDev, 1 ); + tools::Long nOffX = 3*nOnePixel; + tools::Long nOffY = 2*nOnePixel; + + // Clipping? + if ( ( nOffY < 0 ) || ( (nOffY+aTextSz.Height()) > aSize.Height() ) || ( (nOffX+aTextSz.Width()) > aSize.Width() ) ) + { + tools::Rectangle aClip( aPos, aSize ); + if ( aTextSz.Height() > aSize.Height() ) + aClip.AdjustBottom(aTextSz.Height() - aSize.Height() + 1 ); // so that HP-printer does not 'optimize-away' + pDev->IntersectClipRegion( aClip ); + } + + ExtTextEngine aTE; + aTE.SetText( GetText() ); + aTE.SetMaxTextWidth( aSize.Width() ); + aTE.SetFont( aFont ); + aTE.SetTextAlign( pImpVclMEdit->GetTextWindow()->GetTextEngine()->GetTextAlign() ); + aTE.Draw( pDev, Point( aPos.X() + nOffX, aPos.Y() + nOffY ) ); + + pDev->Pop(); +} + +bool VclMultiLineEdit::EventNotify( NotifyEvent& rNEvt ) +{ + bool bDone = false; + if( rNEvt.GetType() == NotifyEventType::COMMAND ) + { + bDone = pImpVclMEdit->HandleCommand( *rNEvt.GetCommandEvent() ); + } + return bDone || Edit::EventNotify( rNEvt ); +} + +bool VclMultiLineEdit::PreNotify( NotifyEvent& rNEvt ) +{ + bool bDone = false; + + if( ( rNEvt.GetType() == NotifyEventType::KEYINPUT ) && ( !GetTextView()->IsCursorEnabled() ) ) + { + const KeyEvent& rKEvent = *rNEvt.GetKeyEvent(); + if ( !rKEvent.GetKeyCode().IsShift() && ( rKEvent.GetKeyCode().GetGroup() == KEYGROUP_CURSOR ) ) + { + bDone = true; + TextSelection aSel = pImpVclMEdit->GetTextWindow()->GetTextView()->GetSelection(); + if ( aSel.HasRange() ) + { + aSel.GetStart() = aSel.GetEnd(); + pImpVclMEdit->GetTextWindow()->GetTextView()->SetSelection( aSel ); + } + else + { + switch ( rKEvent.GetKeyCode().GetCode() ) + { + case KEY_UP: + { + if ( pImpVclMEdit->GetVScrollBar().IsVisible() ) + pImpVclMEdit->GetVScrollBar().DoScrollAction( ScrollType::LineUp ); + } + break; + case KEY_DOWN: + { + if ( pImpVclMEdit->GetVScrollBar().IsVisible() ) + pImpVclMEdit->GetVScrollBar().DoScrollAction( ScrollType::LineDown ); + } + break; + case KEY_PAGEUP : + { + if ( pImpVclMEdit->GetVScrollBar().IsVisible() ) + pImpVclMEdit->GetVScrollBar().DoScrollAction( ScrollType::PageUp ); + } + break; + case KEY_PAGEDOWN: + { + if ( pImpVclMEdit->GetVScrollBar().IsVisible() ) + pImpVclMEdit->GetVScrollBar().DoScrollAction( ScrollType::PageDown ); + } + break; + case KEY_LEFT: + { + if ( pImpVclMEdit->GetHScrollBar().IsVisible() ) + pImpVclMEdit->GetHScrollBar().DoScrollAction( ScrollType::LineUp ); + } + break; + case KEY_RIGHT: + { + if ( pImpVclMEdit->GetHScrollBar().IsVisible() ) + pImpVclMEdit->GetHScrollBar().DoScrollAction( ScrollType::LineDown ); + } + break; + case KEY_HOME: + { + if ( rKEvent.GetKeyCode().IsMod1() ) + pImpVclMEdit->GetTextWindow()->GetTextView()-> + SetSelection( TextSelection( TextPaM( 0, 0 ) ) ); + } + break; + case KEY_END: + { + if ( rKEvent.GetKeyCode().IsMod1() ) + pImpVclMEdit->GetTextWindow()->GetTextView()-> + SetSelection( TextSelection( TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ) ) ); + } + break; + default: + { + bDone = false; + } + } + } + } + } + + return bDone || Edit::PreNotify( rNEvt ); +} + +// Internals for derived classes, e.g. TextComponent + +ExtTextEngine* VclMultiLineEdit::GetTextEngine() const +{ + return pImpVclMEdit->GetTextWindow()->GetTextEngine(); +} + +TextView* VclMultiLineEdit::GetTextView() const +{ + return pImpVclMEdit->GetTextWindow()->GetTextView(); +} + +ScrollBar& VclMultiLineEdit::GetVScrollBar() const +{ + return pImpVclMEdit->GetVScrollBar(); +} + +void VclMultiLineEdit::EnableFocusSelectionHide( bool bHide ) +{ + pImpVclMEdit->GetTextWindow()->SetAutoFocusHide( bHide ); +} + +void VclMultiLineEdit::DisableSelectionOnFocus() +{ + pImpVclMEdit->GetTextWindow()->DisableSelectionOnFocus(); +} + +void VclMultiLineEdit::EnableCursor( bool bEnable ) +{ + GetTextView()->EnableCursor( bEnable ); +} + +bool VclMultiLineEdit::CanUp() const +{ + TextView* pTextView = GetTextView(); + const TextSelection& rTextSelection = pTextView->GetSelection(); + TextPaM aPaM(rTextSelection.GetEnd()); + return aPaM != pTextView->CursorUp(aPaM); +} + +bool VclMultiLineEdit::CanDown() const +{ + TextView* pTextView = GetTextView(); + const TextSelection& rTextSelection = pTextView->GetSelection(); + TextPaM aPaM(rTextSelection.GetEnd()); + return aPaM != pTextView->CursorDown(aPaM); +} + +TextWindow* VclMultiLineEdit::GetTextWindow() +{ + return pImpVclMEdit->GetTextWindow(); +} + +FactoryFunction VclMultiLineEdit::GetUITestFactory() const +{ + return MultiLineEditUIObject::create; +} + +bool VclMultiLineEdit::set_property(const OUString &rKey, const OUString &rValue) +{ + if (rKey == "cursor-visible") + EnableCursor(toBool(rValue)); + else if (rKey == "accepts-tab") + pImpVclMEdit->GetTextWindow()->SetIgnoreTab(!toBool(rValue)); + else + return Edit::set_property(rKey, rValue); + return true; +} + +void VclMultiLineEdit::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) +{ + Edit::DumpAsPropertyTree(rJsonWriter); + + rJsonWriter.put("cursor", pImpVclMEdit->GetTextWindow()->GetTextView()->IsCursorEnabled()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |