Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  vclmedit.cxx   Sprache: C

 
/* -*- 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 )
{
    switch (rHint.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;

        defaultbreak;
    }
}

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.reset();
    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.reset();
        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;
    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;
    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;
    GetBorder(nLeft, nTop, nRight, nBottom);
    aSz.AdjustWidth(nLeft+nRight );
    aSz.AdjustHeight(nTop+nBottom );
    return aSz;
}

void VclMultiLineEdit::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16&&nbsp;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: */

Messung V0.5
C=93 H=97 G=94

¤ Dauer der Verarbeitung: 0.57 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge