1505 lines
46 KiB
C++
1505 lines
46 KiB
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;
|
|
|
|
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;
|
|
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& 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: */
|