/* -*- 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 <scitems.hxx>
#include <editeng/eeitem.hxx>
#include <memory>
#include <AccessibleText.hxx>
#include <AccessibleCell.hxx>
#include <attrib.hxx>
#include <tabvwsh.hxx>
#include <editutil.hxx>
#include <document.hxx>
#include <scmod.hxx>
#include <prevwsh.hxx>
#include <docsh.hxx>
#include <prevloc.hxx>
#include <patattr.hxx>
#include <inputwin.hxx>
#include <editeng/unofored.hxx>
#include <editeng/editview.hxx>
#include <editeng/unoedhlp.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/adjustitem.hxx>
#include <editeng/justifyitem.hxx>
#include <svx/svdmodel.hxx>
#include <svx/algitem.hxx>
#include <utility>
#include <vcl/svapp.hxx>
class ScViewForwarder : public SvxViewForwarder
{
ScTabViewShell* mpViewShell;
ScSplitPos meSplitPos;
public :
ScViewForwarder(ScTabViewShell* pViewShell, ScSplitPos eSplitPos);
virtual bool IsValid() const override;
virtual Point LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const override;
virtual Point PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const override;
void SetInvalid();
};
ScViewForwarder::ScViewForwarder(ScTabViewShell* pViewShell, ScSplitPos eSplitPos)
:
mpViewShell(pViewShell),
meSplitPos(eSplitPos)
{
}
bool ScViewForwarder::IsValid() const
{
return mpViewShell != nullptr;
}
Point ScViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
{
if (mpViewShell)
{
vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
if (pWindow)
return pWindow->LogicToPixel( rPoint, rMapMode );
}
else
{
OSL_FAIL("this ViewForwarder is not valid" );
}
return Point();
}
Point ScViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
{
if (mpViewShell)
{
vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
if (pWindow)
return pWindow->PixelToLogic( rPoint, rMapMode );
}
else
{
OSL_FAIL("this ViewForwarder is not valid" );
}
return Point();
}
void ScViewForwarder::SetInvalid()
{
mpViewShell = nullptr;
}
class ScEditObjectViewForwarder : public SvxViewForwarder
{
VclPtr<OutputDevice> mpWindow;
// #i49561# EditView needed for access to its visible area.
const EditView* mpEditView;
public :
ScEditObjectViewForwarder( OutputDevice* pWindow,
const EditView* _pEditView);
virtual bool IsValid() const override;
virtual Point LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const override;
virtual Point PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const override;
void SetInvalid();
};
ScEditObjectViewForwarder::ScEditObjectViewForwarder( OutputDevice* pWindow,
const EditView* _pEditView )
: mpWindow(pWindow)
, mpEditView( _pEditView )
{
}
bool ScEditObjectViewForwarder::IsValid() const
{
return (mpWindow != nullptr);
}
Point ScEditObjectViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
{
if (mpWindow)
{
// #i49561# - consider offset of the visible area
// of the EditView before converting point to pixel.
Point aPoint( rPoint );
if ( mpEditView )
{
tools::Rectangle aEditViewVisArea( mpEditView->GetVisArea() );
aPoint += aEditViewVisArea.TopLeft();
}
return mpWindow->LogicToPixel( aPoint, rMapMode );
}
else
{
OSL_FAIL("this ViewForwarder is not valid" );
}
return Point();
}
Point ScEditObjectViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
{
if (mpWindow)
{
// #i49561# - consider offset of the visible area
// of the EditView after converting point to logic.
Point aPoint( mpWindow->PixelToLogic( rPoint, rMapMode ) );
if ( mpEditView )
{
tools::Rectangle aEditViewVisArea( mpEditView->GetVisArea() );
aPoint -= aEditViewVisArea.TopLeft();
}
return aPoint;
}
else
{
OSL_FAIL("this ViewForwarder is not valid" );
}
return Point();
}
void ScEditObjectViewForwarder::SetInvalid()
{
mpWindow = nullptr;
}
class ScPreviewViewForwarder : public SvxViewForwarder
{
protected :
ScPreviewShell* mpViewShell;
public :
explicit ScPreviewViewForwarder(ScPreviewShell* pViewShell);
virtual bool IsValid() const override;
virtual Point LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const override;
virtual Point PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const override;
void SetInvalid();
};
ScPreviewViewForwarder::ScPreviewViewForwarder(ScPreviewShell* pViewShell)
: mpViewShell(pViewShell)
{
}
bool ScPreviewViewForwarder::IsValid() const
{
return mpViewShell != nullptr;
}
Point ScPreviewViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
{
if (mpViewShell)
{
vcl::Window* pWindow = mpViewShell->GetWindow();
if (pWindow)
{
MapMode aMapMode(pWindow->GetMapMode().GetMapUnit());
Point aPoint2( OutputDevice::LogicToLogic( rPoint, rMapMode, aMapMode) );
return pWindow->LogicToPixel(aPoint2);
}
}
else
{
OSL_FAIL("this ViewForwarder is not valid" );
}
return Point();
}
Point ScPreviewViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
{
if (mpViewShell)
{
vcl::Window* pWindow = mpViewShell->GetWindow();
if (pWindow)
{
MapMode aMapMode(pWindow->GetMapMode());
aMapMode.SetOrigin(Point());
Point aPoint1( pWindow->PixelToLogic( rPoint ) );
Point aPoint2( OutputDevice::LogicToLogic( aPoint1,
MapMode(aMapMode.GetMapUnit()),
rMapMode ) );
return aPoint2;
}
}
else
{
OSL_FAIL("this ViewForwarder is not valid" );
}
return Point();
}
void ScPreviewViewForwarder::SetInvalid()
{
mpViewShell = nullptr;
}
namespace {
class ScPreviewHeaderFooterViewForwarder : public ScPreviewViewForwarder
{
public :
ScPreviewHeaderFooterViewForwarder(ScPreviewShell* pViewShell);
};
}
ScPreviewHeaderFooterViewForwarder::ScPreviewHeaderFooterViewForwarder(ScPreviewShell* pViewShell)
:
ScPreviewViewForwarder(pViewShell)
{
}
namespace {
class ScPreviewCellViewForwarder : public ScPreviewViewForwarder
{
public :
ScPreviewCellViewForwarder(ScPreviewShell* pViewShell);
};
}
ScPreviewCellViewForwarder::ScPreviewCellViewForwarder(ScPreviewShell* pViewShell)
:
ScPreviewViewForwarder(pViewShell)
{
}
namespace {
class ScPreviewHeaderCellViewForwarder : public ScPreviewViewForwarder
{
public :
ScPreviewHeaderCellViewForwarder(ScPreviewShell* pViewShell);
};
}
ScPreviewHeaderCellViewForwarder::ScPreviewHeaderCellViewForwarder(ScPreviewShell* pViewShell)
:
ScPreviewViewForwarder(pViewShell)
{
}
namespace {
class ScPreviewNoteViewForwarder : public ScPreviewViewForwarder
{
public :
ScPreviewNoteViewForwarder(ScPreviewShell* pViewShell);
};
}
ScPreviewNoteViewForwarder::ScPreviewNoteViewForwarder(ScPreviewShell* pViewShell)
:
ScPreviewViewForwarder(pViewShell)
{
}
class ScEditViewForwarder : public SvxEditViewForwarder
{
EditView* mpEditView;
VclPtr<OutputDevice> mpWindow;
public :
ScEditViewForwarder(EditView* pEditView, OutputDevice* pWin);
virtual bool IsValid() const override;
virtual Point LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const override;
virtual Point PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const override;
virtual bool GetSelection( ESelection& rSelection ) const override;
virtual bool SetSelection( const ESelection& rSelection ) override;
virtual bool Copy() override;
virtual bool Cut() override;
virtual bool Paste() override;
void SetInvalid();
};
ScEditViewForwarder::ScEditViewForwarder(EditView* pEditView, OutputDevice* pWin)
: mpEditView(pEditView)
, mpWindow(pWin)
{
}
bool ScEditViewForwarder::IsValid() const
{
return mpWindow && mpEditView;
}
Point ScEditViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
{
if (mpWindow)
return mpWindow->LogicToPixel( rPoint, rMapMode );
else
{
OSL_FAIL("this ViewForwarder is not valid" );
}
return Point();
}
Point ScEditViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
{
if (mpWindow)
return mpWindow->PixelToLogic( rPoint, rMapMode );
else
{
OSL_FAIL("this ViewForwarder is not valid" );
}
return Point();
}
bool ScEditViewForwarder::GetSelection( ESelection& rSelection ) const
{
bool bResult(false );
if (IsValid())
{
rSelection = mpEditView->GetSelection();
bResult = true ;
}
else
{
OSL_FAIL("this ViewForwarder is not valid" );
}
return bResult;
}
bool ScEditViewForwarder::SetSelection( const ESelection& rSelection )
{
bool bResult(false );
if (IsValid())
{
mpEditView->SetSelection(rSelection);
bResult = true ;
}
else
{
OSL_FAIL("this ViewForwarder is not valid" );
}
return bResult;
}
bool ScEditViewForwarder::Copy()
{
bool bResult(false );
if (IsValid())
{
mpEditView->Copy();
bResult = true ;
}
else
{
OSL_FAIL("this ViewForwarder is not valid" );
}
return bResult;
}
bool ScEditViewForwarder::Cut()
{
bool bResult(false );
if (IsValid())
{
mpEditView->Cut();
bResult = true ;
}
else
{
OSL_FAIL("this ViewForwarder is not valid" );
}
return bResult;
}
bool ScEditViewForwarder::Paste()
{
bool bResult(false );
if (IsValid())
{
mpEditView->Paste();
bResult = true ;
}
else
{
OSL_FAIL("this ViewForwarder is not valid" );
}
return bResult;
}
void ScEditViewForwarder::SetInvalid()
{
mpWindow = nullptr;
mpEditView = nullptr;
}
// ScAccessibleCellTextData: shared data between sub objects of an accessible cell text object
ScAccessibleCellTextData::ScAccessibleCellTextData(ScTabViewShell* pViewShell,
const ScAddress& rP, ScSplitPos eSplitPos, ScAccessibleCell* pAccCell)
: ScAccessibleCellBaseTextData(GetDocShell(pViewShell), rP),
mpViewShell(pViewShell),
meSplitPos(eSplitPos),
mpAccessibleCell( pAccCell )
{
}
ScAccessibleCellTextData::~ScAccessibleCellTextData()
{
if (pEditEngine)
pEditEngine->SetNotifyHdl(Link<EENotify&,void >());
mpViewForwarder.reset();
}
void ScAccessibleCellTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
if ( rHint.GetId() == SfxHintId::Dying )
{
mpViewShell = nullptr; // invalid now
if (mpViewForwarder)
mpViewForwarder->SetInvalid();
}
ScAccessibleCellBaseTextData::Notify(rBC, rHint);
}
ScAccessibleTextData* ScAccessibleCellTextData::Clone() const
{
return new ScAccessibleCellTextData( mpViewShell, aCellPos, meSplitPos, mpAccessibleCell );
}
SvxTextForwarder* ScAccessibleCellTextData::GetTextForwarder()
{
ScCellTextData::GetTextForwarder(); // creates Forwarder and EditEngine
if ( pDocShell && pEditEngine && mpViewShell )
{
ScDocument& rDoc = pDocShell->GetDocument();
tools::Long nSizeX, nSizeY;
mpViewShell->GetViewData().GetMergeSizePixel(
aCellPos.Col(), aCellPos.Row(), nSizeX, nSizeY);
Size aSize(nSizeX, nSizeY);
// #i92143# text getRangeExtents reports incorrect 'x' values for spreadsheet cells
tools::Long nIndent = 0 ;
const SvxHorJustifyItem* pHorJustifyItem = rDoc.GetAttr( aCellPos, ATTR_HOR_JUSTIFY );
SvxCellHorJustify eHorJust = pHorJustifyItem ? pHorJustifyItem->GetValue() : SvxCellHorJustify::Standard;
if ( eHorJust == SvxCellHorJustify::Left )
{
const ScIndentItem* pIndentItem = rDoc.GetAttr( aCellPos, ATTR_INDENT );
if ( pIndentItem )
{
nIndent = static_cast < tools::Long >( pIndentItem->GetValue() );
}
}
const SvxMarginItem* pMarginItem = rDoc.GetAttr( aCellPos, ATTR_MARGIN );
ScViewData& rViewData = mpViewShell->GetViewData();
double nPPTX = rViewData.GetPPTX();
double nPPTY = rViewData.GetPPTY();
tools::Long nLeftM = ( pMarginItem ? static_cast < tools::Long >( ( pMarginItem->GetLeftMargin() + nIndent ) * nPPTX ) : 0 );
tools::Long nTopM = ( pMarginItem ? static_cast < tools::Long >( pMarginItem->GetTopMargin() * nPPTY ) : 0 );
tools::Long nRightM = ( pMarginItem ? static_cast < tools::Long >( pMarginItem->GetRightMargin() * nPPTX ) : 0 );
tools::Long nBottomM = ( pMarginItem ? static_cast < tools::Long >( pMarginItem->GetBottomMargin() * nPPTY ) : 0 );
tools::Long nWidth = aSize.getWidth() - nLeftM - nRightM;
aSize.setWidth( nWidth );
aSize.setHeight( aSize.getHeight() - nTopM - nBottomM );
vcl::Window* pWin = mpViewShell->GetWindowByPos( meSplitPos );
if ( pWin )
{
aSize = pWin->PixelToLogic( aSize, pEditEngine->GetRefMapMode() );
}
/* #i19430# Gnopernicus reads text partly if it sticks out of the cell
boundaries . This leads to wrong results in cases where the cell text
is rotated , because rotation is not taken into account when calcu -
lating the visible part of the text . In these cases we will expand
the cell size passed as paper size to the edit engine . The function
accessibility : : AccessibleStaticTextBase : : GetParagraphBoundingBox ( )
( see svx / source / accessibility / AccessibleStaticTextBase . cxx ) will
return the size of the complete text then , which is used to expand
the cell bounding box in ScAccessibleCell : : GetBoundingBox ( )
(see sc/source/ui/Accessibility/AccessibleCell.cxx). */
const ScRotateValueItem* pItem = rDoc.GetAttr( aCellPos, ATTR_ROTATE_VALUE );
if ( pItem && (pItem->GetValue() != 0 _deg100) )
{
pEditEngine->SetPaperSize( Size( LONG_MAX, aSize.getHeight() ) );
tools::Long nTxtWidth = static_cast < tools::Long >( pEditEngine->CalcTextWidth() );
aSize.setWidth( std::max( aSize.getWidth(), nTxtWidth + 2 ) );
}
else
{
// #i92143# text getRangeExtents reports incorrect 'x' values for spreadsheet cells
const ScLineBreakCell* pLineBreakItem = rDoc.GetAttr( aCellPos, ATTR_LINEBREAK );
bool bLineBreak = ( pLineBreakItem && pLineBreakItem->GetValue() );
if ( !bLineBreak )
{
tools::Long nTxtWidth = static_cast < tools::Long >( pEditEngine->CalcTextWidth() );
aSize.setWidth( ::std::max( aSize.getWidth(), nTxtWidth ) );
}
}
pEditEngine->SetPaperSize( aSize );
// #i92143# text getRangeExtents reports incorrect 'x' values for spreadsheet cells
if ( eHorJust == SvxCellHorJustify::Standard && rDoc.HasValueData( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab() ) )
{
pEditEngine->SetDefaultItem( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
}
Size aTextSize;
if ( pWin )
{
aTextSize = pWin->LogicToPixel( Size( pEditEngine->CalcTextWidth(), pEditEngine->GetTextHeight() ), pEditEngine->GetRefMapMode() );
}
tools::Long nTextWidth = aTextSize.Width();
tools::Long nTextHeight = aTextSize.Height();
tools::Long nOffsetX = nLeftM;
tools::Long nDiffX = nTextWidth - nWidth;
if ( nDiffX > 0 )
{
switch ( eHorJust )
{
case SvxCellHorJustify::Right:
{
nOffsetX -= nDiffX;
}
break ;
case SvxCellHorJustify::Center:
{
nOffsetX -= nDiffX / 2 ;
}
break ;
default :
{
}
break ;
}
}
tools::Long nOffsetY = 0 ;
const SvxVerJustifyItem* pVerJustifyItem = rDoc.GetAttr( aCellPos, ATTR_VER_JUSTIFY );
SvxCellVerJustify eVerJust = ( pVerJustifyItem ? pVerJustifyItem->GetValue() : SvxCellVerJustify::Standard );
switch ( eVerJust )
{
case SvxCellVerJustify::Standard:
case SvxCellVerJustify::Bottom:
{
nOffsetY = nSizeY - nBottomM - nTextHeight;
}
break ;
case SvxCellVerJustify::Center:
{
nOffsetY = ( nSizeY - nTopM - nBottomM - nTextHeight ) / 2 + nTopM;
}
break ;
default :
{
nOffsetY = nTopM;
}
break ;
}
if ( mpAccessibleCell )
{
mpAccessibleCell->SetOffset( Point( nOffsetX, nOffsetY ) );
}
pEditEngine->SetNotifyHdl( LINK(this , ScAccessibleCellTextData, NotifyHdl) );
}
return pForwarder.get();
}
SvxViewForwarder* ScAccessibleCellTextData::GetViewForwarder()
{
if (!mpViewForwarder)
mpViewForwarder.reset(new ScViewForwarder(mpViewShell, meSplitPos));
return mpViewForwarder.get();
}
SvxEditViewForwarder* ScAccessibleCellTextData::GetEditViewForwarder( bool /* bCreate */ )
{
//#102219#; there should no EditViewForwarder be, because the cell is now readonly in this interface
return nullptr;
}
IMPL_LINK(ScAccessibleTextData, NotifyHdl, EENotify&, aNotify, void )
{
::std::unique_ptr< SfxHint > aHint = SvxEditSourceHelper::EENotification2Hint( &aNotify );
if (aHint)
GetBroadcaster().Broadcast(*aHint);
}
ScDocShell* ScAccessibleCellTextData::GetDocShell(ScTabViewShell* pViewShell)
{
ScDocShell* pDocSh = nullptr;
if (pViewShell)
pDocSh = &pViewShell->GetViewData().GetDocShell();
return pDocSh;
}
ScAccessibleEditObjectTextData::ScAccessibleEditObjectTextData(EditView* pEditView, OutputDevice* pWin, bool isClone)
: mpEditView(pEditView)
, mpEditEngine(pEditView ? &pEditView->getEditEngine() : nullptr)
, mpWindow(pWin)
{
// If the object is cloned, do NOT add notify hdl.
mbIsCloned = isClone;
if (mpEditEngine && !mbIsCloned)
mpEditEngine->SetNotifyHdl( LINK(this , ScAccessibleEditObjectTextData, NotifyHdl) );
}
ScAccessibleEditObjectTextData::~ScAccessibleEditObjectTextData()
{
// If the object is cloned, do NOT set notify hdl.
if (mpEditEngine && !mbIsCloned)
mpEditEngine->SetNotifyHdl(Link<EENotify&,void >());
mpViewForwarder.reset();
mpEditViewForwarder.reset();
mpForwarder.reset();
}
void ScAccessibleEditObjectTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
if ( rHint.GetId() == SfxHintId::Dying )
{
mpWindow = nullptr;
mpEditView = nullptr;
mpEditEngine = nullptr;
mpForwarder.reset();
if (mpViewForwarder)
mpViewForwarder->SetInvalid();
if (mpEditViewForwarder)
mpEditViewForwarder->SetInvalid();
}
ScAccessibleTextData::Notify(rBC, rHint);
}
ScAccessibleTextData* ScAccessibleEditObjectTextData::Clone() const
{
// Add para to indicate the object is cloned
return new ScAccessibleEditObjectTextData(mpEditView, mpWindow, true );
}
SvxTextForwarder* ScAccessibleEditObjectTextData::GetTextForwarder()
{
if ((!mpForwarder && mpEditView) || (mpEditEngine && !mpEditEngine->GetNotifyHdl().IsSet()))
{
if (!mpEditEngine)
mpEditEngine = &mpEditView->getEditEngine();
// If the object is cloned, do NOT add notify hdl.
if (mpEditEngine && !mpEditEngine->GetNotifyHdl().IsSet()&&!mbIsCloned)
mpEditEngine->SetNotifyHdl( LINK(this , ScAccessibleEditObjectTextData, NotifyHdl) );
if (!mpForwarder)
mpForwarder.reset(new SvxEditEngineForwarder(*mpEditEngine));
}
return mpForwarder.get();
}
SvxViewForwarder* ScAccessibleEditObjectTextData::GetViewForwarder()
{
if (!mpViewForwarder)
{
// i#49561 Get right-aligned cell content to be read by screenreader.
mpViewForwarder.reset(new ScEditObjectViewForwarder( mpWindow, mpEditView ));
}
return mpViewForwarder.get();
}
SvxEditViewForwarder* ScAccessibleEditObjectTextData::GetEditViewForwarder( bool bCreate )
{
if (!mpEditViewForwarder && mpEditView)
mpEditViewForwarder.reset(new ScEditViewForwarder(mpEditView, mpWindow));
if (bCreate)
{
if (!mpEditView && mpEditViewForwarder)
{
mpEditViewForwarder.reset();
}
}
return mpEditViewForwarder.get();
}
IMPL_LINK(ScAccessibleEditObjectTextData, NotifyHdl, EENotify&, rNotify, void )
{
::std::unique_ptr< SfxHint > aHint = SvxEditSourceHelper::EENotification2Hint( &rNotify );
if (aHint)
GetBroadcaster().Broadcast(*aHint);
}
ScAccessibleEditLineTextData::ScAccessibleEditLineTextData(EditView* pEditView,
OutputDevice* pWin,
ScTextWnd* pTxtWnd)
: ScAccessibleEditObjectTextData(pEditView, pWin)
, mpTxtWnd(pTxtWnd)
, mbEditEngineCreated(false )
{
if (mpTxtWnd)
mpTxtWnd->InsertAccessibleTextData( *this );
}
ScAccessibleEditLineTextData::~ScAccessibleEditLineTextData()
{
if (mpTxtWnd)
mpTxtWnd->RemoveAccessibleTextData( *this );
if (mbEditEngineCreated && mpEditEngine)
{
delete mpEditEngine;
mpEditEngine = nullptr; // don't access in ScAccessibleEditObjectTextData dtor!
}
else if (mpTxtWnd && mpTxtWnd->HasEditView())
{
// the NotifyHdl also has to be removed from the ScTextWnd's EditEngine
// (it's set in ScAccessibleEditLineTextData::GetTextForwarder, and mpEditEngine
// is reset there)
mpTxtWnd->GetEditView()->getEditEngine().SetNotifyHdl(Link<EENotify&,void >());
}
}
void ScAccessibleEditLineTextData::Dispose()
{
if (mpTxtWnd)
mpTxtWnd->RemoveAccessibleTextData( *this );
ResetEditMode();
mpWindow = nullptr;
mpTxtWnd = nullptr;
}
ScAccessibleTextData* ScAccessibleEditLineTextData::Clone() const
{
return new ScAccessibleEditLineTextData(mpEditView, mpWindow, mpTxtWnd);
}
SvxTextForwarder* ScAccessibleEditLineTextData::GetTextForwarder()
{
if (mpTxtWnd)
{
if (mpTxtWnd->HasEditView())
{
mpEditView = mpTxtWnd->GetEditView();
if (mbEditEngineCreated && mpEditEngine)
ResetEditMode();
mbEditEngineCreated = false ;
mpEditView = mpTxtWnd->GetEditView();
ScAccessibleEditObjectTextData::GetTextForwarder(); // fill the mpForwarder
mpEditEngine = nullptr;
}
else
{
mpEditView = nullptr;
if (mpEditEngine && !mbEditEngineCreated)
ResetEditMode();
if (!mpEditEngine)
{
rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
mpEditEngine = new ScFieldEditEngine(nullptr, pEnginePool.get(), nullptr, true );
mbEditEngineCreated = true ;
mpEditEngine->EnableUndo( false );
mpEditEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
mpForwarder.reset(new SvxEditEngineForwarder(*mpEditEngine));
mpEditEngine->SetText(mpTxtWnd->GetTextString());
#if 0
Size aSize(pTxtWnd->GetSizePixel());
aSize = pTxtWnd->PixelToLogic(aSize, mpEditEngine->GetRefMapMode());
mpEditEngine->SetPaperSize(aSize);
#else
OutputDevice& rDevice = mpTxtWnd->GetDrawingArea()->get_ref_device();
Size aSize(rDevice.GetOutputSizePixel());
aSize = rDevice.PixelToLogic(aSize, mpEditEngine->GetRefMapMode());
mpEditEngine->SetPaperSize(aSize);
#endif
mpEditEngine->SetNotifyHdl( LINK(this , ScAccessibleEditObjectTextData, NotifyHdl) );
}
}
}
return mpForwarder.get();
}
SvxEditViewForwarder* ScAccessibleEditLineTextData::GetEditViewForwarder( bool bCreate )
{
if (mpTxtWnd)
{
if (!mpTxtWnd->HasEditView() && bCreate)
{
if ( !mpTxtWnd->IsInputActive() )
{
mpTxtWnd->StartEditEngine();
mpTxtWnd->GrabFocus();
mpEditView = mpTxtWnd->GetEditView();
}
}
}
return ScAccessibleEditObjectTextData::GetEditViewForwarder(bCreate);
}
void ScAccessibleEditLineTextData::ResetEditMode()
{
if (mbEditEngineCreated && mpEditEngine)
delete mpEditEngine;
else if (mpTxtWnd && mpTxtWnd->HasEditView())
mpTxtWnd->GetEditView()->getEditEngine().SetNotifyHdl(Link<EENotify&,void >());
mpEditEngine = nullptr;
mpForwarder.reset();
mpEditViewForwarder.reset();
mpViewForwarder.reset();
mbEditEngineCreated = false ;
}
void ScAccessibleEditLineTextData::TextChanged()
{
if (mbEditEngineCreated && mpEditEngine)
{
if (mpTxtWnd)
mpEditEngine->SetText(mpTxtWnd->GetTextString());
}
}
void ScAccessibleEditLineTextData::StartEdit()
{
ResetEditMode();
mpEditView = nullptr;
// send SdrHintKind::BeginEdit
SdrHint aHint(SdrHintKind::BeginEdit);
GetBroadcaster().Broadcast( aHint );
}
void ScAccessibleEditLineTextData::EndEdit()
{
// send SdrHintKind::EndEdit
SdrHint aHint(SdrHintKind::EndEdit);
GetBroadcaster().Broadcast( aHint );
ResetEditMode();
mpEditView = nullptr;
}
// ScAccessiblePreviewCellTextData: shared data between sub objects of an accessible cell text object
ScAccessiblePreviewCellTextData::ScAccessiblePreviewCellTextData(ScPreviewShell* pViewShell,
const ScAddress& rP)
: ScAccessibleCellBaseTextData(GetDocShell(pViewShell), rP),
mpViewShell(pViewShell)
{
}
ScAccessiblePreviewCellTextData::~ScAccessiblePreviewCellTextData()
{
if (pEditEngine)
pEditEngine->SetNotifyHdl(Link<EENotify&,void >());
mpViewForwarder.reset();
}
void ScAccessiblePreviewCellTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
if ( rHint.GetId() == SfxHintId::Dying )
{
mpViewShell = nullptr; // invalid now
if (mpViewForwarder)
mpViewForwarder->SetInvalid();
}
ScAccessibleCellBaseTextData::Notify(rBC, rHint);
}
ScAccessibleTextData* ScAccessiblePreviewCellTextData::Clone() const
{
return new ScAccessiblePreviewCellTextData(mpViewShell, aCellPos);
}
SvxTextForwarder* ScAccessiblePreviewCellTextData::GetTextForwarder()
{
bool bEditEngineBefore(pEditEngine != nullptr);
ScCellTextData::GetTextForwarder(); // creates Forwarder and EditEngine
if (!bEditEngineBefore && pEditEngine)
{
Size aSize(mpViewShell->GetLocationData().GetCellOutputRect(aCellPos).GetSize());
vcl::Window* pWin = mpViewShell->GetWindow();
if (pWin)
aSize = pWin->PixelToLogic(aSize, pEditEngine->GetRefMapMode());
pEditEngine->SetPaperSize(aSize);
}
if (pEditEngine)
pEditEngine->SetNotifyHdl( LINK(this , ScAccessiblePreviewCellTextData, NotifyHdl) );
return pForwarder.get();
}
SvxViewForwarder* ScAccessiblePreviewCellTextData::GetViewForwarder()
{
if (!mpViewForwarder)
mpViewForwarder.reset(new ScPreviewCellViewForwarder(mpViewShell));
return mpViewForwarder.get();
}
ScDocShell* ScAccessiblePreviewCellTextData::GetDocShell(ScPreviewShell* pViewShell)
{
ScDocShell* pDocSh = nullptr;
if (pViewShell)
pDocSh = pViewShell->GetDocument().GetDocumentShell();
return pDocSh;
}
// ScAccessiblePreviewHeaderCellTextData: shared data between sub objects of an accessible cell text object
ScAccessiblePreviewHeaderCellTextData::ScAccessiblePreviewHeaderCellTextData(ScPreviewShell* pViewShell,
OUString aText, const ScAddress& rP, bool bColHeader, bool bRowHeader)
: ScAccessibleCellBaseTextData(GetDocShell(pViewShell), rP),
mpViewShell(pViewShell),
maText(std::move(aText)),
mbColHeader(bColHeader),
mbRowHeader(bRowHeader)
{
}
ScAccessiblePreviewHeaderCellTextData::~ScAccessiblePreviewHeaderCellTextData()
{
if (pEditEngine)
pEditEngine->SetNotifyHdl(Link<EENotify&,void >());
mpViewForwarder.reset();
}
void ScAccessiblePreviewHeaderCellTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
if ( rHint.GetId() == SfxHintId::Dying )
{
mpViewShell = nullptr; // invalid now
if (mpViewForwarder)
mpViewForwarder->SetInvalid();
}
ScAccessibleCellBaseTextData::Notify(rBC, rHint);
}
ScAccessibleTextData* ScAccessiblePreviewHeaderCellTextData::Clone() const
{
return new ScAccessiblePreviewHeaderCellTextData(mpViewShell, maText, aCellPos, mbColHeader, mbRowHeader);
}
SvxTextForwarder* ScAccessiblePreviewHeaderCellTextData::GetTextForwarder()
{
if (!pEditEngine)
{
if ( pDocShell )
{
ScDocument& rDoc = pDocShell->GetDocument();
pEditEngine = rDoc.CreateFieldEditEngine();
}
else
{
rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
pEditEngine.reset( new ScFieldEditEngine(nullptr, pEnginePool.get(), nullptr, true ) );
}
pEditEngine->EnableUndo( false );
if (pDocShell)
pEditEngine->SetRefDevice(pDocShell->GetRefDevice());
else
pEditEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
pForwarder.reset( new SvxEditEngineForwarder(*pEditEngine) );
}
if (bDataValid)
return pForwarder.get();
if (!maText.isEmpty())
{
if ( mpViewShell )
{
Size aOutputSize;
vcl::Window* pWindow = mpViewShell->GetWindow();
if ( pWindow )
aOutputSize = pWindow->GetOutputSizePixel();
tools::Rectangle aVisRect( Point(), aOutputSize );
Size aSize(mpViewShell->GetLocationData().GetHeaderCellOutputRect(aVisRect, aCellPos, mbColHeader).GetSize());
if (pWindow)
aSize = pWindow->PixelToLogic(aSize, pEditEngine->GetRefMapMode());
pEditEngine->SetPaperSize(aSize);
}
pEditEngine->SetTextCurrentDefaults( maText );
}
bDataValid = true ;
pEditEngine->SetNotifyHdl( LINK(this , ScAccessiblePreviewHeaderCellTextData, NotifyHdl) );
return pForwarder.get();
}
SvxViewForwarder* ScAccessiblePreviewHeaderCellTextData::GetViewForwarder()
{
if (!mpViewForwarder)
mpViewForwarder.reset(new ScPreviewHeaderCellViewForwarder(mpViewShell));
return mpViewForwarder.get();
}
ScDocShell* ScAccessiblePreviewHeaderCellTextData::GetDocShell(ScPreviewShell* pViewShell)
{
ScDocShell* pDocSh = nullptr;
if (pViewShell)
pDocSh = pViewShell->GetDocument().GetDocumentShell();
return pDocSh;
}
ScAccessibleHeaderTextData::ScAccessibleHeaderTextData(ScPreviewShell* pViewShell,
const EditTextObject* pEditObj, SvxAdjust eAdjust)
:
mpViewShell(pViewShell),
mpDocSh(nullptr),
mpEditObj(pEditObj),
mbDataValid(false ),
meAdjust(eAdjust)
{
if (pViewShell)
mpDocSh = pViewShell->GetDocument().GetDocumentShell();
if (mpDocSh)
mpDocSh->GetDocument().AddUnoObject(*this );
}
ScAccessibleHeaderTextData::~ScAccessibleHeaderTextData()
{
SolarMutexGuard aGuard; // needed for EditEngine dtor
if (mpDocSh)
mpDocSh->GetDocument().RemoveUnoObject(*this );
if (mpEditEngine)
mpEditEngine->SetNotifyHdl(Link<EENotify&,void >());
mpEditEngine.reset();
mpForwarder.reset();
}
ScAccessibleTextData* ScAccessibleHeaderTextData::Clone() const
{
return new ScAccessibleHeaderTextData(mpViewShell, mpEditObj, meAdjust);
}
void ScAccessibleHeaderTextData::Notify( SfxBroadcaster&, const SfxHint& rHint )
{
if ( rHint.GetId() == SfxHintId::Dying )
{
mpViewShell = nullptr;// invalid now
mpDocSh = nullptr;
if (mxViewForwarder)
mxViewForwarder->SetInvalid();
}
}
SvxTextForwarder* ScAccessibleHeaderTextData::GetTextForwarder()
{
if (!mpEditEngine)
{
rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
std::unique_ptr<ScHeaderEditEngine> pHdrEngine(new ScHeaderEditEngine( pEnginePool.get() ));
pHdrEngine->EnableUndo( false );
pHdrEngine->SetRefMapMode(MapMode(MapUnit::MapTwip));
// default font must be set, independently of document
// -> use global pool from module
std::unique_ptr<CellAttributeHelper> pTmp;
const ScPatternAttr* pCellAttributeDefault(nullptr);
if (nullptr != mpDocSh)
{
// we can use default CellAttribute from ScDocument
pCellAttributeDefault = &mpDocSh->GetDocument().getCellAttributeHelper().getDefaultCellAttribute();
}
else
{
// no access to ScDocument, use temporary CellAttributeHelper.
// also see ScHeaderFooterTextData::GetTextForwarder for more comments
pTmp.reset(new CellAttributeHelper(ScModule::get()->GetPool()));
pCellAttributeDefault = &pTmp->getDefaultCellAttribute();
}
SfxItemSet aDefaults(pHdrEngine->GetEmptyItemSet());
pCellAttributeDefault->FillEditItemSet(&aDefaults);
// FillEditItemSet adjusts font height to 1/100th mm,
// but for header/footer twips is needed, as in the PatternAttr:
aDefaults.Put( pCellAttributeDefault->GetItem(ATTR_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT) );
aDefaults.Put( pCellAttributeDefault->GetItem(ATTR_CJK_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CJK) );
aDefaults.Put( pCellAttributeDefault->GetItem(ATTR_CTL_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CTL) );
aDefaults.Put( SvxAdjustItem( meAdjust, EE_PARA_JUST ) );
pHdrEngine->SetDefaults(std::move(aDefaults));
ScHeaderFieldData aData;
if (mpViewShell)
mpViewShell->FillFieldData(aData);
else
ScHeaderFooterTextObj::FillDummyFieldData( aData );
pHdrEngine->SetData( aData );
mpEditEngine = std::move(pHdrEngine);
mpForwarder.reset(new SvxEditEngineForwarder(*mpEditEngine));
}
if (mbDataValid)
return mpForwarder.get();
if ( mpViewShell )
{
tools::Rectangle aVisRect;
mpViewShell->GetLocationData().GetHeaderPosition(aVisRect);
Size aSize(aVisRect.GetSize());
vcl::Window* pWin = mpViewShell->GetWindow();
if (pWin)
aSize = pWin->PixelToLogic(aSize, mpEditEngine->GetRefMapMode());
mpEditEngine->SetPaperSize(aSize);
}
if (mpEditObj)
mpEditEngine->SetTextCurrentDefaults(*mpEditObj);
mbDataValid = true ;
return mpForwarder.get();
}
SvxViewForwarder* ScAccessibleHeaderTextData::GetViewForwarder()
{
if (!mxViewForwarder)
mxViewForwarder = std::make_unique<ScPreviewHeaderFooterViewForwarder>(mpViewShell);
return mxViewForwarder.get();
}
ScAccessibleNoteTextData::ScAccessibleNoteTextData(ScPreviewShell* pViewShell,
OUString sText, const ScAddress& aCellPos, bool bMarkNote)
:
mpViewShell(pViewShell),
mpDocSh(nullptr),
msText(std::move(sText)),
maCellPos(aCellPos),
mbMarkNote(bMarkNote),
mbDataValid(false )
{
if (pViewShell)
mpDocSh = pViewShell->GetDocument().GetDocumentShell();
if (mpDocSh)
mpDocSh->GetDocument().AddUnoObject(*this );
}
ScAccessibleNoteTextData::~ScAccessibleNoteTextData()
{
SolarMutexGuard aGuard; // needed for EditEngine dtor
if (mpDocSh)
mpDocSh->GetDocument().RemoveUnoObject(*this );
if (mpEditEngine)
mpEditEngine->SetNotifyHdl(Link<EENotify&,void >());
mpEditEngine.reset();
mpForwarder.reset();
}
ScAccessibleTextData* ScAccessibleNoteTextData::Clone() const
{
return new ScAccessibleNoteTextData(mpViewShell, msText, maCellPos, mbMarkNote);
}
void ScAccessibleNoteTextData::Notify( SfxBroadcaster&, const SfxHint& rHint )
{
if ( rHint.GetId() == SfxHintId::Dying )
{
mpViewShell = nullptr;// invalid now
mpDocSh = nullptr;
if (mxViewForwarder)
mxViewForwarder->SetInvalid();
}
}
SvxTextForwarder* ScAccessibleNoteTextData::GetTextForwarder()
{
if (!mpEditEngine)
{
if ( mpDocSh )
{
ScDocument& rDoc = mpDocSh->GetDocument();
mpEditEngine = rDoc.CreateFieldEditEngine();
}
else
{
rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
mpEditEngine.reset( new ScFieldEditEngine(nullptr, pEnginePool.get(), nullptr, true ) );
}
mpEditEngine->EnableUndo( false );
if (mpDocSh)
mpEditEngine->SetRefDevice(mpDocSh->GetRefDevice());
else
mpEditEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
mpForwarder.reset( new SvxEditEngineForwarder(*mpEditEngine) );
}
if (mbDataValid)
return mpForwarder.get();
if (!msText.isEmpty())
{
if ( mpViewShell )
{
Size aOutputSize;
vcl::Window* pWindow = mpViewShell->GetWindow();
if ( pWindow )
aOutputSize = pWindow->GetOutputSizePixel();
tools::Rectangle aVisRect( Point(), aOutputSize );
Size aSize(mpViewShell->GetLocationData().GetNoteInRangeOutputRect(aVisRect, mbMarkNote, maCellPos).GetSize());
if (pWindow)
aSize = pWindow->PixelToLogic(aSize, mpEditEngine->GetRefMapMode());
mpEditEngine->SetPaperSize(aSize);
}
mpEditEngine->SetTextCurrentDefaults( msText );
}
mbDataValid = true ;
mpEditEngine->SetNotifyHdl( LINK(this , ScAccessibleNoteTextData, NotifyHdl) );
return mpForwarder.get();
}
SvxViewForwarder* ScAccessibleNoteTextData::GetViewForwarder()
{
if (!mxViewForwarder)
mxViewForwarder = std::make_unique<ScPreviewNoteViewForwarder>(mpViewShell);
return mxViewForwarder.get();
}
// CSV import =================================================================
class ScCsvViewForwarder : public SvxViewForwarder
{
VclPtr<OutputDevice> mpWindow;
public :
explicit ScCsvViewForwarder( OutputDevice* pWindow );
virtual bool IsValid() const override;
virtual Point LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const override;
virtual Point PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const override;
void SetInvalid();
};
ScCsvViewForwarder::ScCsvViewForwarder( OutputDevice* pWindow ) :
mpWindow( pWindow )
{
}
bool ScCsvViewForwarder::IsValid() const
{
return mpWindow != nullptr;
}
Point ScCsvViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
{
if ( !mpWindow ) return Point();
return mpWindow->LogicToPixel( rPoint, rMapMode );
}
Point ScCsvViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
{
if ( !mpWindow ) return Point();
return mpWindow->PixelToLogic( rPoint, rMapMode );
}
void ScCsvViewForwarder::SetInvalid()
{
mpWindow = nullptr;
}
ScAccessibleCsvTextData::ScAccessibleCsvTextData(
OutputDevice* pWindow, EditEngine* pEditEngine,
OUString aCellText, const Size& rCellSize ) :
mpWindow( pWindow ),
mpEditEngine( pEditEngine ),
maCellText(std::move( aCellText )),
maCellSize( rCellSize )
{
}
ScAccessibleCsvTextData::~ScAccessibleCsvTextData()
{
}
void ScAccessibleCsvTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
if ( rHint.GetId() == SfxHintId::Dying )
{
mpWindow = nullptr;
mpEditEngine = nullptr;
if (mpViewForwarder)
mpViewForwarder->SetInvalid();
}
ScAccessibleTextData::Notify( rBC, rHint );
}
ScAccessibleTextData* ScAccessibleCsvTextData::Clone() const
{
return new ScAccessibleCsvTextData( mpWindow, mpEditEngine, maCellText, maCellSize );
}
SvxTextForwarder* ScAccessibleCsvTextData::GetTextForwarder()
{
if ( mpEditEngine )
{
mpEditEngine->SetPaperSize( maCellSize );
mpEditEngine->SetText( maCellText );
if ( !mpTextForwarder )
mpTextForwarder.reset( new SvxEditEngineForwarder( *mpEditEngine ) );
}
else
mpTextForwarder.reset();
return mpTextForwarder.get();
}
SvxViewForwarder* ScAccessibleCsvTextData::GetViewForwarder()
{
if ( !mpViewForwarder )
mpViewForwarder.reset( new ScCsvViewForwarder( mpWindow ) );
return mpViewForwarder.get();
}
SvxEditViewForwarder* ScAccessibleCsvTextData::GetEditViewForwarder( bool /* bCreate */ )
{
return nullptr;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent C=97 H=99 G=97
¤ Dauer der Verarbeitung: 0.30 Sekunden
(vorverarbeitet am 2026-06-12)
¤
*© Formatika GbR, Deutschland