summaryrefslogtreecommitdiffstats
path: root/sc/source/ui/app
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sc/source/ui/app
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sc/source/ui/app')
-rw-r--r--sc/source/ui/app/client.cxx232
-rw-r--r--sc/source/ui/app/drwtrans.cxx738
-rw-r--r--sc/source/ui/app/inputhdl.cxx4635
-rw-r--r--sc/source/ui/app/inputwin.cxx2703
-rw-r--r--sc/source/ui/app/lnktrans.cxx76
-rw-r--r--sc/source/ui/app/msgpool.cxx93
-rw-r--r--sc/source/ui/app/rfindlst.cxx90
-rw-r--r--sc/source/ui/app/scdll.cxx257
-rw-r--r--sc/source/ui/app/scmod.cxx2325
-rw-r--r--sc/source/ui/app/seltrans.cxx429
-rw-r--r--sc/source/ui/app/transobj.cxx921
-rw-r--r--sc/source/ui/app/typemap.cxx140
-rw-r--r--sc/source/ui/app/uiitems.cxx438
13 files changed, 13077 insertions, 0 deletions
diff --git a/sc/source/ui/app/client.cxx b/sc/source/ui/app/client.cxx
new file mode 100644
index 000000000..0886fae89
--- /dev/null
+++ b/sc/source/ui/app/client.cxx
@@ -0,0 +1,232 @@
+/* -*- 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 <com/sun/star/embed/XEmbeddedObject.hpp>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <sfx2/objsh.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdoole2.hxx>
+
+#include <client.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <gridwin.hxx>
+
+using namespace com::sun::star;
+
+ScClient::ScClient( ScTabViewShell* pViewShell, vcl::Window* pDraw, SdrModel* pSdrModel, const SdrOle2Obj* pObj ) :
+ SfxInPlaceClient( pViewShell, pDraw, pObj->GetAspect() ),
+ pModel( pSdrModel )
+{
+ SetObject( pObj->GetObjRef() );
+}
+
+ScClient::~ScClient()
+{
+}
+
+SdrOle2Obj* ScClient::GetDrawObj()
+{
+ uno::Reference < embed::XEmbeddedObject > xObj = GetObject();
+ SdrOle2Obj* pOle2Obj = nullptr;
+ OUString aName = GetViewShell()->GetObjectShell()->GetEmbeddedObjectContainer().GetEmbeddedObjectName( xObj );
+
+ sal_uInt16 nPages = pModel->GetPageCount();
+ for (sal_uInt16 nPNr=0; nPNr<nPages && !pOle2Obj; nPNr++)
+ {
+ SdrPage* pPage = pModel->GetPage(nPNr);
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !pOle2Obj)
+ {
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 )
+ {
+ // name from InfoObject is PersistName
+ if ( static_cast<SdrOle2Obj*>(pObject)->GetPersistName() == aName )
+ pOle2Obj = static_cast<SdrOle2Obj*>(pObject);
+ }
+ pObject = aIter.Next();
+ }
+ }
+ return pOle2Obj;
+}
+
+void ScClient::RequestNewObjectArea( tools::Rectangle& aLogicRect )
+{
+ SfxViewShell* pSfxViewSh = GetViewShell();
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( pSfxViewSh );
+ if (!pViewSh)
+ {
+ OSL_FAIL("Wrong ViewShell");
+ return;
+ }
+
+ tools::Rectangle aOldRect = GetObjArea();
+ SdrOle2Obj* pDrawObj = GetDrawObj();
+ if ( pDrawObj )
+ {
+ if ( pDrawObj->IsResizeProtect() )
+ aLogicRect.SetSize( aOldRect.GetSize() );
+
+ if ( pDrawObj->IsMoveProtect() )
+ aLogicRect.SetPos( aOldRect.TopLeft() );
+ }
+
+ sal_uInt16 nTab = pViewSh->GetViewData().GetTabNo();
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(static_cast<sal_Int16>(nTab)));
+ if ( !(pPage && aLogicRect != aOldRect) )
+ return;
+
+ Point aPos;
+ Size aSize = pPage->GetSize();
+ if ( aSize.Width() < 0 )
+ {
+ aPos.setX( aSize.Width() + 1 ); // negative
+ aSize.setWidth( -aSize.Width() ); // positive
+ }
+ tools::Rectangle aPageRect( aPos, aSize );
+
+ if (aLogicRect.Right() > aPageRect.Right())
+ {
+ tools::Long nDiff = aLogicRect.Right() - aPageRect.Right();
+ aLogicRect.AdjustLeft( -nDiff );
+ aLogicRect.AdjustRight( -nDiff );
+ }
+ if (aLogicRect.Bottom() > aPageRect.Bottom())
+ {
+ tools::Long nDiff = aLogicRect.Bottom() - aPageRect.Bottom();
+ aLogicRect.AdjustTop( -nDiff );
+ aLogicRect.AdjustBottom( -nDiff );
+ }
+
+ if (aLogicRect.Left() < aPageRect.Left())
+ {
+ tools::Long nDiff = aLogicRect.Left() - aPageRect.Left();
+ aLogicRect.AdjustRight( -nDiff );
+ aLogicRect.AdjustLeft( -nDiff );
+ }
+ if (aLogicRect.Top() < aPageRect.Top())
+ {
+ tools::Long nDiff = aLogicRect.Top() - aPageRect.Top();
+ aLogicRect.AdjustBottom( -nDiff );
+ aLogicRect.AdjustTop( -nDiff );
+ }
+}
+
+void ScClient::ObjectAreaChanged()
+{
+ SfxViewShell* pSfxViewSh = GetViewShell();
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( pSfxViewSh );
+ if (!pViewSh)
+ {
+ OSL_FAIL("Wrong ViewShell");
+ return;
+ }
+
+ // Take over position and size into document
+ SdrOle2Obj* pDrawObj = GetDrawObj();
+ if (!pDrawObj)
+ return;
+
+ tools::Rectangle aNewRectangle(GetScaledObjArea());
+
+ // #i118524# if sheared/rotated, center to non-rotated LogicRect
+ pDrawObj->setSuppressSetVisAreaSize(true);
+
+ if(pDrawObj->GetGeoStat().nRotationAngle || pDrawObj->GetGeoStat().nShearAngle)
+ {
+ pDrawObj->SetLogicRect( aNewRectangle );
+
+ const tools::Rectangle& rBoundRect = pDrawObj->GetCurrentBoundRect();
+ const Point aDelta(aNewRectangle.Center() - rBoundRect.Center());
+
+ aNewRectangle.Move(aDelta.X(), aDelta.Y());
+ }
+
+ pDrawObj->SetLogicRect( aNewRectangle );
+ pDrawObj->setSuppressSetVisAreaSize(false);
+
+ // set document modified (SdrModel::SetChanged is not used)
+ pViewSh->GetViewData().GetDocShell()->SetDrawModified();
+ pViewSh->ScrollToObject(pDrawObj);
+}
+
+void ScClient::ViewChanged()
+{
+ if ( GetAspect() == embed::Aspects::MSOLE_ICON )
+ {
+ // the iconified object seems not to need such a scaling handling
+ // since the replacement image and the size a completely controlled by the container
+ // TODO/LATER: when the icon exchange is implemented the scaling handling might be required again here
+
+ return;
+ }
+
+ uno::Reference < embed::XEmbeddedObject > xObj = GetObject();
+
+ // TODO/LEAN: working with Visual Area can switch object to running state
+ awt::Size aSz;
+ try {
+ aSz = xObj->getVisualAreaSize( GetAspect() );
+ } catch (const uno::Exception&) {
+ TOOLS_WARN_EXCEPTION("sc", "The visual area size must be available!");
+ return; // leave it unchanged on failure
+ }
+
+ MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( GetAspect() ) );
+ Size aVisSize = OutputDevice::LogicToLogic(Size(aSz.Width, aSz.Height), MapMode(aMapUnit), MapMode(MapUnit::Map100thMM));
+
+ // Take over position and size into document
+ SdrOle2Obj* pDrawObj = GetDrawObj();
+ if (!pDrawObj)
+ return;
+
+ tools::Rectangle aLogicRect = pDrawObj->GetLogicRect();
+ Fraction aFractX = GetScaleWidth() * aVisSize.Width();
+ Fraction aFractY = GetScaleHeight() * aVisSize.Height();
+ aVisSize = Size( static_cast<tools::Long>(aFractX), static_cast<tools::Long>(aFractY) ); // Scaled for Draw model
+
+ // pClientData->SetObjArea before pDrawObj->SetLogicRect, so that we don't
+ // calculate wrong scalings:
+ //Rectangle aObjArea = aLogicRect;
+ //aObjArea.SetSize( aVisSize ); // Document size from the server
+ //SetObjArea( aObjArea );
+
+ SfxViewShell* pSfxViewSh = GetViewShell();
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( pSfxViewSh );
+ if ( pViewSh )
+ {
+ vcl::Window* pWin = pViewSh->GetActiveWin();
+ if ( pWin->LogicToPixel( aVisSize ) != pWin->LogicToPixel( aLogicRect.GetSize() ) )
+ {
+ aLogicRect.SetSize( aVisSize );
+ pDrawObj->SetLogicRect( aLogicRect );
+
+ // set document modified (SdrModel::SetChanged is not used)
+ pViewSh->GetViewData().GetDocShell()->SetDrawModified();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/drwtrans.cxx b/sc/source/ui/app/drwtrans.cxx
new file mode 100644
index 000000000..8cd335b2e
--- /dev/null
+++ b/sc/source/ui/app/drwtrans.cxx
@@ -0,0 +1,738 @@
+/* -*- 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 <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/embed/XEmbedPersist.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/uno/Exception.hpp>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <unotools/streamwrap.hxx>
+
+#include <svx/unomodel.hxx>
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/servicehelper.hxx>
+
+#include <svtools/embedtransfer.hxx>
+#include <sot/storage.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdouno.hxx>
+#include <sfx2/docfile.hxx>
+#include <svl/itempool.hxx>
+#include <svl/urlbmk.hxx>
+#include <tools/urlobj.hxx>
+#include <osl/diagnose.h>
+
+#include <drwtrans.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+#include <drawview.hxx>
+#include <viewdata.hxx>
+#include <scmod.hxx>
+#include <dragdata.hxx>
+
+#include <editeng/eeitem.hxx>
+
+#include <editeng/fhgtitem.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace com::sun::star;
+
+constexpr sal_uInt32 SCDRAWTRANS_TYPE_EMBOBJ = 1;
+constexpr sal_uInt32 SCDRAWTRANS_TYPE_DRAWMODEL = 2;
+constexpr sal_uInt32 SCDRAWTRANS_TYPE_DOCUMENT = 3;
+
+ScDrawTransferObj::ScDrawTransferObj( std::unique_ptr<SdrModel> pClipModel, ScDocShell* pContainerShell,
+ const TransferableObjectDescriptor& rDesc ) :
+ m_pModel( std::move(pClipModel) ),
+ m_aObjDesc( rDesc ),
+ m_bGraphic( false ),
+ m_bGrIsBit( false ),
+ m_bOleObj( false ),
+ m_nDragSourceFlags( ScDragSrc::Undefined ),
+ m_bDragWasInternal( false ),
+ maShellID(SfxObjectShell::CreateShellID(pContainerShell))
+{
+
+ // check what kind of objects are contained
+
+ SdrPage* pPage = m_pModel->GetPage(0);
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::Flat );
+ SdrObject* pObject = aIter.Next();
+ if (pObject && !aIter.Next()) // exactly one object?
+ {
+
+ // OLE object
+
+ SdrObjKind nSdrObjKind = pObject->GetObjIdentifier();
+ if (nSdrObjKind == SdrObjKind::OLE2)
+ {
+ // if object has no persistence it must be copied as a part of document
+ try
+ {
+ uno::Reference< embed::XEmbedPersist > xPersObj( static_cast<SdrOle2Obj*>(pObject)->GetObjRef(), uno::UNO_QUERY );
+ if ( xPersObj.is() && xPersObj->hasEntry() )
+ m_bOleObj = true;
+ }
+ catch( uno::Exception& )
+ {}
+ // aOleData is initialized later
+ }
+
+ // Graphic object
+
+ if (nSdrObjKind == SdrObjKind::Graphic)
+ {
+ m_bGraphic = true;
+ if ( static_cast<SdrGrafObj*>(pObject)->GetGraphic().GetType() == GraphicType::Bitmap )
+ m_bGrIsBit = true;
+ }
+
+ // URL button
+
+ SdrUnoObj* pUnoCtrl = dynamic_cast<SdrUnoObj*>( pObject );
+ if (pUnoCtrl && SdrInventor::FmForm == pUnoCtrl->GetObjInventor())
+ {
+ const uno::Reference<awt::XControlModel>& xControlModel = pUnoCtrl->GetUnoControlModel();
+ OSL_ENSURE( xControlModel.is(), "uno control without model" );
+ if ( xControlModel.is() )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY );
+ uno::Reference< beans::XPropertySetInfo > xInfo = xPropSet->getPropertySetInfo();
+
+ OUString sPropButtonType( "ButtonType" );
+
+ if(xInfo->hasPropertyByName( sPropButtonType ))
+ {
+ uno::Any aAny = xPropSet->getPropertyValue( sPropButtonType );
+ form::FormButtonType eTmp;
+ if ( (aAny >>= eTmp) && eTmp == form::FormButtonType_URL )
+ {
+ // URL
+ OUString sPropTargetURL( "TargetURL" );
+ if(xInfo->hasPropertyByName( sPropTargetURL ))
+ {
+ aAny = xPropSet->getPropertyValue( sPropTargetURL );
+ OUString sTmp;
+ if ( (aAny >>= sTmp) && !sTmp.isEmpty() )
+ {
+ OUString aUrl = sTmp;
+ OUString aAbs = aUrl;
+ if (pContainerShell)
+ {
+ const SfxMedium* pMedium = pContainerShell->GetMedium();
+ if (pMedium)
+ {
+ bool bWasAbs = true;
+ aAbs = pMedium->GetURLObject().smartRel2Abs( aUrl, bWasAbs ).
+ GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ // full path as stored INetBookmark must be encoded
+ }
+ }
+
+ // Label
+ OUString aLabel;
+ OUString sPropLabel( "Label" );
+ if(xInfo->hasPropertyByName( sPropLabel ))
+ {
+ aAny = xPropSet->getPropertyValue( sPropLabel );
+ if ( (aAny >>= sTmp) && !sTmp.isEmpty() )
+ {
+ aLabel = sTmp;
+ }
+ }
+ m_pBookmark.reset( new INetBookmark( aAbs, aLabel ) );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // get size for object descriptor
+
+ // #i71538# use complete SdrViews
+ // SdrExchangeView aView(pModel);
+ SdrView aView(*m_pModel);
+ SdrPageView* pPv = aView.ShowSdrPage(aView.GetModel()->GetPage(0));
+ aView.MarkAllObj(pPv);
+ m_aSrcSize = aView.GetAllMarkedRect().GetSize();
+
+ if ( m_bOleObj ) // single OLE object
+ {
+ SdrOle2Obj* pObj = GetSingleObject();
+ if ( pObj && pObj->GetObjRef().is() )
+ SvEmbedTransferHelper::FillTransferableObjectDescriptor( m_aObjDesc, pObj->GetObjRef(), pObj->GetGraphic(), pObj->GetAspect() );
+ }
+
+ m_aObjDesc.maSize = m_aSrcSize;
+ PrepareOLE( m_aObjDesc );
+
+ // remember a unique ID of the source document
+
+ if ( pContainerShell )
+ {
+ ScDocument& rDoc = pContainerShell->GetDocument();
+ if ( pPage )
+ {
+ ScChartHelper::FillProtectedChartRangesVector( m_aProtectedChartRangesVector, rDoc, pPage );
+ }
+ }
+}
+
+ScDrawTransferObj::~ScDrawTransferObj()
+{
+ SolarMutexGuard aSolarGuard;
+
+ ScModule* pScMod = SC_MOD();
+ if (pScMod && pScMod->GetDragData().pDrawTransfer == this)
+ {
+ OSL_FAIL("ScDrawTransferObj wasn't released");
+ pScMod->ResetDragObject();
+ }
+
+ m_aOleData = TransferableDataHelper(); // clear before releasing the mutex
+ m_aDocShellRef.clear();
+
+ m_pModel.reset();
+ m_aDrawPersistRef.clear(); // after the model
+
+ m_pBookmark.reset();
+ m_pDragSourceView.reset();
+}
+
+ScDrawTransferObj* ScDrawTransferObj::GetOwnClipboard(const uno::Reference<datatransfer::XTransferable2>& xTransferable)
+{
+ return comphelper::getFromUnoTunnel<ScDrawTransferObj>(xTransferable);
+}
+
+static bool lcl_HasOnlyControls( SdrModel* pModel )
+{
+ bool bOnlyControls = false; // default if there are no objects
+
+ if ( pModel )
+ {
+ SdrPage* pPage = pModel->GetPage(0);
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObj = aIter.Next();
+ if ( pObj )
+ {
+ bOnlyControls = true; // only set if there are any objects at all
+ while ( pObj )
+ {
+ if (dynamic_cast<const SdrUnoObj*>( pObj) == nullptr)
+ {
+ bOnlyControls = false;
+ break;
+ }
+ pObj = aIter.Next();
+ }
+ }
+ }
+ }
+
+ return bOnlyControls;
+}
+
+void ScDrawTransferObj::AddSupportedFormats()
+{
+ if ( m_bGrIsBit ) // single bitmap graphic
+ {
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::SVXB );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ }
+ else if ( m_bGraphic ) // other graphic
+ {
+ // #i25616#
+ AddFormat( SotClipboardFormatId::DRAWING );
+
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::SVXB );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ }
+ else if ( m_pBookmark ) // url button
+ {
+// AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::SOLK );
+ AddFormat( SotClipboardFormatId::STRING );
+ AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
+ AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
+ AddFormat( SotClipboardFormatId::DRAWING );
+ }
+ else if ( m_bOleObj ) // single OLE object
+ {
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+
+ CreateOLEData();
+
+ if ( m_aOleData.GetTransferable().is() )
+ {
+ // get format list from object snapshot
+ // (this must be after inserting the default formats!)
+
+ DataFlavorExVector aVector( m_aOleData.GetDataFlavorExVector() );
+
+ for( const auto& rItem : aVector )
+ AddFormat( rItem );
+ }
+ }
+ else // any drawing objects
+ {
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::DRAWING );
+
+ // leave out bitmap and metafile if there are only controls
+ if ( !lcl_HasOnlyControls( m_pModel.get() ) )
+ {
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ }
+ }
+
+// if( pImageMap )
+// AddFormat( SotClipboardFormatId::SVIM );
+}
+
+bool ScDrawTransferObj::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc )
+{
+ bool bOK = false;
+ SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+
+ if ( m_bOleObj && nFormat != SotClipboardFormatId::GDIMETAFILE )
+ {
+ CreateOLEData();
+
+ if( m_aOleData.GetTransferable().is() && m_aOleData.HasFormat( rFlavor ) )
+ {
+ bOK = SetAny( m_aOleData.GetAny(rFlavor, rDestDoc) );
+
+ return bOK;
+ }
+ }
+
+ if( HasFormat( nFormat ) )
+ {
+ if ( nFormat == SotClipboardFormatId::LINKSRCDESCRIPTOR || nFormat == SotClipboardFormatId::OBJECTDESCRIPTOR )
+ {
+ bOK = SetTransferableObjectDescriptor( m_aObjDesc );
+ }
+ else if ( nFormat == SotClipboardFormatId::DRAWING )
+ {
+ bOK = SetObject( m_pModel.get(), SCDRAWTRANS_TYPE_DRAWMODEL, rFlavor );
+ }
+ else if ( nFormat == SotClipboardFormatId::BITMAP
+ || nFormat == SotClipboardFormatId::PNG
+ || nFormat == SotClipboardFormatId::GDIMETAFILE )
+ {
+ // #i71538# use complete SdrViews
+ // SdrExchangeView aView( pModel );
+ SdrView aView(*m_pModel);
+ SdrPageView* pPv = aView.ShowSdrPage(aView.GetModel()->GetPage(0));
+ OSL_ENSURE( pPv, "pPv not there..." );
+ aView.MarkAllObj( pPv );
+ if ( nFormat == SotClipboardFormatId::GDIMETAFILE )
+ bOK = SetGDIMetaFile( aView.GetMarkedObjMetaFile(true) );
+ else
+ bOK = SetBitmapEx( aView.GetMarkedObjBitmapEx(true), rFlavor );
+ }
+ else if ( nFormat == SotClipboardFormatId::SVXB )
+ {
+ // only enabled for single graphics object
+
+ SdrPage* pPage = m_pModel->GetPage(0);
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::Flat );
+ SdrObject* pObject = aIter.Next();
+ if (pObject && pObject->GetObjIdentifier() == SdrObjKind::Graphic)
+ {
+ SdrGrafObj* pGraphObj = static_cast<SdrGrafObj*>(pObject);
+ bOK = SetGraphic( pGraphObj->GetGraphic() );
+ }
+ }
+ }
+ else if ( nFormat == SotClipboardFormatId::EMBED_SOURCE )
+ {
+ if ( m_bOleObj ) // single OLE object
+ {
+ SdrOle2Obj* pObj = GetSingleObject();
+ if ( pObj && pObj->GetObjRef().is() )
+ {
+ bOK = SetObject( pObj->GetObjRef().get(), SCDRAWTRANS_TYPE_EMBOBJ, rFlavor );
+ }
+ }
+ else // create object from contents
+ {
+ //TODO/LATER: needs new Format, because now single OLE and "this" are different
+ InitDocShell(); // set aDocShellRef
+
+ SfxObjectShell* pEmbObj = m_aDocShellRef.get();
+ bOK = SetObject( pEmbObj, SCDRAWTRANS_TYPE_DOCUMENT, rFlavor );
+ }
+ }
+ else if( m_pBookmark )
+ {
+ bOK = SetINetBookmark( *m_pBookmark, rFlavor );
+ }
+ }
+ return bOK;
+}
+
+bool ScDrawTransferObj::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId,
+ const css::datatransfer::DataFlavor& /* rFlavor */ )
+{
+ // called from SetObject, put data into stream
+
+ bool bRet = false;
+ switch (nUserObjectId)
+ {
+ case SCDRAWTRANS_TYPE_DRAWMODEL:
+ {
+ SdrModel* pDrawModel = static_cast<SdrModel*>(pUserObject);
+ rxOStm->SetBufferSize( 0xff00 );
+
+ // for the changed pool defaults from drawing layer pool set those
+ // attributes as hard attributes to preserve them for saving
+ const SfxItemPool& rItemPool = m_pModel->GetItemPool();
+ const SvxFontHeightItem& rDefaultFontHeight = rItemPool.GetDefaultItem(EE_CHAR_FONTHEIGHT);
+
+ // SW should have no MasterPages
+ OSL_ENSURE(0 == m_pModel->GetMasterPageCount(), "SW with MasterPages (!)");
+
+ for(sal_uInt16 a(0); a < m_pModel->GetPageCount(); a++)
+ {
+ const SdrPage* pPage(m_pModel->GetPage(a));
+ SdrObjListIter aIter(pPage, SdrIterMode::DeepNoGroups);
+
+ while(aIter.IsMore())
+ {
+ SdrObject* pObj = aIter.Next();
+ const SvxFontHeightItem& rItem = pObj->GetMergedItem(EE_CHAR_FONTHEIGHT);
+
+ if(rItem.GetHeight() == rDefaultFontHeight.GetHeight())
+ {
+ pObj->SetMergedItem(rDefaultFontHeight);
+ }
+ }
+ }
+
+ {
+ css::uno::Reference<css::io::XOutputStream> xDocOut( new utl::OOutputStreamWrapper( *rxOStm ) );
+ SvxDrawingLayerExport( pDrawModel, xDocOut );
+ }
+
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+ break;
+
+ case SCDRAWTRANS_TYPE_EMBOBJ:
+ {
+ // impl. for "single OLE"
+ embed::XEmbeddedObject* pEmbObj = static_cast<embed::XEmbeddedObject*>(pUserObject);
+
+ ::utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ uno::Reference< embed::XStorage > xWorkStore =
+ ::comphelper::OStorageHelper::GetStorageFromURL( aTempFile.GetURL(), embed::ElementModes::READWRITE );
+
+ uno::Reference < embed::XEmbedPersist > xPers( static_cast<embed::XVisualObject*>(pEmbObj), uno::UNO_QUERY );
+ if ( xPers.is() )
+ {
+ try
+ {
+ uno::Sequence < beans::PropertyValue > aSeq;
+ OUString aDummyName("Dummy");
+ xPers->storeToEntry( xWorkStore, aDummyName, aSeq, aSeq );
+ if ( xWorkStore->isStreamElement( aDummyName ) )
+ {
+ uno::Reference < io::XOutputStream > xDocOut( new utl::OOutputStreamWrapper( *rxOStm ) );
+ uno::Reference < io::XStream > xNewStream = xWorkStore->openStreamElement( aDummyName, embed::ElementModes::READ );
+ ::comphelper::OStorageHelper::CopyInputToOutput( xNewStream->getInputStream(), xDocOut );
+ }
+ else
+ {
+ uno::Reference < io::XStream > xDocStr( new utl::OStreamWrapper( *rxOStm ) );
+ uno::Reference< embed::XStorage > xDocStg = ::comphelper::OStorageHelper::GetStorageFromStream( xDocStr );
+ uno::Reference < embed::XStorage > xNewStg = xWorkStore->openStorageElement( aDummyName, embed::ElementModes::READ );
+ xNewStg->copyToStorage( xDocStg );
+ uno::Reference < embed::XTransactedObject > xTrans( xDocStg, uno::UNO_QUERY );
+ if ( xTrans.is() )
+ xTrans->commit();
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+
+ break;
+ }
+ case SCDRAWTRANS_TYPE_DOCUMENT:
+ {
+ // impl. for "DocShell"
+ SfxObjectShell* pEmbObj = static_cast<SfxObjectShell*>(pUserObject);
+
+ try
+ {
+ ::utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ uno::Reference< embed::XStorage > xWorkStore =
+ ::comphelper::OStorageHelper::GetStorageFromURL( aTempFile.GetURL(), embed::ElementModes::READWRITE );
+
+ // write document storage
+ pEmbObj->SetupStorage( xWorkStore, SOFFICE_FILEFORMAT_CURRENT, false );
+
+ // mba: no relative URLs for clipboard!
+ SfxMedium aMedium( xWorkStore, OUString() );
+ pEmbObj->DoSaveObjectAs( aMedium, false );
+ pEmbObj->DoSaveCompleted();
+
+ uno::Reference< embed::XTransactedObject > xTransact( xWorkStore, uno::UNO_QUERY );
+ if ( xTransact.is() )
+ xTransact->commit();
+
+ std::unique_ptr<SvStream> pSrcStm = ::utl::UcbStreamHelper::CreateStream( aTempFile.GetURL(), StreamMode::READ );
+ if( pSrcStm )
+ {
+ rxOStm->SetBufferSize( 0xff00 );
+ rxOStm->WriteStream( *pSrcStm );
+ pSrcStm.reset();
+ }
+
+ xWorkStore->dispose();
+ xWorkStore.clear();
+ }
+ catch ( uno::Exception& )
+ {}
+
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+ break;
+
+ default:
+ OSL_FAIL("unknown object id");
+ }
+ return bRet;
+}
+
+void ScDrawTransferObj::DragFinished( sal_Int8 nDropAction )
+{
+ if ( nDropAction == DND_ACTION_MOVE && !m_bDragWasInternal && !(m_nDragSourceFlags & ScDragSrc::Navigator) )
+ {
+ // move: delete source objects
+
+ if ( m_pDragSourceView )
+ m_pDragSourceView->DeleteMarked();
+ }
+
+ ScModule* pScMod = SC_MOD();
+ if ( pScMod->GetDragData().pDrawTransfer == this )
+ pScMod->ResetDragObject();
+
+ m_pDragSourceView.reset();
+
+ TransferDataContainer::DragFinished( nDropAction );
+}
+
+void ScDrawTransferObj::SetDrawPersist( const SfxObjectShellRef& rRef )
+{
+ m_aDrawPersistRef = rRef;
+}
+
+static void lcl_InitMarks( SdrMarkView& rDest, const SdrMarkView& rSource, SCTAB nTab )
+{
+ rDest.ShowSdrPage(rDest.GetModel()->GetPage(nTab));
+ SdrPageView* pDestPV = rDest.GetSdrPageView();
+ OSL_ENSURE(pDestPV,"PageView ?");
+
+ const SdrMarkList& rMarkList = rSource.GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ SdrMark* pMark = rMarkList.GetMark(i);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ rDest.MarkObj(pObj, pDestPV);
+ }
+}
+
+void ScDrawTransferObj::SetDragSource( const ScDrawView* pView )
+{
+ m_pDragSourceView.reset(new SdrView(pView->getSdrModelFromSdrView())); // TTTT pView should be reference
+ lcl_InitMarks( *m_pDragSourceView, *pView, pView->GetTab() );
+
+ //! add as listener with document, delete pDragSourceView if document gone
+}
+
+void ScDrawTransferObj::SetDragSourceObj( SdrObject& rObj, SCTAB nTab )
+{
+ m_pDragSourceView.reset(new SdrView(rObj.getSdrModelFromSdrObject()));
+ m_pDragSourceView->ShowSdrPage(m_pDragSourceView->GetModel()->GetPage(nTab));
+ SdrPageView* pPV = m_pDragSourceView->GetSdrPageView();
+ m_pDragSourceView->MarkObj(&rObj, pPV); // TTTT MarkObj should take SdrObject&
+
+ //! add as listener with document, delete pDragSourceView if document gone
+}
+
+void ScDrawTransferObj::SetDragSourceFlags(ScDragSrc nFlags)
+{
+ m_nDragSourceFlags = nFlags;
+}
+
+void ScDrawTransferObj::SetDragWasInternal()
+{
+ m_bDragWasInternal = true;
+}
+
+const OUString& ScDrawTransferObj::GetShellID() const
+{
+ return maShellID;
+}
+
+SdrOle2Obj* ScDrawTransferObj::GetSingleObject()
+{
+ // if single OLE object was copied, get its object
+
+ SdrPage* pPage = m_pModel->GetPage(0);
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::Flat );
+ SdrObject* pObject = aIter.Next();
+ if (pObject && pObject->GetObjIdentifier() == SdrObjKind::OLE2)
+ {
+ return static_cast<SdrOle2Obj*>(pObject);
+ }
+ }
+
+ return nullptr;
+}
+
+void ScDrawTransferObj::CreateOLEData()
+{
+ if (m_aOleData.GetTransferable().is())
+ // Already created.
+ return;
+
+ SdrOle2Obj* pObj = GetSingleObject();
+ if (!pObj || !pObj->GetObjRef().is())
+ // No OLE object present.
+ return;
+
+ rtl::Reference<SvEmbedTransferHelper> pEmbedTransfer =
+ new SvEmbedTransferHelper(
+ pObj->GetObjRef(), pObj->GetGraphic(), pObj->GetAspect());
+
+ pEmbedTransfer->SetParentShellID(maShellID);
+
+ m_aOleData = TransferableDataHelper(pEmbedTransfer);
+}
+
+// initialize aDocShellRef with a live document from the ClipDoc
+
+void ScDrawTransferObj::InitDocShell()
+{
+ if ( m_aDocShellRef.is() )
+ return;
+
+ ScDocShell* pDocSh = new ScDocShell;
+ m_aDocShellRef = pDocSh; // ref must be there before InitNew
+
+ pDocSh->DoInitNew();
+
+ ScDocument& rDestDoc = pDocSh->GetDocument();
+ rDestDoc.InitDrawLayer( pDocSh );
+
+ SdrModel* pDestModel = rDestDoc.GetDrawLayer();
+ // #i71538# use complete SdrViews
+ // SdrExchangeView aDestView( pDestModel );
+ SdrView aDestView(*pDestModel);
+ aDestView.ShowSdrPage(aDestView.GetModel()->GetPage(0));
+ aDestView.Paste(
+ *m_pModel,
+ Point(m_aSrcSize.Width()/2, m_aSrcSize.Height()/2),
+ nullptr, SdrInsertFlags::NONE);
+
+ // put objects to right layer (see ScViewFunc::PasteDataFormat for SotClipboardFormatId::DRAWING)
+
+ SdrPage* pPage = pDestModel->GetPage(0);
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( dynamic_cast<const SdrUnoObj*>( pObject) != nullptr )
+ pObject->NbcSetLayer(SC_LAYER_CONTROLS);
+ else
+ pObject->NbcSetLayer(SC_LAYER_FRONT);
+ pObject = aIter.Next();
+ }
+ }
+
+ tools::Rectangle aDestArea( Point(), m_aSrcSize );
+ pDocSh->SetVisArea( aDestArea );
+
+ ScViewOptions aViewOpt( rDestDoc.GetViewOptions() );
+ aViewOpt.SetOption( VOPT_GRID, false );
+ rDestDoc.SetViewOptions( aViewOpt );
+
+ ScViewData aViewData( *pDocSh, nullptr );
+ aViewData.SetTabNo( 0 );
+ aViewData.SetScreen( aDestArea );
+ aViewData.SetCurX( 0 );
+ aViewData.SetCurY( 0 );
+ pDocSh->UpdateOle(aViewData, true);
+}
+
+const css::uno::Sequence< sal_Int8 >& ScDrawTransferObj::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theScDrawTransferObjUnoTunnelId;
+ return theScDrawTransferObjUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL ScDrawTransferObj::getSomething( const css::uno::Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(
+ rId, this, comphelper::FallbackToGetSomethingOf<TransferDataContainer>{});
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx
new file mode 100644
index 000000000..884e2e696
--- /dev/null
+++ b/sc/source/ui/app/inputhdl.cxx
@@ -0,0 +1,4635 @@
+/* -*- 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 <iterator>
+#include <memory>
+#include <string_view>
+
+#include <inputhdl.hxx>
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <sfx2/app.hxx>
+#include <editeng/acorrcfg.hxx>
+#include <formula/errorcodes.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <svtools/colorcfg.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/svxacorr.hxx>
+#include <editeng/unolingu.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <editeng/misspellrange.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/printer.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/charclass.hxx>
+#include <vcl/help.hxx>
+#include <vcl/jsdialog/executor.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/urlobj.hxx>
+#include <formula/formulahelper.hxx>
+#include <formula/funcvarargs.h>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+#include <osl/diagnose.h>
+
+#include <attrib.hxx>
+#include <inputwin.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <scmod.hxx>
+#include <formulaopt.hxx>
+#include <uiitems.hxx>
+#include <global.hxx>
+#include <sc.hrc>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <patattr.hxx>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <docpool.hxx>
+#include <editutil.hxx>
+#include <appoptio.hxx>
+#include <docoptio.hxx>
+#include <validat.hxx>
+#include <rfindlst.hxx>
+#include <inputopt.hxx>
+#include <simpleformulacalc.hxx>
+#include <compiler.hxx>
+#include <editable.hxx>
+#include <funcdesc.hxx>
+#include <markdata.hxx>
+#include <tokenarray.hxx>
+#include <gridwin.hxx>
+#include <output.hxx>
+#include <fillinfo.hxx>
+
+// Maximum Ranges in RangeFinder
+#define RANGEFIND_MAX 128
+
+using namespace formula;
+
+namespace {
+
+ScTypedCaseStrSet::const_iterator findText(
+ const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator const & itPos,
+ const OUString& rStart, OUString& rResult, bool bBack)
+{
+ auto lIsMatch = [&rStart](const ScTypedStrData& rData) {
+ return (rData.GetStringType() != ScTypedStrData::Value) && ScGlobal::GetTransliteration().isMatch(rStart, rData.GetString()); };
+
+ if (bBack) // Backwards
+ {
+ ScTypedCaseStrSet::const_reverse_iterator it = rDataSet.rbegin(), itEnd = rDataSet.rend();
+ if (itPos != rDataSet.end())
+ {
+ size_t nPos = std::distance(rDataSet.begin(), itPos);
+ size_t nRPos = rDataSet.size() - 1 - nPos;
+ std::advance(it, nRPos);
+ ++it;
+ }
+
+ it = std::find_if(it, itEnd, lIsMatch);
+ if (it != itEnd)
+ {
+ rResult = it->GetString();
+ return (++it).base(); // convert the reverse iterator back to iterator.
+ }
+ }
+ else // Forwards
+ {
+ ScTypedCaseStrSet::const_iterator it = rDataSet.begin(), itEnd = rDataSet.end();
+ if (itPos != itEnd)
+ {
+ it = std::next(itPos);
+ }
+
+ it = std::find_if(it, itEnd, lIsMatch);
+ if (it != itEnd)
+ {
+ rResult = it->GetString();
+ return it;
+ }
+ }
+
+ return rDataSet.end(); // no matching text found
+}
+
+OUString getExactMatch(const ScTypedCaseStrSet& rDataSet, const OUString& rString)
+{
+ auto it = std::find_if(rDataSet.begin(), rDataSet.end(),
+ [&rString](const ScTypedStrData& rData) {
+ return (rData.GetStringType() != ScTypedStrData::Value)
+ && ScGlobal::GetTransliteration().isEqual(rData.GetString(), rString);
+ });
+ if (it != rDataSet.end())
+ return it->GetString();
+ return rString;
+}
+
+// This assumes that rResults is a sorted ring w.r.t ScTypedStrData::LessCaseInsensitive() or
+// in the reverse direction, whose origin is specified by nRingOrigin.
+sal_Int32 getLongestCommonPrefixLength(const std::vector<OUString>& rResults, const OUString& rUserEntry, sal_Int32 nRingOrigin)
+{
+ sal_Int32 nResults = rResults.size();
+ if (!nResults)
+ return 0;
+
+ if (nResults == 1)
+ return rResults[0].getLength();
+
+ sal_Int32 nMinLen = rUserEntry.getLength();
+ sal_Int32 nLastIdx = nRingOrigin ? nRingOrigin - 1 : nResults - 1;
+ const OUString& rFirst = rResults[nRingOrigin];
+ const OUString& rLast = rResults[nLastIdx];
+ const sal_Int32 nMaxLen = std::min(rFirst.getLength(), rLast.getLength());
+
+ for (sal_Int32 nLen = nMaxLen; nLen > nMinLen; --nLen)
+ {
+ if (ScGlobal::GetTransliteration().isMatch(rFirst.copy(0, nLen), rLast))
+ return nLen;
+ }
+
+ return nMinLen;
+}
+
+ScTypedCaseStrSet::const_iterator findTextAll(
+ const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator const & itPos,
+ const OUString& rStart, ::std::vector< OUString > &rResultVec, bool bBack, sal_Int32* pLongestPrefixLen = nullptr)
+{
+ rResultVec.clear(); // clear contents
+
+ if (!rDataSet.size())
+ return rDataSet.end();
+
+ sal_Int32 nRingOrigin = 0;
+ size_t nCount = 0;
+ ScTypedCaseStrSet::const_iterator retit;
+ if ( bBack ) // Backwards
+ {
+ ScTypedCaseStrSet::const_reverse_iterator it, itEnd;
+ if ( itPos == rDataSet.end() )
+ {
+ it = rDataSet.rend();
+ --it;
+ itEnd = it;
+ }
+ else
+ {
+ it = rDataSet.rbegin();
+ size_t nPos = std::distance(rDataSet.begin(), itPos);
+ size_t nRPos = rDataSet.size() - 1 - nPos; // if itPos == rDataSet.end(), then nRPos = -1
+ std::advance(it, nRPos);
+ if ( it == rDataSet.rend() )
+ it = rDataSet.rbegin();
+ itEnd = it;
+ }
+ bool bFirstTime = true;
+
+ while ( it != itEnd || bFirstTime )
+ {
+ ++it;
+ if ( it == rDataSet.rend() ) // go to the first if reach the end
+ {
+ it = rDataSet.rbegin();
+ nRingOrigin = nCount;
+ }
+
+ if ( bFirstTime )
+ bFirstTime = false;
+ const ScTypedStrData& rData = *it;
+ if ( rData.GetStringType() == ScTypedStrData::Value )
+ // skip values
+ continue;
+
+ if ( !ScGlobal::GetTransliteration().isMatch(rStart, rData.GetString()) )
+ // not a match
+ continue;
+
+ rResultVec.push_back(rData.GetString()); // set the match data
+ if ( nCount == 0 ) // convert the reverse iterator back to iterator.
+ {
+ // actually we want to do "retit = it;".
+ retit = rDataSet.begin();
+ size_t nRPos = std::distance(rDataSet.rbegin(), it);
+ size_t nPos = rDataSet.size() - 1 - nRPos;
+ std::advance(retit, nPos);
+ }
+ ++nCount;
+ }
+ }
+ else // Forwards
+ {
+ ScTypedCaseStrSet::const_iterator it, itEnd;
+ it = itPos;
+ if ( it == rDataSet.end() )
+ it = --rDataSet.end();
+ itEnd = it;
+ bool bFirstTime = true;
+
+ while ( it != itEnd || bFirstTime )
+ {
+ ++it;
+ if ( it == rDataSet.end() ) // go to the first if reach the end
+ {
+ it = rDataSet.begin();
+ nRingOrigin = nCount;
+ }
+
+ if ( bFirstTime )
+ bFirstTime = false;
+ const ScTypedStrData& rData = *it;
+ if ( rData.GetStringType() == ScTypedStrData::Value )
+ // skip values
+ continue;
+
+ if ( !ScGlobal::GetTransliteration().isMatch(rStart, rData.GetString()) )
+ // not a match
+ continue;
+
+ rResultVec.push_back(rData.GetString()); // set the match data
+ if ( nCount == 0 )
+ retit = it; // remember first match iterator
+ ++nCount;
+ }
+ }
+
+ if (pLongestPrefixLen)
+ {
+ if (nRingOrigin >= static_cast<sal_Int32>(nCount))
+ {
+ // All matches were picked when rDataSet was read in one direction.
+ nRingOrigin = 0;
+ }
+ // rResultsVec is a sorted ring with nRingOrigin "origin".
+ // The direction of sorting is not important for getLongestCommonPrefixLength.
+ *pLongestPrefixLen = getLongestCommonPrefixLength(rResultVec, rStart, nRingOrigin);
+ }
+
+ if ( nCount > 0 ) // at least one function has matched
+ return retit;
+ return rDataSet.end(); // no matching text found
+}
+
+}
+
+void ScInputHandler::SendReferenceMarks( const SfxViewShell* pViewShell,
+ const std::vector<ReferenceMark>& rReferenceMarks )
+{
+ if ( !pViewShell )
+ return;
+
+ bool bSend = false;
+
+ std::stringstream ss;
+
+ ss << "{ \"marks\": [ ";
+
+ for ( size_t i = 0; i < rReferenceMarks.size(); i++ )
+ {
+ if ( rReferenceMarks[i].Is() )
+ {
+ if ( bSend )
+ ss << ", ";
+
+ ss << "{ \"rectangle\": \""
+ << rReferenceMarks[i].nX << ", "
+ << rReferenceMarks[i].nY << ", "
+ << rReferenceMarks[i].nWidth << ", "
+ << rReferenceMarks[i].nHeight << "\", "
+ "\"color\": \"" << rReferenceMarks[i].aColor.AsRGBHexString() << "\", "
+ "\"part\": \"" << rReferenceMarks[i].nTab << "\" } ";
+
+ bSend = true;
+ }
+ }
+
+ ss << " ] }";
+
+ OString aPayload = ss.str().c_str();
+ pViewShell->libreOfficeKitViewCallback(
+ LOK_CALLBACK_REFERENCE_MARKS, aPayload.getStr() );
+}
+
+void ScInputHandler::InitRangeFinder( const OUString& rFormula )
+{
+ DeleteRangeFinder();
+ if ( !pActiveViewSh || !SC_MOD()->GetInputOptions().GetRangeFinder() )
+ return;
+ ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const sal_Unicode cSheetSep = rDoc.GetSheetSeparator();
+
+ OUString aDelimiters = ScEditUtil::ModifyDelimiters(" !~\"");
+ // delimiters (in addition to ScEditUtil): only characters that are
+ // allowed in formulas next to references and the quotation mark (so
+ // string constants can be skipped)
+
+ sal_Int32 nColon = aDelimiters.indexOf( ':' );
+ if ( nColon != -1 )
+ aDelimiters = aDelimiters.replaceAt( nColon, 1, u""); // Delimiter without colon
+ sal_Int32 nDot = aDelimiters.indexOf(cSheetSep);
+ if ( nDot != -1 )
+ aDelimiters = aDelimiters.replaceAt( nDot, 1 , u""); // Delimiter without dot
+
+ const sal_Unicode* pChar = rFormula.getStr();
+ sal_Int32 nLen = rFormula.getLength();
+ sal_Int32 nPos = 0;
+ sal_Int32 nStart = 0;
+ sal_uInt16 nCount = 0;
+ ScRange aRange;
+ while ( nPos < nLen && nCount < RANGEFIND_MAX )
+ {
+ // Skip separator
+ while ( nPos<nLen && ScGlobal::UnicodeStrChr( aDelimiters.getStr(), pChar[nPos] ) )
+ {
+ if ( pChar[nPos] == '"' ) // String
+ {
+ ++nPos;
+ while (nPos<nLen && pChar[nPos] != '"') // Skip until end
+ ++nPos;
+ }
+ ++nPos; // Separator or closing quote
+ }
+
+ // text between separators
+ nStart = nPos;
+handle_r1c1:
+ {
+ bool bSingleQuoted = false;
+ while (nPos < nLen)
+ {
+ // tdf#114113: handle addresses with quoted sheet names like "'Sheet 1'.A1"
+ // Literal single quotes in sheet names are masked by another single quote
+ if (pChar[nPos] == '\'')
+ {
+ bSingleQuoted = !bSingleQuoted;
+ }
+ else if (!bSingleQuoted) // Get everything in single quotes, including separators
+ {
+ if (ScGlobal::UnicodeStrChr(aDelimiters.getStr(), pChar[nPos]))
+ break;
+ }
+ ++nPos;
+ }
+ }
+
+ // for R1C1 '-' in R[-]... or C[-]... are not delimiters
+ // Nothing heroic here to ensure that there are '[]' around a negative
+ // integer. we need to clean up this code.
+ if( nPos < nLen && nPos > 0 &&
+ '-' == pChar[nPos] && '[' == pChar[nPos-1] &&
+ formula::FormulaGrammar::CONV_XL_R1C1 == rDoc.GetAddressConvention() )
+ {
+ nPos++;
+ goto handle_r1c1;
+ }
+
+ if ( nPos > nStart )
+ {
+ OUString aTest = rFormula.copy( nStart, nPos-nStart );
+ const ScAddress::Details aAddrDetails( rDoc, aCursorPos );
+ ScRefFlags nFlags = aRange.ParseAny( aTest, rDoc, aAddrDetails );
+ if ( nFlags & ScRefFlags::VALID )
+ {
+ // Set tables if not specified
+ if ( (nFlags & ScRefFlags::TAB_3D) == ScRefFlags::ZERO)
+ aRange.aStart.SetTab( pActiveViewSh->GetViewData().GetTabNo() );
+ if ( (nFlags & ScRefFlags::TAB2_3D) == ScRefFlags::ZERO)
+ aRange.aEnd.SetTab( aRange.aStart.Tab() );
+
+ if ( ( nFlags & (ScRefFlags::COL2_VALID|ScRefFlags::ROW2_VALID|ScRefFlags::TAB2_VALID) ) ==
+ ScRefFlags::ZERO )
+ {
+ // #i73766# if a single ref was parsed, set the same "abs" flags for ref2,
+ // so Format doesn't output a double ref because of different flags.
+ ScRefFlags nAbsFlags = nFlags & (ScRefFlags::COL_ABS|ScRefFlags::ROW_ABS|ScRefFlags::TAB_ABS);
+ applyStartToEndFlags(nFlags, nAbsFlags);
+ }
+
+ if (!nCount)
+ {
+ mpEditEngine->SetUpdateLayout( false );
+ pRangeFindList.reset(new ScRangeFindList( pDocSh->GetTitle() ));
+ }
+
+ Color nColor = pRangeFindList->Insert( ScRangeFindData( aRange, nFlags, nStart, nPos ) );
+
+ ESelection aSel( 0, nStart, 0, nPos );
+ SfxItemSet aSet( mpEditEngine->GetEmptyItemSet() );
+ aSet.Put( SvxColorItem( nColor, EE_CHAR_COLOR ) );
+ mpEditEngine->QuickSetAttribs( aSet, aSel );
+ ++nCount;
+ }
+ }
+
+ // Do not skip last separator; could be a quote (?)
+ }
+
+ UpdateLokReferenceMarks();
+
+ if (nCount)
+ {
+ mpEditEngine->SetUpdateLayout( true );
+
+ pDocSh->Broadcast( SfxHint( SfxHintId::ScShowRangeFinder ) );
+ }
+}
+
+ReferenceMark ScInputHandler::GetReferenceMark( const ScViewData& rViewData, ScDocShell* pDocSh,
+ tools::Long nX1, tools::Long nX2, tools::Long nY1, tools::Long nY2,
+ tools::Long nTab, const Color& rColor )
+{
+ ScSplitPos eWhich = rViewData.GetActivePart();
+
+ // This method is LOK specific.
+ if (comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ {
+ SCCOL nCol1 = nX1, nCol2 = nX2;
+ SCROW nRow1 = nY1, nRow2 = nY2;
+ PutInOrder(nCol1, nCol2);
+ PutInOrder(nRow1, nRow2);
+ if (nCol1 == nCol2 && nRow1 == nRow2)
+ pDocSh->GetDocument().ExtendMerge(nCol1, nRow1, nCol2, nRow2, nTab);
+
+ Point aTopLeft = rViewData.GetPrintTwipsPos(nCol1, nRow1);
+ Point aBottomRight = rViewData.GetPrintTwipsPos(nCol2 + 1, nRow2 + 1);
+ tools::Long nSizeX = aBottomRight.X() - aTopLeft.X() - 1;
+ tools::Long nSizeY = aBottomRight.Y() - aTopLeft.Y() - 1;
+
+ return ReferenceMark(aTopLeft.X(), aTopLeft.Y(), nSizeX, nSizeY, nTab, rColor);
+ }
+
+ Point aScrPos = rViewData.GetScrPos( nX1, nY1, eWhich );
+ tools::Long nScrX = aScrPos.X();
+ tools::Long nScrY = aScrPos.Y();
+
+ double nPPTX = rViewData.GetPPTX();
+ double nPPTY = rViewData.GetPPTY();
+
+ Fraction aZoomX = rViewData.GetZoomX();
+ Fraction aZoomY = rViewData.GetZoomY();
+
+ ScTableInfo aTabInfo;
+ pDocSh->GetDocument().FillInfo( aTabInfo, nX1, nY1, nX2, nY2,
+ nTab, nPPTX, nPPTY, false, false );
+
+ ScOutputData aOutputData( nullptr, OUTTYPE_WINDOW, aTabInfo,
+ &( pDocSh->GetDocument() ), nTab,
+ nScrX, nScrY,
+ nX1, nY1, nX2, nY2,
+ nPPTX, nPPTY,
+ &aZoomX, &aZoomY );
+
+ return aOutputData.FillReferenceMark( nX1, nY1, nX2, nY2,
+ rColor );
+}
+
+void ScInputHandler::UpdateLokReferenceMarks()
+{
+ if ( !comphelper::LibreOfficeKit::isActive())
+ return;
+
+ ScTabViewShell* pShell = pActiveViewSh ? pActiveViewSh
+ : dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
+
+ if (!pShell)
+ return;
+
+ ScViewData& rViewData = pShell->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScRangeFindList* pRangeFinder = GetRangeFindList();
+
+ if ( !pRangeFinder && !rViewData.IsRefMode() )
+ return;
+
+ sal_uInt16 nAdditionalMarks = 0;
+ std::vector<ReferenceMark> aReferenceMarks( 1 );
+
+ if ( rViewData.IsRefMode() )
+ {
+ nAdditionalMarks = 1;
+
+ const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
+ Color aRefColor( rColorCfg.GetColorValue( svtools::CALCREFERENCE ).nColor );
+ tools::Long nX1 = rViewData.GetRefStartX();
+ tools::Long nX2 = rViewData.GetRefEndX();
+ tools::Long nY1 = rViewData.GetRefStartY();
+ tools::Long nY2 = rViewData.GetRefEndY();
+ tools::Long nTab = rViewData.GetRefStartZ();
+
+ if (rViewData.GetRefEndZ() == rViewData.GetTabNo())
+ nTab = rViewData.GetRefEndZ();
+
+ PutInOrder(nX1, nX2);
+ PutInOrder(nY1, nY2);
+
+ aReferenceMarks[0] = ScInputHandler::GetReferenceMark( rViewData, pDocSh,
+ nX1, nX2, nY1, nY2,
+ nTab, aRefColor );
+ }
+
+ sal_uInt16 nCount = pRangeFinder ?
+ ( static_cast<sal_uInt16>( pRangeFinder->Count() ) + nAdditionalMarks ) : nAdditionalMarks;
+ aReferenceMarks.resize( nCount );
+
+ if ( nCount && pRangeFinder && !pRangeFinder->IsHidden() &&
+ pRangeFinder->GetDocName() == pDocSh->GetTitle() )
+ {
+ for (sal_uInt16 i = 0; i < nCount - nAdditionalMarks; i++)
+ {
+ ScRangeFindData& rData = pRangeFinder->GetObject( i );
+ ScRange aRef = rData.aRef;
+ aRef.PutInOrder();
+
+ tools::Long nX1 = aRef.aStart.Col();
+ tools::Long nX2 = aRef.aEnd.Col();
+ tools::Long nY1 = aRef.aStart.Row();
+ tools::Long nY2 = aRef.aEnd.Row();
+ tools::Long nTab = aRef.aStart.Tab();
+
+ aReferenceMarks[i + nAdditionalMarks] = ScInputHandler::GetReferenceMark( rViewData, pDocSh,
+ nX1, nX2, nY1, nY2,
+ nTab, rData.nColor );
+
+ ScInputHandler::SendReferenceMarks( pShell, aReferenceMarks );
+ }
+ }
+ else if ( nCount )
+ {
+ ScInputHandler::SendReferenceMarks( pShell, aReferenceMarks );
+ }
+ else
+ {
+ // Clear
+ aReferenceMarks.clear();
+ ScInputHandler::SendReferenceMarks( pShell, aReferenceMarks );
+ }
+}
+
+void ScInputHandler::SetDocumentDisposing( bool b )
+{
+ mbDocumentDisposing = b;
+}
+
+static void lcl_Replace( EditView* pView, const OUString& rNewStr, const ESelection& rOldSel )
+{
+ if ( !pView )
+ return;
+
+ ESelection aOldSel = pView->GetSelection();
+ if (aOldSel.HasRange())
+ pView->SetSelection( ESelection( aOldSel.nEndPara, aOldSel.nEndPos,
+ aOldSel.nEndPara, aOldSel.nEndPos ) );
+
+ EditEngine* pEngine = pView->GetEditEngine();
+ pEngine->QuickInsertText( rNewStr, rOldSel );
+
+ // Dummy InsertText for Update and Paint
+ // To do that we need to cancel the selection from above (before QuickInsertText)
+ pView->InsertText( OUString() );
+
+ sal_Int32 nLen = pEngine->GetTextLen(0);
+ ESelection aSel( 0, nLen, 0, nLen );
+ pView->SetSelection( aSel ); // Set cursor to the end
+}
+
+void ScInputHandler::UpdateRange( sal_uInt16 nIndex, const ScRange& rNew )
+{
+ ScTabViewShell* pDocView = pRefViewSh ? pRefViewSh : pActiveViewSh;
+ if ( pDocView && pRangeFindList && nIndex < pRangeFindList->Count() )
+ {
+ ScRangeFindData& rData = pRangeFindList->GetObject( nIndex );
+ sal_Int32 nOldStart = rData.nSelStart;
+ sal_Int32 nOldEnd = rData.nSelEnd;
+ Color nNewColor = pRangeFindList->FindColor( rNew, nIndex );
+
+ ScRange aJustified = rNew;
+ aJustified.PutInOrder(); // Always display Ref in the Formula the right way
+ ScDocument& rDoc = pDocView->GetViewData().GetDocument();
+ const ScAddress::Details aAddrDetails( rDoc, aCursorPos );
+ OUString aNewStr(aJustified.Format(rDoc, rData.nFlags, aAddrDetails));
+ ESelection aOldSel( 0, nOldStart, 0, nOldEnd );
+ SfxItemSet aSet( mpEditEngine->GetEmptyItemSet() );
+
+ DataChanging();
+
+ lcl_Replace( pTopView, aNewStr, aOldSel );
+ lcl_Replace( pTableView, aNewStr, aOldSel );
+ aSet.Put( SvxColorItem( nNewColor, EE_CHAR_COLOR ) );
+ mpEditEngine->QuickSetAttribs( aSet, aOldSel );
+
+ bInRangeUpdate = true;
+ DataChanged();
+ bInRangeUpdate = false;
+
+ tools::Long nDiff = aNewStr.getLength() - static_cast<tools::Long>(nOldEnd-nOldStart);
+
+ rData.aRef = rNew;
+ rData.nSelEnd = rData.nSelEnd + nDiff;
+ rData.nColor = nNewColor;
+
+ sal_uInt16 nCount = static_cast<sal_uInt16>(pRangeFindList->Count());
+ for (sal_uInt16 i=nIndex+1; i<nCount; i++)
+ {
+ ScRangeFindData& rNext = pRangeFindList->GetObject( i );
+ rNext.nSelStart = rNext.nSelStart + nDiff;
+ rNext.nSelEnd = rNext.nSelEnd + nDiff;
+ }
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ pActiveView->ShowCursor( false );
+ }
+ else
+ {
+ OSL_FAIL("UpdateRange: we're missing something");
+ }
+}
+
+void ScInputHandler::DeleteRangeFinder()
+{
+ ScTabViewShell* pPaintView = pRefViewSh ? pRefViewSh : pActiveViewSh;
+ if ( pRangeFindList && pPaintView )
+ {
+ ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
+ pRangeFindList->SetHidden(true);
+ pDocSh->Broadcast( SfxHint( SfxHintId::ScShowRangeFinder ) ); // Steal
+ pRangeFindList.reset();
+ }
+}
+
+static OUString GetEditText(const EditEngine* pEng)
+{
+ return ScEditUtil::GetMultilineString(*pEng);
+}
+
+static void lcl_RemoveTabs(OUString& rStr)
+{
+ rStr = rStr.replace('\t', ' ');
+}
+
+static void lcl_RemoveLineEnd(OUString& rStr)
+{
+ rStr = convertLineEnd(rStr, LINEEND_LF);
+ rStr = rStr.replace('\n', ' ');
+}
+
+static sal_Int32 lcl_MatchParenthesis( const OUString& rStr, sal_Int32 nPos )
+{
+ int nDir;
+ sal_Unicode c1, c2 = 0;
+ c1 = rStr[nPos];
+ switch ( c1 )
+ {
+ case '(' :
+ c2 = ')';
+ nDir = 1;
+ break;
+ case ')' :
+ c2 = '(';
+ nDir = -1;
+ break;
+ case '<' :
+ c2 = '>';
+ nDir = 1;
+ break;
+ case '>' :
+ c2 = '<';
+ nDir = -1;
+ break;
+ case '{' :
+ c2 = '}';
+ nDir = 1;
+ break;
+ case '}' :
+ c2 = '{';
+ nDir = -1;
+ break;
+ case '[' :
+ c2 = ']';
+ nDir = 1;
+ break;
+ case ']' :
+ c2 = '[';
+ nDir = -1;
+ break;
+ default:
+ nDir = 0;
+ }
+ if ( !nDir )
+ return -1;
+ sal_Int32 nLen = rStr.getLength();
+ const sal_Unicode* p0 = rStr.getStr();
+ const sal_Unicode* p;
+ const sal_Unicode* p1;
+ sal_uInt16 nQuotes = 0;
+ if ( nPos < nLen / 2 )
+ {
+ p = p0;
+ p1 = p0 + nPos;
+ }
+ else
+ {
+ p = p0 + nPos;
+ p1 = p0 + nLen;
+ }
+ while ( p < p1 )
+ {
+ if ( *p++ == '\"' )
+ nQuotes++;
+ }
+ // Odd number of quotes that we find ourselves in a string
+ bool bLookInString = ((nQuotes % 2) != 0);
+ bool bInString = bLookInString;
+ p = p0 + nPos;
+ p1 = (nDir < 0 ? p0 : p0 + nLen) ;
+ sal_uInt16 nLevel = 1;
+ while ( p != p1 && nLevel )
+ {
+ p += nDir;
+ if ( *p == '\"' )
+ {
+ bInString = !bInString;
+ if ( bLookInString && !bInString )
+ p = p1; // That's it then
+ }
+ else if ( bInString == bLookInString )
+ {
+ if ( *p == c1 )
+ nLevel++;
+ else if ( *p == c2 )
+ nLevel--;
+ }
+ }
+ if ( nLevel )
+ return -1;
+ return static_cast<sal_Int32>(p - p0);
+}
+
+ScInputHandler::ScInputHandler()
+ : pInputWin( nullptr ),
+ pTableView( nullptr ),
+ pTopView( nullptr ),
+ pTipVisibleParent( nullptr ),
+ nTipVisible( nullptr ),
+ pTipVisibleSecParent( nullptr ),
+ nTipVisibleSec( nullptr ),
+ nFormSelStart( 0 ),
+ nFormSelEnd( 0 ),
+ nCellPercentFormatDecSep( 0 ),
+ nAutoPar( 0 ),
+ eMode( SC_INPUT_NONE ),
+ bUseTab( false ),
+ bTextValid( true ),
+ bModified( false ),
+ bSelIsRef( false ),
+ bFormulaMode( false ),
+ bInRangeUpdate( false ),
+ bParenthesisShown( false ),
+ bCreatingFuncView( false ),
+ bInEnterHandler( false ),
+ bCommandErrorShown( false ),
+ bInOwnChange( false ),
+ bProtected( false ),
+ bLastIsSymbol( false ),
+ mbDocumentDisposing(false),
+ mbPartialPrefix(false),
+ mbEditingExistingContent(false),
+ nValidation( 0 ),
+ eAttrAdjust( SvxCellHorJustify::Standard ),
+ aScaleX( 1,1 ),
+ aScaleY( 1,1 ),
+ pRefViewSh( nullptr ),
+ pLastPattern( nullptr )
+{
+ // The InputHandler is constructed with the view, so SfxViewShell::Current
+ // doesn't have the right view yet. pActiveViewSh is updated in NotifyChange.
+ pActiveViewSh = nullptr;
+
+ // Bindings (only still used for Invalidate) are retrieved if needed on demand
+
+ pDelayTimer.reset( new Timer( "ScInputHandlerDelay timer" ) );
+ pDelayTimer->SetTimeout( 500 ); // 500 ms delay
+ pDelayTimer->SetInvokeHandler( LINK( this, ScInputHandler, DelayTimer ) );
+}
+
+ScInputHandler::~ScInputHandler()
+{
+ // If this is the application InputHandler, the dtor is called after SfxApplication::Main,
+ // thus we can't rely on any Sfx functions
+ if (!mbDocumentDisposing) // inplace
+ EnterHandler(); // Finish input
+
+ if (SC_MOD()->GetRefInputHdl() == this)
+ SC_MOD()->SetRefInputHdl(nullptr);
+
+ if ( pInputWin && pInputWin->GetInputHandler() == this )
+ pInputWin->SetInputHandler( nullptr );
+}
+
+void ScInputHandler::SetRefScale( const Fraction& rX, const Fraction& rY )
+{
+ if ( rX != aScaleX || rY != aScaleY )
+ {
+ aScaleX = rX;
+ aScaleY = rY;
+ if (mpEditEngine)
+ {
+ MapMode aMode( MapUnit::Map100thMM, Point(), aScaleX, aScaleY );
+ mpEditEngine->SetRefMapMode( aMode );
+ }
+ }
+}
+
+void ScInputHandler::UpdateRefDevice()
+{
+ if (!mpEditEngine)
+ return;
+
+ bool bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg();
+ bool bInPlace = pActiveViewSh && pActiveViewSh->GetViewFrame()->GetFrame().IsInPlace();
+ EEControlBits nCtrl = mpEditEngine->GetControlWord();
+ if ( bTextWysiwyg || bInPlace )
+ nCtrl |= EEControlBits::FORMAT100; // EditEngine default: always format for 100%
+ else
+ nCtrl &= ~EEControlBits::FORMAT100; // when formatting for screen, use the actual MapMode
+ mpEditEngine->SetControlWord( nCtrl );
+ if ( bTextWysiwyg && pActiveViewSh )
+ mpEditEngine->SetRefDevice( pActiveViewSh->GetViewData().GetDocument().GetPrinter() );
+ else
+ mpEditEngine->SetRefDevice( nullptr );
+
+ MapMode aMode( MapUnit::Map100thMM, Point(), aScaleX, aScaleY );
+ mpEditEngine->SetRefMapMode( aMode );
+
+ // SetRefDevice(NULL) uses VirtualDevice, SetRefMapMode forces creation of a local VDev,
+ // so the DigitLanguage can be safely modified (might use an own VDev instead of NULL).
+ if ( !( bTextWysiwyg && pActiveViewSh ) )
+ {
+ mpEditEngine->GetRefDevice()->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
+ }
+}
+
+void ScInputHandler::ImplCreateEditEngine()
+{
+ if ( mpEditEngine )
+ return;
+
+ if ( pActiveViewSh )
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
+ mpEditEngine = std::make_unique<ScFieldEditEngine>(&rDoc, rDoc.GetEnginePool(), rDoc.GetEditPool());
+ }
+ else
+ mpEditEngine = std::make_unique<ScFieldEditEngine>(nullptr, EditEngine::CreatePool().get(), nullptr, true);
+
+ mpEditEngine->SetWordDelimiters( ScEditUtil::ModifyDelimiters( mpEditEngine->GetWordDelimiters() ) );
+ UpdateRefDevice(); // also sets MapMode
+ mpEditEngine->SetPaperSize( Size( 1000000, 1000000 ) );
+ pEditDefaults.reset( new SfxItemSet( mpEditEngine->GetEmptyItemSet() ) );
+
+ mpEditEngine->SetControlWord( mpEditEngine->GetControlWord() | EEControlBits::AUTOCORRECT );
+ mpEditEngine->SetReplaceLeadingSingleQuotationMark( false );
+ mpEditEngine->SetModifyHdl( LINK( this, ScInputHandler, ModifyHdl ) );
+}
+
+void ScInputHandler::UpdateAutoCorrFlag()
+{
+ EEControlBits nCntrl = mpEditEngine->GetControlWord();
+ EEControlBits nOld = nCntrl;
+
+ // Don't use pLastPattern here (may be invalid because of AutoStyle)
+ bool bDisable = bLastIsSymbol || bFormulaMode;
+ if ( bDisable )
+ nCntrl &= ~EEControlBits::AUTOCORRECT;
+ else
+ nCntrl |= EEControlBits::AUTOCORRECT;
+
+ if ( nCntrl != nOld )
+ mpEditEngine->SetControlWord(nCntrl);
+}
+
+void ScInputHandler::UpdateSpellSettings( bool bFromStartTab )
+{
+ if ( !pActiveViewSh )
+ return;
+
+ ScViewData& rViewData = pActiveViewSh->GetViewData();
+ bool bOnlineSpell = rViewData.GetDocument().GetDocOptions().IsAutoSpell();
+
+ // SetDefaultLanguage is independent of the language attributes,
+ // ScGlobal::GetEditDefaultLanguage is always used.
+ // It must be set every time in case the office language was changed.
+
+ mpEditEngine->SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
+
+ // if called for changed options, update flags only if already editing
+ // if called from StartTable, always update flags
+
+ if ( bFromStartTab || eMode != SC_INPUT_NONE )
+ {
+ EEControlBits nCntrl = mpEditEngine->GetControlWord();
+ EEControlBits nOld = nCntrl;
+ if( bOnlineSpell )
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+ // No AutoCorrect for Symbol Font (EditEngine does no evaluate Default)
+ if ( pLastPattern && pLastPattern->IsSymbolFont() )
+ nCntrl &= ~EEControlBits::AUTOCORRECT;
+ else
+ nCntrl |= EEControlBits::AUTOCORRECT;
+ if ( nCntrl != nOld )
+ mpEditEngine->SetControlWord(nCntrl);
+
+ ScDocument& rDoc = rViewData.GetDocument();
+ rDoc.ApplyAsianEditSettings( *mpEditEngine );
+ mpEditEngine->SetDefaultHorizontalTextDirection(
+ rDoc.GetEditTextDirection( rViewData.GetTabNo() ) );
+ mpEditEngine->SetFirstWordCapitalization( false );
+ }
+
+ // Language is set separately, so the speller is needed only if online spelling is active
+ if ( bOnlineSpell ) {
+ css::uno::Reference<css::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() );
+ mpEditEngine->SetSpeller( xXSpellChecker1 );
+ }
+
+ bool bHyphen = pLastPattern && pLastPattern->GetItem(ATTR_HYPHENATE).GetValue();
+ if ( bHyphen ) {
+ css::uno::Reference<css::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
+ mpEditEngine->SetHyphenator( xXHyphenator );
+ }
+}
+
+// Function/Range names etc. as Tip help
+
+// The other types are defined in ScDocument::GetFormulaEntries
+void ScInputHandler::GetFormulaData()
+{
+ if ( !pActiveViewSh )
+ return;
+
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
+
+ if ( pFormulaData )
+ pFormulaData->clear();
+ else
+ {
+ pFormulaData.reset( new ScTypedCaseStrSet );
+ }
+
+ if( pFormulaDataPara )
+ pFormulaDataPara->clear();
+ else
+ pFormulaDataPara.reset( new ScTypedCaseStrSet );
+
+ const OUString aParenthesesReplacement( cParenthesesReplacement);
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ const sal_uInt32 nListCount = pFuncList->GetCount();
+ const InputHandlerFunctionNames& rFunctionNames = ScGlobal::GetInputHandlerFunctionNames();
+ *pFormulaData = rFunctionNames.maFunctionData;
+ *pFormulaDataPara = rFunctionNames.maFunctionDataPara;
+ maFormulaChar = rFunctionNames.maFunctionChar;
+
+ // Increase suggestion priority of MRU formulas
+ const ScAppOptions& rOpt = SC_MOD()->GetAppOptions();
+ const sal_uInt16 nMRUCount = rOpt.GetLRUFuncListCount();
+ const sal_uInt16* pMRUList = rOpt.GetLRUFuncList();
+ for (sal_uInt16 i = 0; i < nMRUCount; i++)
+ {
+ const sal_uInt16 nId = pMRUList[i];
+ for (sal_uInt32 j = 0; j < nListCount; j++)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction(j);
+ if (pDesc->nFIndex == nId && pDesc->mxFuncName)
+ {
+ const OUString aEntry = *pDesc->mxFuncName + aParenthesesReplacement;;
+ const ScTypedStrData aData(aEntry, 0.0, 0.0, ScTypedStrData::Standard);
+ auto it = pFormulaData->find(aData);
+ if (it != pFormulaData->end())
+ pFormulaData->erase(it);
+ pFormulaData->insert(ScTypedStrData(aEntry, 0.0, 0.0, ScTypedStrData::MRU));
+ break; // Stop searching
+ }
+ }
+ }
+ miAutoPosFormula = pFormulaData->end();
+
+ // tdf#142031 - collect all the characters for the formula suggestion auto input
+ ScTypedCaseStrSet aStrSet;
+ rDoc.GetFormulaEntries( aStrSet );
+ for (auto iter = aStrSet.begin(); iter != aStrSet.end(); ++iter)
+ {
+ const OUString aFuncName = ScGlobal::getCharClass().uppercase((*iter).GetString());
+ // fdo#75264 fill maFormulaChar with all characters used in formula names
+ for (sal_Int32 j = 0; j < aFuncName.getLength(); j++)
+ maFormulaChar.insert(aFuncName[j]);
+ }
+ pFormulaData->insert(aStrSet.begin(), aStrSet.end());
+ pFormulaDataPara->insert(aStrSet.begin(), aStrSet.end());
+}
+
+IMPL_LINK( ScInputHandler, ShowHideTipVisibleParentListener, VclWindowEvent&, rEvent, void )
+{
+ if (rEvent.GetId() == VclEventId::ObjectDying || rEvent.GetId() == VclEventId::WindowHide
+ || rEvent.GetId() == VclEventId::WindowLoseFocus || rEvent.GetId() == VclEventId::ControlLoseFocus)
+ HideTip();
+}
+
+IMPL_LINK( ScInputHandler, ShowHideTipVisibleSecParentListener, VclWindowEvent&, rEvent, void )
+{
+ if (rEvent.GetId() == VclEventId::ObjectDying || rEvent.GetId() == VclEventId::WindowHide
+ || rEvent.GetId() == VclEventId::WindowLoseFocus || rEvent.GetId() == VclEventId::ControlLoseFocus)
+ HideTipBelow();
+}
+
+void ScInputHandler::HideTip()
+{
+ if ( nTipVisible )
+ {
+ pTipVisibleParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
+ Help::HidePopover(pTipVisibleParent, nTipVisible );
+ nTipVisible = nullptr;
+ pTipVisibleParent = nullptr;
+ }
+ aManualTip.clear();
+}
+void ScInputHandler::HideTipBelow()
+{
+ if ( nTipVisibleSec )
+ {
+ pTipVisibleSecParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
+ Help::HidePopover(pTipVisibleSecParent, nTipVisibleSec);
+ nTipVisibleSec = nullptr;
+ pTipVisibleSecParent = nullptr;
+ }
+ aManualTip.clear();
+}
+
+namespace
+{
+
+bool lcl_hasSingleToken(std::u16string_view s, sal_Unicode c)
+{
+ return !s.empty() && s.find(c) == std::u16string_view::npos;
+}
+
+}
+
+void ScInputHandler::ShowArgumentsTip( OUString& rSelText )
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ return;
+ }
+
+ ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ const sal_Unicode cSheetSep = pDocSh->GetDocument().GetSheetSeparator();
+ FormulaHelper aHelper(ScGlobal::GetStarCalcFunctionMgr());
+ bool bFound = false;
+ while( !bFound )
+ {
+ rSelText += ")";
+ sal_Int32 nLeftParentPos = lcl_MatchParenthesis( rSelText, rSelText.getLength()-1 );
+ if( nLeftParentPos != -1 )
+ {
+ sal_Int32 nNextFStart = aHelper.GetFunctionStart( rSelText, nLeftParentPos, true);
+ const IFunctionDescription* ppFDesc;
+ ::std::vector< OUString> aArgs;
+ if( aHelper.GetNextFunc( rSelText, false, nNextFStart, nullptr, &ppFDesc, &aArgs ) )
+ {
+ if( !ppFDesc->getFunctionName().isEmpty() )
+ {
+ sal_Int32 nArgPos = aHelper.GetArgStart( rSelText, nNextFStart, 0 );
+ sal_uInt16 nArgs = static_cast<sal_uInt16>(ppFDesc->getParameterCount());
+ OUString aFuncName( ppFDesc->getFunctionName() + "(");
+ OUString aNew;
+ ScTypedCaseStrSet::const_iterator it =
+ findText(*pFormulaDataPara, pFormulaDataPara->end(), aFuncName, aNew, false);
+ if (it != pFormulaDataPara->end())
+ {
+ bool bFlag = false;
+ sal_uInt16 nActive = 0;
+ for( sal_uInt16 i=0; i < nArgs; i++ )
+ {
+ sal_Int32 nLength = aArgs[i].getLength();
+ if( nArgPos <= rSelText.getLength()-1 )
+ {
+ nActive = i+1;
+ bFlag = true;
+ }
+ nArgPos+=nLength+1;
+ }
+ if( bFlag )
+ {
+ sal_Int32 nStartPosition = 0;
+ sal_Int32 nEndPosition = 0;
+
+ if( lcl_hasSingleToken(aNew, cSep) )
+ {
+ for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
+ {
+ sal_Unicode cNext = aNew[i];
+ if( cNext == '(' )
+ {
+ nStartPosition = i+1;
+ }
+ }
+ }
+ else if( lcl_hasSingleToken(aNew, cSheetSep) )
+ {
+ sal_uInt16 nCount = 0;
+ for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
+ {
+ sal_Unicode cNext = aNew[i];
+ if( cNext == '(' )
+ {
+ nStartPosition = i+1;
+ }
+ else if( cNext == cSep )
+ {
+ nCount ++;
+ nEndPosition = i;
+ if( nCount == nActive )
+ {
+ break;
+ }
+ nStartPosition = nEndPosition+1;
+ }
+ }
+ }
+ else
+ {
+ sal_uInt16 nCount = 0;
+ for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
+ {
+ sal_Unicode cNext = aNew[i];
+ if( cNext == '(' )
+ {
+ nStartPosition = i+1;
+ }
+ else if( cNext == cSep )
+ {
+ nCount ++;
+ nEndPosition = i;
+ if( nCount == nActive )
+ {
+ break;
+ }
+ nStartPosition = nEndPosition+1;
+ }
+ else if( cNext == cSheetSep )
+ {
+ continue;
+ }
+ }
+ }
+
+ if (nStartPosition > 0)
+ {
+ nArgs = ppFDesc->getParameterCount();
+ sal_Int16 nVarArgsSet = 0;
+ if ( nArgs >= PAIRED_VAR_ARGS )
+ {
+ nVarArgsSet = 2;
+ nArgs -= PAIRED_VAR_ARGS - nVarArgsSet;
+ }
+ else if ( nArgs >= VAR_ARGS )
+ {
+ nVarArgsSet = 1;
+ nArgs -= VAR_ARGS - nVarArgsSet;
+ }
+ if ( nVarArgsSet > 0 && nActive > nArgs )
+ nActive = nArgs - (nActive - nArgs) % nVarArgsSet;
+ aNew = OUString::Concat(aNew.subView(0, nStartPosition)) +
+ u"\x25BA" +
+ aNew.subView(nStartPosition) +
+ " : " +
+ ppFDesc->getParameterDescription(nActive-1);
+ if (eMode != SC_INPUT_TOP)
+ {
+ ShowTipBelow( aNew );
+ }
+ else
+ {
+ ShowTip(aNew);
+ }
+ bFound = true;
+ }
+ }
+ else
+ {
+ ShowTipBelow( aNew );
+ bFound = true;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+void ScInputHandler::ShowTipCursor()
+{
+ HideTip();
+ HideTipBelow();
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+
+ /* TODO: MLFORMULA: this should work also with multi-line formulas. */
+ if ( !(bFormulaMode && pActiveView && pFormulaDataPara && mpEditEngine->GetParagraphCount() == 1) )
+ return;
+
+ OUString aParagraph = mpEditEngine->GetText( 0 );
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+
+ if ( aParagraph.getLength() < aSel.nEndPos )
+ return;
+
+ if ( aSel.nEndPos > 0 )
+ {
+ OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
+
+ ShowArgumentsTip( aSelText );
+ }
+}
+
+void ScInputHandler::ShowTip( const OUString& rText )
+{
+ // aManualTip needs to be set afterwards from outside
+
+ HideTip();
+ HideTipBelow();
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if (!pActiveView)
+ return;
+
+ Point aPos;
+ if (pInputWin && pInputWin->GetEditView() == pActiveView)
+ {
+ pTipVisibleParent = pInputWin->GetEditWindow();
+ aPos = pInputWin->GetCursorScreenPixelPos();
+ }
+ else
+ {
+ pTipVisibleParent = pActiveView->GetWindow();
+ if (vcl::Cursor* pCur = pActiveView->GetCursor())
+ aPos = pTipVisibleParent->LogicToPixel( pCur->GetPos() );
+ aPos = pTipVisibleParent->OutputToScreenPixel( aPos );
+ }
+
+ tools::Rectangle aRect( aPos, aPos );
+ QuickHelpFlags const nAlign = QuickHelpFlags::Left|QuickHelpFlags::Bottom;
+ nTipVisible = Help::ShowPopover(pTipVisibleParent, aRect, rText, nAlign);
+ pTipVisibleParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
+}
+
+void ScInputHandler::ShowTipBelow( const OUString& rText )
+{
+ HideTipBelow();
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if ( !pActiveView )
+ return;
+
+ Point aPos;
+ if (pInputWin && pInputWin->GetEditView() == pActiveView)
+ {
+ pTipVisibleSecParent = pInputWin->GetEditWindow();
+ aPos = pInputWin->GetCursorScreenPixelPos(true);
+ }
+ else
+ {
+ pTipVisibleSecParent = pActiveView->GetWindow();
+ if (vcl::Cursor* pCur = pActiveView->GetCursor())
+ {
+ Point aLogicPos = pCur->GetPos();
+ aLogicPos.AdjustY(pCur->GetHeight() );
+ aPos = pTipVisibleSecParent->LogicToPixel( aLogicPos );
+ }
+ aPos = pTipVisibleSecParent->OutputToScreenPixel( aPos );
+ }
+
+ tools::Rectangle aRect( aPos, aPos );
+ QuickHelpFlags const nAlign = QuickHelpFlags::Left | QuickHelpFlags::Top | QuickHelpFlags::NoEvadePointer;
+ nTipVisibleSec = Help::ShowPopover(pTipVisibleSecParent, aRect, rText, nAlign);
+ pTipVisibleSecParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
+}
+
+bool ScInputHandler::GetFuncName( OUString& aStart, OUString& aResult )
+{
+ if ( aStart.isEmpty() )
+ return false;
+
+ aStart = ScGlobal::getCharClass().uppercase( aStart );
+ sal_Int32 nPos = aStart.getLength() - 1;
+ sal_Unicode c = aStart[ nPos ];
+ // fdo#75264 use maFormulaChar to check if characters are used in function names
+ ::std::set< sal_Unicode >::const_iterator p = maFormulaChar.find( c );
+ if ( p == maFormulaChar.end() )
+ return false; // last character is not part of any function name, quit
+
+ ::std::vector<sal_Unicode> aTemp { c };
+ for(sal_Int32 i = nPos - 1; i >= 0; --i)
+ {
+ c = aStart[ i ];
+ p = maFormulaChar.find( c );
+
+ if (p == maFormulaChar.end())
+ break;
+
+ aTemp.push_back( c );
+ }
+
+ ::std::vector<sal_Unicode>::reverse_iterator rIt = aTemp.rbegin();
+ aResult = OUString( *rIt++ );
+ while ( rIt != aTemp.rend() )
+ aResult += OUStringChar( *rIt++ );
+
+ return true;
+}
+
+namespace {
+ /// Rid ourselves of unwanted " quoted json characters.
+ OString escapeJSON(const OUString &aStr)
+ {
+ OUString aEscaped = aStr;
+ aEscaped = aEscaped.replaceAll("\n", " ");
+ aEscaped = aEscaped.replaceAll("\"", "'");
+ return OUStringToOString(aEscaped, RTL_TEXTENCODING_UTF8);
+ }
+}
+
+void ScInputHandler::ShowFuncList( const ::std::vector< OUString > & rFuncStrVec )
+{
+ const SfxViewShell* pViewShell = SfxViewShell::Current();
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (rFuncStrVec.size() && pViewShell && pViewShell->isLOKMobilePhone())
+ {
+ auto aPos = pFormulaData->begin();
+ sal_uInt32 nCurIndex = std::distance(aPos, miAutoPosFormula);
+ const sal_uInt32 nSize = pFormulaData->size();
+
+ OUString aFuncNameStr;
+ OUString aDescFuncNameStr;
+ OStringBuffer aPayload;
+ aPayload.append("[ ");
+ for (const OUString& rFunc : rFuncStrVec)
+ {
+ if ( rFunc[rFunc.getLength()-1] == cParenthesesReplacement )
+ {
+ aFuncNameStr = rFunc.copy(0, rFunc.getLength()-1);
+ }
+ else
+ {
+ aFuncNameStr = rFunc;
+ }
+
+ FormulaHelper aHelper(ScGlobal::GetStarCalcFunctionMgr());
+ aDescFuncNameStr = aFuncNameStr + "()";
+ sal_Int32 nNextFStart = 0;
+ const IFunctionDescription* ppFDesc;
+ ::std::vector< OUString > aArgs;
+ OUString eqPlusFuncName = "=" + aDescFuncNameStr;
+ if ( aHelper.GetNextFunc( eqPlusFuncName, false, nNextFStart, nullptr, &ppFDesc, &aArgs ) )
+ {
+ if ( !ppFDesc->getFunctionName().isEmpty() )
+ {
+ aPayload.append("{");
+ aPayload.append("\"index\": ");
+ aPayload.append(static_cast<sal_Int64>(nCurIndex));
+ aPayload.append(", ");
+ aPayload.append("\"signature\": \"");
+ aPayload.append(escapeJSON(ppFDesc->getSignature()));
+ aPayload.append("\", ");
+ aPayload.append("\"description\": \"");
+ aPayload.append(escapeJSON(ppFDesc->getDescription()));
+ aPayload.append("\"}, ");
+ }
+ }
+ ++nCurIndex;
+ if (nCurIndex == nSize)
+ nCurIndex = 0;
+ }
+ sal_Int32 nLen = aPayload.getLength();
+ aPayload[nLen - 2] = ' ';
+ aPayload[nLen - 1] = ']';
+
+ OString s = aPayload.makeStringAndClear();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CALC_FUNCTION_LIST, s.getStr());
+ }
+ // not tunnel tooltips in the lok case
+ return;
+ }
+
+ OUStringBuffer aTipStr;
+ OUString aFuncNameStr;
+ OUString aDescFuncNameStr;
+ ::std::vector<OUString>::const_iterator itStr = rFuncStrVec.begin();
+ sal_Int32 nMaxFindNumber = 3;
+ sal_Int32 nRemainFindNumber = nMaxFindNumber;
+ for ( ; itStr != rFuncStrVec.end(); ++itStr )
+ {
+ const OUString& rFunc = *itStr;
+ if ( rFunc[rFunc.getLength()-1] == cParenthesesReplacement )
+ {
+ aFuncNameStr = rFunc.copy(0, rFunc.getLength()-1);
+ }
+ else
+ {
+ aFuncNameStr = rFunc;
+ }
+ if ( itStr == rFuncStrVec.begin() )
+ {
+ aTipStr = "[";
+ aDescFuncNameStr = aFuncNameStr + "()";
+ }
+ else
+ {
+ aTipStr.append(", ");
+ }
+ aTipStr.append(aFuncNameStr);
+ if ( itStr == rFuncStrVec.begin() )
+ aTipStr.append("]");
+ if ( --nRemainFindNumber <= 0 )
+ break;
+ }
+ sal_Int32 nRemainNumber = rFuncStrVec.size() - nMaxFindNumber;
+ if ( nRemainFindNumber == 0 && nRemainNumber > 0 )
+ {
+ OUString aMessage( ScResId( STR_FUNCTIONS_FOUND ) );
+ aMessage = aMessage.replaceFirst("%2", OUString::number(nRemainNumber));
+ aMessage = aMessage.replaceFirst("%1", aTipStr);
+ aTipStr = aMessage;
+ }
+ FormulaHelper aHelper(ScGlobal::GetStarCalcFunctionMgr());
+ sal_Int32 nNextFStart = 0;
+ const IFunctionDescription* ppFDesc;
+ ::std::vector< OUString > aArgs;
+ OUString eqPlusFuncName = "=" + aDescFuncNameStr;
+ if ( aHelper.GetNextFunc( eqPlusFuncName, false, nNextFStart, nullptr, &ppFDesc, &aArgs ) )
+ {
+ if ( !ppFDesc->getFunctionName().isEmpty() )
+ {
+ aTipStr.append(" : " + ppFDesc->getDescription());
+ }
+ }
+ ShowTip( aTipStr.makeStringAndClear() );
+}
+
+void ScInputHandler::UseFormulaData()
+{
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+
+ /* TODO: MLFORMULA: this should work also with multi-line formulas. */
+ if ( !(pActiveView && pFormulaData && mpEditEngine->GetParagraphCount() == 1) )
+ return;
+
+ OUString aParagraph = mpEditEngine->GetText( 0 );
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+
+ // Due to differences between table and input cell (e.g clipboard with line breaks),
+ // the selection may not be in line with the EditEngine anymore.
+ // Just return without any indication as to why.
+ if ( aSel.nEndPos > aParagraph.getLength() )
+ return;
+
+ if ( aParagraph.getLength() > aSel.nEndPos &&
+ ( ScGlobal::getCharClass().isLetterNumeric( aParagraph, aSel.nEndPos ) ||
+ aParagraph[ aSel.nEndPos ] == '_' ||
+ aParagraph[ aSel.nEndPos ] == '.' ||
+ aParagraph[ aSel.nEndPos ] == '$' ) )
+ return;
+
+ // Is the cursor at the end of a word?
+ if ( aSel.nEndPos <= 0 )
+ return;
+
+ OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
+
+ OUString aText;
+ if ( GetFuncName( aSelText, aText ) )
+ {
+ // function name is incomplete:
+ // show matching functions name as tip above cell
+ ::std::vector<OUString> aNewVec;
+ miAutoPosFormula = pFormulaData->end();
+ miAutoPosFormula = findTextAll(*pFormulaData, miAutoPosFormula, aText, aNewVec, false);
+ if (miAutoPosFormula != pFormulaData->end())
+ {
+ // check if partial function name is not between quotes
+ sal_Unicode cBetweenQuotes = 0;
+ for ( int n = 0; n < aSelText.getLength(); n++ )
+ {
+ if (cBetweenQuotes)
+ {
+ if (aSelText[n] == cBetweenQuotes)
+ cBetweenQuotes = 0;
+ }
+ else if ( aSelText[ n ] == '"' )
+ cBetweenQuotes = '"';
+ else if ( aSelText[ n ] == '\'' )
+ cBetweenQuotes = '\'';
+ }
+ if ( cBetweenQuotes )
+ return; // we're between quotes
+
+ ShowFuncList(aNewVec);
+ aAutoSearch = aText;
+ }
+ return;
+ }
+
+ // function name is complete:
+ // show tip below the cell with function name and arguments of function
+ ShowArgumentsTip( aSelText );
+}
+
+void ScInputHandler::NextFormulaEntry( bool bBack )
+{
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if ( pActiveView && pFormulaData )
+ {
+ ::std::vector<OUString> aNewVec;
+ ScTypedCaseStrSet::const_iterator itNew = findTextAll(*pFormulaData, miAutoPosFormula, aAutoSearch, aNewVec, bBack);
+ if (itNew != pFormulaData->end())
+ {
+ miAutoPosFormula = itNew;
+ ShowFuncList( aNewVec );
+ }
+ }
+
+ // For Tab we always call HideCursor first
+ if (pActiveView)
+ pActiveView->ShowCursor();
+}
+
+namespace {
+
+void completeFunction( EditView* pView, const OUString& rInsert, bool& rParInserted )
+{
+ if (!pView)
+ return;
+
+ ESelection aSel = pView->GetSelection();
+
+ bool bNoInitialLetter = false;
+ OUString aOld = pView->GetEditEngine()->GetText(0);
+ // in case we want just insert a function and not completing
+ if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ ESelection aSelRange = aSel;
+ --aSelRange.nStartPos;
+ --aSelRange.nEndPos;
+ pView->SetSelection(aSelRange);
+ pView->SelectCurrentWord();
+
+ if ( aOld == "=" )
+ {
+ bNoInitialLetter = true;
+ aSelRange.nStartPos = 1;
+ aSelRange.nEndPos = 1;
+ pView->SetSelection(aSelRange);
+ }
+ else if ( pView->GetSelected().startsWith("()") )
+ {
+ bNoInitialLetter = true;
+ ++aSelRange.nStartPos;
+ ++aSelRange.nEndPos;
+ pView->SetSelection(aSelRange);
+ }
+ }
+
+ if(!bNoInitialLetter)
+ {
+ const sal_Int32 nMinLen = std::max(aSel.nEndPos - aSel.nStartPos, sal_Int32(1));
+ // Since transliteration service is used to test for match, the replaced string could be
+ // longer than rInsert, so in order to find longest match before the cursor, test whole
+ // string from start to current cursor position (don't limit to length of rInsert)
+ // Disclaimer: I really don't know if a match longer than rInsert is actually possible,
+ // so the above is based on assumptions how "transliteration" might possibly work. If
+ // it's in fact impossible, an optimization would be useful to limit aSel.nStartPos to
+ // std::max(sal_Int32(0), aSel.nEndPos - rInsert.getLength()).
+ aSel.nStartPos = 0;
+ pView->SetSelection(aSel);
+ const OUString aAll = pView->GetSelected();
+ OUString aMatch;
+ for (sal_Int32 n = aAll.getLength(); n >= nMinLen && aMatch.isEmpty(); --n)
+ {
+ const OUString aTest = aAll.copy(aAll.getLength() - n); // n trailing chars
+ if (ScGlobal::GetTransliteration().isMatch(aTest, rInsert))
+ aMatch = aTest; // Found => break the loop
+ }
+
+ aSel.nStartPos = aSel.nEndPos - aMatch.getLength();
+ pView->SetSelection(aSel);
+ }
+
+ OUString aInsStr = rInsert;
+ sal_Int32 nInsLen = aInsStr.getLength();
+ bool bDoParen = ( nInsLen > 1 && aInsStr[nInsLen-2] == '('
+ && aInsStr[nInsLen-1] == ')' );
+ if ( bDoParen )
+ {
+ // Do not insert parentheses after function names if there already are some
+ // (e.g. if the function name was edited).
+ ESelection aWordSel = pView->GetSelection();
+
+ // aWordSel.EndPos points one behind string if word at end
+ if (aWordSel.nEndPos < aOld.getLength())
+ {
+ sal_Unicode cNext = aOld[aWordSel.nEndPos];
+ if ( cNext == '(' )
+ {
+ bDoParen = false;
+ aInsStr = aInsStr.copy( 0, nInsLen - 2 ); // Skip parentheses
+ }
+ }
+ }
+
+ pView->InsertText( aInsStr );
+
+ if ( bDoParen ) // Put cursor between parentheses
+ {
+ aSel = pView->GetSelection();
+ --aSel.nStartPos;
+ --aSel.nEndPos;
+ pView->SetSelection(aSel);
+
+ rParInserted = true;
+ }
+}
+
+}
+
+void ScInputHandler::PasteFunctionData()
+{
+ if (pFormulaData && miAutoPosFormula != pFormulaData->end())
+ {
+ const ScTypedStrData& rData = *miAutoPosFormula;
+ OUString aInsert = rData.GetString();
+ if (aInsert[aInsert.getLength()-1] == cParenthesesReplacement)
+ aInsert = OUString::Concat(aInsert.subView( 0, aInsert.getLength()-1)) + "()";
+ bool bParInserted = false;
+
+ DataChanging(); // Cannot be new
+ completeFunction( pTopView, aInsert, bParInserted );
+ completeFunction( pTableView, aInsert, bParInserted );
+ DataChanged();
+ ShowTipCursor();
+
+ if (bParInserted)
+ AutoParAdded();
+ }
+
+ HideTip();
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if (comphelper::LibreOfficeKit::isActive() && pTopView && pInputWin)
+ pInputWin->TextGrabFocus();
+ if (pActiveView)
+ pActiveView->ShowCursor();
+}
+
+void ScInputHandler::LOKPasteFunctionData(const OUString& rFunctionName)
+{
+ // in case we have no top view try to create it
+ if (!pTopView && pInputWin)
+ {
+ ScInputMode eCurMode = eMode;
+ SetMode(SC_INPUT_TOP);
+ if (!pTopView)
+ SetMode(eCurMode);
+ }
+
+ EditView* pEditView = pTopView ? pTopView : pTableView;
+
+ if (!pActiveViewSh || !pEditView)
+ return;
+
+ bool bEdit = false;
+ OUString aFormula;
+ const EditEngine* pEditEngine = pEditView->GetEditEngine();
+ if (pEditEngine)
+ {
+ aFormula = pEditEngine->GetText(0);
+ /* TODO: LOK: are you sure you want '+' and '-' let start formulas with
+ * function names? That was meant for "data typist" numeric keyboard
+ * input. */
+ bEdit = aFormula.getLength() > 1 && (aFormula[0] == '=' || aFormula[0] == '+' || aFormula[0] == '-');
+ }
+
+ if ( !bEdit )
+ {
+ OUString aNewFormula('=');
+ if ( aFormula.startsWith("=") )
+ aNewFormula = aFormula;
+
+ InputReplaceSelection( aNewFormula );
+ }
+
+ if (pFormulaData)
+ {
+ OUString aNew;
+ ScTypedCaseStrSet::const_iterator aPos = findText(*pFormulaData, pFormulaData->begin(), rFunctionName, aNew, /* backward = */false);
+
+ if (aPos != pFormulaData->end())
+ {
+ miAutoPosFormula = aPos;
+ PasteFunctionData();
+ }
+ }
+}
+
+void ScInputHandler::LOKSendFormulabarUpdate(const SfxViewShell* pActiveViewSh,
+ const OUString& rText,
+ const ESelection& rSelection)
+{
+ OUString aSelection =
+ OUString::number(rSelection.nStartPos) + ";" + OUString::number(rSelection.nEndPos);
+
+ std::unique_ptr<jsdialog::ActionDataMap> pData = std::make_unique<jsdialog::ActionDataMap>();
+ (*pData)["action_type"] = "setText";
+ (*pData)["text"] = rText;
+ (*pData)["selection"] = aSelection;
+
+ sal_uInt64 nCurrentShellId = reinterpret_cast<sal_uInt64>(pActiveViewSh);
+ std::string sWindowId = std::to_string(nCurrentShellId) + "formulabar";
+ jsdialog::SendAction(sWindowId, "sc_input_window", std::move(pData));
+}
+
+// Calculate selection and display as tip help
+static OUString lcl_Calculate( const OUString& rFormula, ScDocument& rDoc, const ScAddress &rPos )
+{
+ //TODO: Merge with ScFormulaDlg::CalcValue and move into Document!
+ // Quotation marks for Strings are only inserted here.
+
+ if(rFormula.isEmpty())
+ return OUString();
+
+ std::optional<ScSimpleFormulaCalculator> pCalc( std::in_place, rDoc, rPos, rFormula, false );
+
+ // FIXME: HACK! In order to not get a #REF! for ColRowNames, if a name is actually inserted as a Range
+ // into the whole Formula, but is interpreted as a single cell reference when displaying it on its own
+ bool bColRowName = pCalc->HasColRowName();
+ if ( bColRowName )
+ {
+ // ColRowName in RPN code?
+ if ( pCalc->GetCode()->GetCodeLen() <= 1 )
+ { // ==1: Single one is as a Parameter always a Range
+ // ==0: It might be one, if ...
+ OUString aBraced = "(" + rFormula + ")";
+ pCalc.emplace( rDoc, rPos, aBraced, false );
+ }
+ else
+ bColRowName = false;
+ }
+
+ FormulaError nErrCode = pCalc->GetErrCode();
+ if ( nErrCode != FormulaError::NONE )
+ return ScGlobal::GetErrorString(nErrCode);
+
+ SvNumberFormatter& aFormatter = *rDoc.GetFormatTable();
+ OUString aValue;
+ if ( pCalc->IsValue() )
+ {
+ double n = pCalc->GetValue();
+ sal_uInt32 nFormat = aFormatter.GetStandardFormat( n, 0,
+ pCalc->GetFormatType(), ScGlobal::eLnge );
+ aFormatter.GetInputLineString( n, nFormat, aValue );
+ //! display OutputString but insert InputLineString
+ }
+ else
+ {
+ OUString aStr = pCalc->GetString().getString();
+ sal_uInt32 nFormat = aFormatter.GetStandardFormat(
+ pCalc->GetFormatType(), ScGlobal::eLnge);
+ {
+ const Color* pColor;
+ aFormatter.GetOutputString( aStr, nFormat,
+ aValue, &pColor );
+ }
+
+ aValue = "\"" + aValue + "\"";
+ //! Escape quotation marks in String??
+ }
+
+ ScRange aTestRange;
+ if ( bColRowName || (aTestRange.Parse(rFormula, rDoc) & ScRefFlags::VALID) )
+ aValue += " ...";
+
+ return aValue;
+}
+
+void ScInputHandler::FormulaPreview()
+{
+ OUString aValue;
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if ( pActiveView && pActiveViewSh )
+ {
+ OUString aPart = pActiveView->GetSelected();
+ if (aPart.isEmpty())
+ aPart = mpEditEngine->GetText(0);
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
+ aValue = lcl_Calculate( aPart, rDoc, aCursorPos );
+ }
+
+ if (!aValue.isEmpty())
+ {
+ ShowTip( aValue ); // Display as QuickHelp
+ aManualTip = aValue; // Set after ShowTip
+ if (pFormulaData)
+ miAutoPosFormula = pFormulaData->end();
+ if (pColumnData)
+ miAutoPosColumn = pColumnData->end();
+ }
+}
+
+void ScInputHandler::PasteManualTip()
+{
+ // Three dots at the end -> Range reference -> do not insert
+ // FIXME: Once we have matrix constants, we can change this
+ sal_Int32 nTipLen = aManualTip.getLength();
+ sal_uInt32 const nTipLen2(sal::static_int_cast<sal_uInt32>(nTipLen));
+ if ( nTipLen && ( nTipLen < 3 || aManualTip.subView( nTipLen2-3 ) != u"..." ) )
+ {
+ DataChanging(); // Cannot be new
+
+ OUString aInsert = aManualTip;
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if (!pActiveView->HasSelection())
+ {
+ // Nothing selected -> select everything
+ sal_Int32 nOldLen = mpEditEngine->GetTextLen(0);
+ ESelection aAllSel( 0, 0, 0, nOldLen );
+ if ( pTopView )
+ pTopView->SetSelection( aAllSel );
+ if ( pTableView )
+ pTableView->SetSelection( aAllSel );
+ }
+
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+ OSL_ENSURE( !aSel.nStartPara && !aSel.nEndPara, "Too many paragraphs in Formula" );
+ if ( !aSel.nStartPos ) // Selection from the start?
+ {
+ if ( aSel.nEndPos == mpEditEngine->GetTextLen(0) )
+ {
+ // Everything selected -> skip quotation marks
+ if ( aInsert[0] == '"' )
+ aInsert = aInsert.copy(1);
+ sal_Int32 nInsLen = aInsert.getLength();
+ if ( aInsert.endsWith("\"") )
+ aInsert = aInsert.copy( 0, nInsLen-1 );
+ }
+ else if ( aSel.nEndPos )
+ {
+ // Not everything selected -> do not overwrite equality sign
+ //FIXME: Even double equality signs??
+ aSel.nStartPos = 1;
+ if ( pTopView )
+ pTopView->SetSelection( aSel );
+ if ( pTableView )
+ pTableView->SetSelection( aSel );
+ }
+ }
+ if ( pTopView )
+ pTopView->InsertText( aInsert, true );
+ if ( pTableView )
+ pTableView->InsertText( aInsert, true );
+
+ DataChanged();
+ }
+
+ HideTip();
+}
+
+void ScInputHandler::ResetAutoPar()
+{
+ nAutoPar = 0;
+}
+
+void ScInputHandler::AutoParAdded()
+{
+ ++nAutoPar; // Closing parenthesis can be overwritten
+}
+
+bool ScInputHandler::CursorAtClosingPar()
+{
+ // Test if the cursor is before a closing parenthesis
+ // Selection from SetReference has been removed before
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if ( pActiveView && !pActiveView->HasSelection() && bFormulaMode )
+ {
+ ESelection aSel = pActiveView->GetSelection();
+ sal_Int32 nPos = aSel.nStartPos;
+ OUString aFormula = mpEditEngine->GetText(0);
+ if ( nPos < aFormula.getLength() && aFormula[nPos] == ')' )
+ return true;
+ }
+ return false;
+}
+
+void ScInputHandler::SkipClosingPar()
+{
+ // this is called when a ')' is typed and the cursor is before a ')'
+ // that can be overwritten -> just set the cursor behind the ')'
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if (pActiveView)
+ {
+ ESelection aSel = pActiveView->GetSelection();
+ ++aSel.nStartPos;
+ ++aSel.nEndPos;
+
+ // this is in a formula (only one paragraph), so the selection
+ // can be used directly for the TopView
+
+ if ( pTopView )
+ pTopView->SetSelection( aSel );
+ if ( pTableView )
+ pTableView->SetSelection( aSel );
+ }
+
+ OSL_ENSURE(nAutoPar, "SkipClosingPar: count is wrong");
+ --nAutoPar;
+}
+
+// Auto input
+
+void ScInputHandler::GetColData()
+{
+ if ( !pActiveViewSh )
+ return;
+
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
+
+ if ( pColumnData )
+ pColumnData->clear();
+ else
+ pColumnData.reset( new ScTypedCaseStrSet );
+
+ std::vector<ScTypedStrData> aEntries;
+ rDoc.GetDataEntries(
+ aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(), aEntries);
+ if (!aEntries.empty())
+ pColumnData->insert(aEntries.begin(), aEntries.end());
+
+ miAutoPosColumn = pColumnData->end();
+}
+
+void ScInputHandler::UseColData() // When typing
+{
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if ( !(pActiveView && pColumnData) )
+ return;
+
+ // Only change when cursor is at the end
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+
+ sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
+ if ( aSel.nEndPara+1 != nParCnt )
+ return;
+
+ sal_Int32 nParLen = mpEditEngine->GetTextLen( aSel.nEndPara );
+ if ( aSel.nEndPos != nParLen )
+ return;
+
+ OUString aText = GetEditText(mpEditEngine.get());
+ if (aText.isEmpty())
+ return;
+
+ std::vector< OUString > aResultVec;
+ OUString aNew;
+ sal_Int32 nLongestPrefixLen = 0;
+ miAutoPosColumn = pColumnData->end();
+ mbPartialPrefix = false;
+ miAutoPosColumn = findTextAll(*pColumnData, miAutoPosColumn, aText, aResultVec, false, &nLongestPrefixLen);
+
+ if (nLongestPrefixLen <= 0 || aResultVec.empty())
+ return;
+
+ if (aResultVec.size() > 1)
+ {
+ mbPartialPrefix = true;
+ bUseTab = true; // Allow Ctrl (+ Shift + ) + TAB cycling.
+ miAutoPosColumn = pColumnData->end();
+
+ // Display the rest of longest common prefix as suggestion.
+ aNew = aResultVec[0].copy(0, nLongestPrefixLen);
+ }
+ else
+ {
+ aNew = aResultVec[0];
+ }
+
+ // Strings can contain line endings (e.g. due to dBase import),
+ // which would result in multiple paragraphs here, which is not desirable.
+ //! Then GetExactMatch doesn't work either
+ lcl_RemoveLineEnd( aNew );
+
+ // Keep paragraph, just append the rest
+ //! Exact replacement in EnterHandler !!!
+ // One Space between paragraphs:
+ sal_Int32 nEdLen = mpEditEngine->GetTextLen() + nParCnt - 1;
+ OUString aIns = aNew.copy(nEdLen);
+
+ // Selection must be "backwards", so the cursor stays behind the last
+ // typed character
+ ESelection aSelection( aSel.nEndPara, aSel.nEndPos + aIns.getLength(),
+ aSel.nEndPara, aSel.nEndPos );
+
+ // When editing in input line, apply to both edit views
+ if ( pTableView )
+ {
+ pTableView->InsertText( aIns );
+ pTableView->SetSelection( aSelection );
+ }
+ if ( pTopView )
+ {
+ pTopView->InsertText( aIns );
+ pTopView->SetSelection( aSelection );
+ }
+
+ aAutoSearch = aText; // To keep searching - nAutoPos is set
+}
+
+void ScInputHandler::NextAutoEntry( bool bBack )
+{
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if ( pActiveView && pColumnData )
+ {
+ if (!aAutoSearch.isEmpty())
+ {
+ // Is the selection still valid (could be changed via the mouse)?
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+ sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
+ if ( aSel.nEndPara+1 == nParCnt && aSel.nStartPara == aSel.nEndPara )
+ {
+ OUString aText = GetEditText(mpEditEngine.get());
+ sal_Int32 nSelLen = aSel.nEndPos - aSel.nStartPos;
+ sal_Int32 nParLen = mpEditEngine->GetTextLen( aSel.nEndPara );
+ if ( aSel.nEndPos == nParLen && aText.getLength() == aAutoSearch.getLength() + nSelLen )
+ {
+ OUString aNew;
+ ScTypedCaseStrSet::const_iterator itNew =
+ findText(*pColumnData, miAutoPosColumn, aAutoSearch, aNew, bBack);
+
+ if (itNew != pColumnData->end())
+ {
+ // match found!
+ miAutoPosColumn = itNew;
+ bInOwnChange = true; // disable ModifyHdl (reset below)
+ mbPartialPrefix = false;
+
+ lcl_RemoveLineEnd( aNew );
+ OUString aIns = aNew.copy(aAutoSearch.getLength());
+
+ // when editing in input line, apply to both edit views
+ if ( pTableView )
+ {
+ pTableView->DeleteSelected();
+ pTableView->InsertText( aIns );
+ pTableView->SetSelection( ESelection(
+ aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
+ aSel.nEndPara, aSel.nStartPos ) );
+ }
+ if ( pTopView )
+ {
+ pTopView->DeleteSelected();
+ pTopView->InsertText( aIns );
+ pTopView->SetSelection( ESelection(
+ aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
+ aSel.nEndPara, aSel.nStartPos ) );
+ }
+
+ bInOwnChange = false;
+ }
+ }
+ }
+ }
+ }
+
+ // For Tab, HideCursor was always called first
+ if (pActiveView)
+ pActiveView->ShowCursor();
+}
+
+// Highlight parentheses
+void ScInputHandler::UpdateParenthesis()
+{
+ // Find parentheses
+ //TODO: Can we disable parentheses highlighting per parentheses?
+ bool bFound = false;
+ if ( bFormulaMode && eMode != SC_INPUT_TOP )
+ {
+ if ( pTableView && !pTableView->HasSelection() ) // Selection is always at the bottom
+ {
+ ESelection aSel = pTableView->GetSelection();
+ if (aSel.nStartPos)
+ {
+ // Examine character left to the cursor
+ sal_Int32 nPos = aSel.nStartPos - 1;
+ OUString aFormula = mpEditEngine->GetText(aSel.nStartPara);
+ sal_Unicode c = aFormula[nPos];
+ if ( c == '(' || c == ')' )
+ {
+ // Note this matches only within one paragraph.
+ sal_Int32 nOther = lcl_MatchParenthesis( aFormula, nPos );
+ if ( nOther != -1 )
+ {
+ SfxItemSet aSet( mpEditEngine->GetEmptyItemSet() );
+ aSet.Put( SvxWeightItem( WEIGHT_BOLD, EE_CHAR_WEIGHT ) );
+
+ //! Distinguish if cell is already highlighted!!!!
+ if (bParenthesisShown)
+ {
+ // Remove old highlighting
+ sal_Int32 nCount = mpEditEngine->GetParagraphCount();
+ for (sal_Int32 i=0; i<nCount; i++)
+ mpEditEngine->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
+ }
+
+ ESelection aSelThis( aSel.nStartPara, nPos, aSel.nStartPara, nPos+1);
+ mpEditEngine->QuickSetAttribs( aSet, aSelThis );
+ ESelection aSelOther( aSel.nStartPara, nOther, aSel.nStartPara, nOther+1);
+ mpEditEngine->QuickSetAttribs( aSet, aSelOther );
+
+ // Dummy InsertText for Update and Paint (selection is empty)
+ pTableView->InsertText( OUString() );
+
+ bFound = true;
+ }
+ }
+ }
+
+ // mark parenthesis right of cursor if it will be overwritten (nAutoPar)
+ // with different color (COL_LIGHTBLUE) ??
+ }
+ }
+
+ // Remove old highlighting, if no new one is set
+ if ( bParenthesisShown && !bFound && pTableView )
+ {
+ sal_Int32 nCount = mpEditEngine->GetParagraphCount();
+ for (sal_Int32 i=0; i<nCount; i++)
+ pTableView->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
+ }
+
+ bParenthesisShown = bFound;
+}
+
+void ScInputHandler::ViewShellGone(const ScTabViewShell* pViewSh) // Executed synchronously!
+{
+ if ( pViewSh == pActiveViewSh )
+ {
+ pLastState.reset();
+ pLastPattern = nullptr;
+ }
+
+ if ( pViewSh == pRefViewSh )
+ {
+ //! The input from the EnterHandler does not arrive anymore
+ // We end the EditMode anyways
+ EnterHandler();
+ bFormulaMode = false;
+ pRefViewSh = nullptr;
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
+ SC_MOD()->SetRefInputHdl(nullptr);
+ if (pInputWin)
+ pInputWin->SetFormulaMode(false);
+ UpdateAutoCorrFlag();
+ }
+
+ pActiveViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+
+ if ( pActiveViewSh && pActiveViewSh == pViewSh )
+ {
+ OSL_FAIL("pActiveViewSh is gone");
+ pActiveViewSh = nullptr;
+ }
+
+ if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
+ UpdateRefDevice(); // Don't keep old document's printer as RefDevice
+}
+
+void ScInputHandler::UpdateActiveView()
+{
+ ImplCreateEditEngine();
+
+ // #i20588# Don't rely on focus to find the active edit view. Instead, the
+ // active pane at the start of editing is now stored (GetEditActivePart).
+ // GetActiveWin (the currently active pane) fails for ref input across the
+ // panes of a split view.
+
+ vcl::Window* pShellWin = pActiveViewSh ?
+ pActiveViewSh->GetWindowByPos( pActiveViewSh->GetViewData().GetEditActivePart() ) :
+ nullptr;
+
+ sal_uInt16 nCount = mpEditEngine->GetViewCount();
+ if (nCount > 0)
+ {
+ pTableView = mpEditEngine->GetView();
+ for (sal_uInt16 i=1; i<nCount; i++)
+ {
+ EditView* pThis = mpEditEngine->GetView(i);
+ vcl::Window* pWin = pThis->GetWindow();
+ if ( pWin==pShellWin )
+ pTableView = pThis;
+ }
+ }
+ else
+ pTableView = nullptr;
+
+ // setup the pTableView editeng for tiled rendering to get cursor and selections
+ if (pTableView && pActiveViewSh)
+ {
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ pTableView->RegisterViewShell(pActiveViewSh);
+ }
+ }
+
+ if (pInputWin && (eMode == SC_INPUT_TOP || eMode == SC_INPUT_TABLE))
+ {
+ // tdf#71409: Always create the edit engine instance for the input
+ // window, in order to properly manage accessibility events.
+ pTopView = pInputWin->GetEditView();
+ if (eMode != SC_INPUT_TOP)
+ pTopView = nullptr;
+ }
+ else
+ pTopView = nullptr;
+}
+
+void ScInputHandler::SetInputWindow( ScInputWindow* pNew )
+{
+ pInputWin = pNew;
+}
+
+void ScInputHandler::StopInputWinEngine( bool bAll )
+{
+ if (pInputWin && !pInputWin->isDisposed())
+ pInputWin->StopEditEngine( bAll );
+
+ pTopView = nullptr; // invalid now
+}
+
+EditView* ScInputHandler::GetActiveView()
+{
+ UpdateActiveView();
+ return pTopView ? pTopView : pTableView;
+}
+
+void ScInputHandler::ForgetLastPattern()
+{
+ pLastPattern = nullptr;
+ if ( !pLastState && pActiveViewSh )
+ pActiveViewSh->UpdateInputHandler( true ); // Get status again
+ else
+ NotifyChange( pLastState.get(), true );
+}
+
+void ScInputHandler::UpdateAdjust( sal_Unicode cTyped )
+{
+ SvxAdjust eSvxAdjust;
+ switch (eAttrAdjust)
+ {
+ case SvxCellHorJustify::Standard:
+ {
+ bool bNumber = false;
+ if (cTyped) // Restarted
+ bNumber = (cTyped>='0' && cTyped<='9'); // Only ciphers are numbers
+ else if ( pActiveViewSh )
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
+ bNumber = ( rDoc.GetCellType( aCursorPos ) == CELLTYPE_VALUE );
+ }
+ eSvxAdjust = bNumber ? SvxAdjust::Right : SvxAdjust::Left;
+ }
+ break;
+ case SvxCellHorJustify::Block:
+ eSvxAdjust = SvxAdjust::Block;
+ break;
+ case SvxCellHorJustify::Center:
+ eSvxAdjust = SvxAdjust::Center;
+ break;
+ case SvxCellHorJustify::Right:
+ eSvxAdjust = SvxAdjust::Right;
+ break;
+ default: // SvxCellHorJustify::Left
+ eSvxAdjust = SvxAdjust::Left;
+ break;
+ }
+
+ bool bAsianVertical = pLastPattern &&
+ pLastPattern->GetItem( ATTR_STACKED ).GetValue() &&
+ pLastPattern->GetItem( ATTR_VERTICAL_ASIAN ).GetValue();
+ if ( bAsianVertical )
+ {
+ // Always edit at top of cell -> LEFT when editing vertically
+ eSvxAdjust = SvxAdjust::Left;
+ }
+
+ pEditDefaults->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
+ mpEditEngine->SetDefaults( *pEditDefaults );
+
+ if ( pActiveViewSh )
+ {
+ pActiveViewSh->GetViewData().SetEditAdjust( eSvxAdjust );
+ }
+ mpEditEngine->SetVertical( bAsianVertical );
+}
+
+void ScInputHandler::RemoveAdjust()
+{
+ // Delete hard alignment attributes
+ bool bUndo = mpEditEngine->IsUndoEnabled();
+ if ( bUndo )
+ mpEditEngine->EnableUndo( false );
+
+ // Non-default paragraph attributes (e.g. from clipboard)
+ // must be turned into character attributes
+ mpEditEngine->RemoveParaAttribs();
+
+ if ( bUndo )
+ mpEditEngine->EnableUndo( true );
+
+}
+
+void ScInputHandler::RemoveRangeFinder()
+{
+ // Delete pRangeFindList and colors
+ mpEditEngine->SetUpdateLayout(false);
+ sal_Int32 nCount = mpEditEngine->GetParagraphCount(); // Could just have been inserted
+ for (sal_Int32 i=0; i<nCount; i++)
+ mpEditEngine->RemoveCharAttribs( i, EE_CHAR_COLOR );
+ mpEditEngine->SetUpdateLayout(true);
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ pActiveView->ShowCursor( false );
+
+ DeleteRangeFinder(); // Deletes the list and the labels on the table
+}
+
+bool ScInputHandler::StartTable( sal_Unicode cTyped, bool bFromCommand, bool bInputActivated,
+ ScEditEngineDefaulter* pTopEngine )
+{
+ bool bNewTable = false;
+
+ if (bModified)
+ return false;
+
+ if (pActiveViewSh)
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
+
+ if (!rDoc.ValidCol(aCursorPos.Col()))
+ return false;
+
+ ImplCreateEditEngine();
+ UpdateActiveView();
+ SyncViews();
+
+
+ const ScMarkData& rMark = pActiveViewSh->GetViewData().GetMarkData();
+ ScEditableTester aTester;
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ aTester.TestSelection( rDoc, rMark );
+ else
+ aTester.TestSelectedBlock(
+ rDoc, aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Col(), aCursorPos.Row(), rMark );
+
+ bool bStartInputMode = true;
+
+ if (!aTester.IsEditable())
+ {
+ bProtected = true;
+ // We allow read-only input mode activation regardless
+ // whether it's part of an array or not or whether explicit cell
+ // activation is requested (double-click or F2) or a click in input
+ // line.
+ bool bShowError = (!bInputActivated || !aTester.GetMessageId() || aTester.GetMessageId() != STR_PROTECTIONERR) &&
+ !pActiveViewSh->GetViewData().GetDocShell()->IsReadOnly();
+ if (bShowError)
+ {
+ eMode = SC_INPUT_NONE;
+ StopInputWinEngine( true );
+ UpdateFormulaMode();
+ if ( pActiveViewSh && ( !bFromCommand || !bCommandErrorShown ) )
+ {
+ // Prevent repeated error messages for the same cell from command events
+ // (for keyboard events, multiple messages are wanted).
+ // Set the flag before showing the error message because the command handler
+ // for the next IME command may be called when showing the dialog.
+ if ( bFromCommand )
+ bCommandErrorShown = true;
+
+ pActiveViewSh->GetActiveWin()->GrabFocus();
+ pActiveViewSh->ErrorMessage(aTester.GetMessageId());
+ }
+ bStartInputMode = false;
+ }
+ }
+
+ if (bStartInputMode)
+ {
+ // UpdateMode is enabled again in ScViewData::SetEditEngine (and not needed otherwise)
+ mpEditEngine->SetUpdateLayout( false );
+
+ // Take over attributes in EditEngine
+ const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(),
+ aCursorPos.Row(),
+ aCursorPos.Tab() );
+ if (pPattern != pLastPattern)
+ {
+ // Percent format?
+ const SfxItemSet& rAttrSet = pPattern->GetItemSet();
+
+ if ( const SfxUInt32Item* pItem = rAttrSet.GetItemIfSet( ATTR_VALUE_FORMAT ) )
+ {
+ sal_uInt32 nFormat = pItem->GetValue();
+ if (SvNumFormatType::PERCENT == rDoc.GetFormatTable()->GetType( nFormat ))
+ nCellPercentFormatDecSep = rDoc.GetFormatTable()->GetFormatDecimalSep( nFormat).toChar();
+ else
+ nCellPercentFormatDecSep = 0;
+ }
+ else
+ nCellPercentFormatDecSep = 0; // Default: no percent
+
+ // Validity specified?
+ if ( const SfxUInt32Item* pItem = rAttrSet.GetItemIfSet( ATTR_VALIDDATA ) )
+ nValidation = pItem->GetValue();
+ else
+ nValidation = 0;
+
+ // EditEngine Defaults
+ // In no case SetParaAttribs, because the EditEngine might already
+ // be filled (for Edit cells).
+ // SetParaAttribs would change the content.
+
+ //! The SetDefaults is now (since MUST/src602
+ //! EditEngine changes) implemented as a SetParaAttribs.
+ //! Any problems?
+
+ pPattern->FillEditItemSet( pEditDefaults.get() );
+ mpEditEngine->SetDefaults( *pEditDefaults );
+ pLastPattern = pPattern;
+ bLastIsSymbol = pPattern->IsSymbolFont();
+
+ // Background color must be known for automatic font color.
+ // For transparent cell background, the document background color must be used.
+
+ Color aBackCol = pPattern->GetItem( ATTR_BACKGROUND ).GetColor();
+ ScModule* pScMod = SC_MOD();
+ if ( aBackCol.IsTransparent() ||
+ Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+ aBackCol = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+ mpEditEngine->SetBackgroundColor( aBackCol );
+
+ // Adjustment
+ eAttrAdjust = pPattern->GetItem(ATTR_HOR_JUSTIFY).GetValue();
+ if ( eAttrAdjust == SvxCellHorJustify::Repeat &&
+ pPattern->GetItem(ATTR_LINEBREAK).GetValue() )
+ {
+ // #i31843# "repeat" with "line breaks" is treated as default alignment
+ eAttrAdjust = SvxCellHorJustify::Standard;
+ }
+ }
+
+ if (pTopEngine)
+ {
+ // Necessary to sync SvxAutoCorrect behavior. This has to be
+ // done before InitRangeFinder() below.
+ MergeLanguageAttributes( *pTopEngine);
+ }
+
+ // UpdateSpellSettings enables online spelling if needed
+ // -> also call if attributes are unchanged
+ UpdateSpellSettings( true ); // uses pLastPattern
+
+ // Fill EditEngine
+ OUString aStr;
+ if (bTextValid)
+ {
+ mpEditEngine->SetTextCurrentDefaults(aCurrentText);
+ aStr = aCurrentText;
+ bTextValid = false;
+ aCurrentText.clear();
+ }
+ else
+ aStr = GetEditText(mpEditEngine.get());
+
+ // cTyped!=0 is overtyping, not editing.
+ mbEditingExistingContent = !cTyped && !aStr.isEmpty();
+
+ if (aStr.startsWith("{=") && aStr.endsWith("}") ) // Matrix formula?
+ {
+ aStr = aStr.copy(1, aStr.getLength() -2);
+ mpEditEngine->SetTextCurrentDefaults(aStr);
+ if ( pInputWin )
+ pInputWin->SetTextString(aStr);
+ }
+
+ UpdateAdjust( cTyped );
+
+ if ( SC_MOD()->GetAppOptions().GetAutoComplete() )
+ GetColData();
+
+ if (!cTyped && !bCreatingFuncView && StartsLikeFormula(aStr))
+ InitRangeFinder(aStr); // Formula is being edited -> RangeFinder
+
+ bNewTable = true; // -> PostEditView Call
+ }
+ }
+
+ if (!bProtected && pInputWin)
+ pInputWin->SetOkCancelMode();
+
+ return bNewTable;
+}
+
+void ScInputHandler::MergeLanguageAttributes( ScEditEngineDefaulter& rDestEngine ) const
+{
+ const SfxItemSet& rSrcSet = mpEditEngine->GetDefaults();
+ rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE ));
+ rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE_CJK ));
+ rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE_CTL ));
+}
+
+static void lcl_SetTopSelection( EditView* pEditView, ESelection& rSel )
+{
+ OSL_ENSURE( rSel.nStartPara==0 && rSel.nEndPara==0, "SetTopSelection: Para != 0" );
+
+ EditEngine* pEngine = pEditView->GetEditEngine();
+ sal_Int32 nCount = pEngine->GetParagraphCount();
+ if (nCount > 1)
+ {
+ sal_Int32 nParLen = pEngine->GetTextLen(rSel.nStartPara);
+ while (rSel.nStartPos > nParLen && rSel.nStartPara+1 < nCount)
+ {
+ rSel.nStartPos -= nParLen + 1; // Including space from line break
+ nParLen = pEngine->GetTextLen(++rSel.nStartPara);
+ }
+
+ nParLen = pEngine->GetTextLen(rSel.nEndPara);
+ while (rSel.nEndPos > nParLen && rSel.nEndPara+1 < nCount)
+ {
+ rSel.nEndPos -= nParLen + 1; // Including space from line break
+ nParLen = pEngine->GetTextLen(++rSel.nEndPara);
+ }
+ }
+
+ ESelection aSel = pEditView->GetSelection();
+
+ if ( rSel.nStartPara != aSel.nStartPara || rSel.nEndPara != aSel.nEndPara
+ || rSel.nStartPos != aSel.nStartPos || rSel.nEndPos != aSel.nEndPos )
+ pEditView->SetSelection( rSel );
+}
+
+void ScInputHandler::SyncViews( const EditView* pSourceView )
+{
+ if (pSourceView)
+ {
+ bool bSelectionForTopView = false;
+ if (pTopView && pTopView != pSourceView)
+ bSelectionForTopView = true;
+ bool bSelectionForTableView = false;
+ if (pTableView && pTableView != pSourceView)
+ bSelectionForTableView = true;
+ if (bSelectionForTopView || bSelectionForTableView)
+ {
+ ESelection aSel(pSourceView->GetSelection());
+ if (bSelectionForTopView)
+ pTopView->SetSelection(aSel);
+ if (bSelectionForTableView)
+ lcl_SetTopSelection(pTableView, aSel);
+ }
+ }
+ // Only sync selection from topView if we are actually editing there
+ else if (pTopView && pTableView)
+ {
+ ESelection aSel(pTopView->GetSelection());
+ lcl_SetTopSelection( pTableView, aSel );
+ }
+}
+
+IMPL_LINK_NOARG(ScInputHandler, ModifyHdl, LinkParamNone*, void)
+{
+ if ( !bInOwnChange && ( eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE ) &&
+ mpEditEngine && mpEditEngine->IsUpdateLayout() && pInputWin )
+ {
+ // Update input line from ModifyHdl for changes that are not
+ // wrapped by DataChanging/DataChanged calls (like Drag&Drop)
+ OUString aText(ScEditUtil::GetMultilineString(*mpEditEngine));
+ lcl_RemoveTabs(aText);
+ pInputWin->SetTextString(aText);
+ }
+}
+
+/**
+ * @return true means new view created
+ */
+bool ScInputHandler::DataChanging( sal_Unicode cTyped, bool bFromCommand )
+{
+ if (pActiveViewSh)
+ pActiveViewSh->GetViewData().SetPasteMode( ScPasteFlags::NONE );
+ bInOwnChange = true; // disable ModifyHdl (reset in DataChanged)
+
+ if ( eMode == SC_INPUT_NONE )
+ return StartTable( cTyped, bFromCommand, false, nullptr );
+ else
+ return false;
+}
+
+void ScInputHandler::DataChanged( bool bFromTopNotify, bool bSetModified )
+{
+ ImplCreateEditEngine();
+
+ if (eMode==SC_INPUT_NONE)
+ eMode = SC_INPUT_TYPE;
+
+ if ( eMode == SC_INPUT_TOP && pTopView && !bFromTopNotify )
+ {
+ // table EditEngine is formatted below, input line needs formatting after paste
+ // #i20282# not when called from the input line's modify handler
+ pTopView->GetEditEngine()->QuickFormatDoc( true );
+
+ // #i23720# QuickFormatDoc hides the cursor, but can't show it again because it
+ // can't safely access the EditEngine's current view, so the cursor has to be
+ // shown again here.
+ pTopView->ShowCursor();
+ }
+
+ if (bSetModified)
+ bModified = true;
+ bSelIsRef = false;
+
+ if ( pRangeFindList && !bInRangeUpdate )
+ RemoveRangeFinder(); // Delete attributes and labels
+
+ UpdateParenthesis(); // Highlight parentheses anew
+
+ if (eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE)
+ {
+ OUString aText;
+ if (pInputWin)
+ aText = ScEditUtil::GetMultilineString(*mpEditEngine);
+ else
+ aText = GetEditText(mpEditEngine.get());
+ lcl_RemoveTabs(aText);
+
+ if ( pInputWin )
+ pInputWin->SetTextString( aText );
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (pActiveViewSh)
+ {
+ // TODO: deprecated?
+ pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_FORMULA, aText.toUtf8().getStr());
+ }
+ }
+ }
+
+ // If the cursor is before the end of a paragraph, parts are being pushed to
+ // the right (independently from the eMode) -> Adapt View!
+ // If the cursor is at the end, the StatusHandler of the ViewData is sufficient.
+ //
+ // First make sure the status handler is called now if the cursor
+ // is outside the visible area
+ mpEditEngine->QuickFormatDoc();
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ ESelection aSel;
+ if (pActiveView && pActiveViewSh)
+ {
+ ScViewData& rViewData = pActiveViewSh->GetViewData();
+
+ bool bNeedGrow = ( rViewData.GetEditAdjust() != SvxAdjust::Left ); // Always right-aligned
+ if (!bNeedGrow)
+ {
+ // Cursor before the end?
+ aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+ bNeedGrow = ( aSel.nEndPos != mpEditEngine->GetTextLen(aSel.nEndPara) );
+ }
+ if (!bNeedGrow)
+ {
+ bNeedGrow = rViewData.GetDocument().IsLayoutRTL( rViewData.GetTabNo() );
+ }
+ if (bNeedGrow)
+ {
+ // Adjust inplace view
+ rViewData.EditGrowY();
+ rViewData.EditGrowX();
+ }
+ }
+
+ if (comphelper::LibreOfficeKit::isActive() && pActiveViewSh && pInputWin)
+ {
+ ScInputHandler::LOKSendFormulabarUpdate(pActiveViewSh,
+ ScEditUtil::GetMultilineString(*mpEditEngine),
+ aSel);
+ }
+
+ UpdateFormulaMode();
+ bTextValid = false; // Changes only in the EditEngine
+ bInOwnChange = false;
+}
+
+bool ScInputHandler::StartsLikeFormula( std::u16string_view rStr ) const
+{
+ // For new input '+' and '-' may start the dreaded "lazy data typist"
+ // formula input, editing existing formula content can only start with '='.
+ return !rStr.empty() && (rStr[0] == '=' || (!mbEditingExistingContent && (rStr[0] == '+' || rStr[0] == '-')));
+}
+
+void ScInputHandler::UpdateFormulaMode()
+{
+ SfxApplication* pSfxApp = SfxGetpApp();
+
+ bool bIsFormula = !bProtected;
+ if (bIsFormula)
+ {
+ const OUString& rText = mpEditEngine->GetText(0);
+ bIsFormula = StartsLikeFormula(rText);
+ }
+
+ if ( bIsFormula )
+ {
+ if (!bFormulaMode)
+ {
+ bFormulaMode = true;
+ pRefViewSh = pActiveViewSh;
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
+ ScModule* pMod = SC_MOD();
+ pMod->SetRefInputHdl(this);
+ if (pInputWin)
+ pInputWin->SetFormulaMode(true);
+
+ // in LOK, we always need to perform the GetFormulaData() call so
+ // that the formula insertion works
+ if (comphelper::LibreOfficeKit::isActive() || pMod->GetAppOptions().GetAutoComplete())
+ GetFormulaData();
+
+ UpdateParenthesis();
+ UpdateAutoCorrFlag();
+ }
+ }
+ else // Deactivate
+ {
+ if (bFormulaMode)
+ {
+ ShowRefFrame();
+ bFormulaMode = false;
+ pRefViewSh = nullptr;
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
+ SC_MOD()->SetRefInputHdl(nullptr);
+ if (pInputWin)
+ pInputWin->SetFormulaMode(false);
+ UpdateAutoCorrFlag();
+ }
+ }
+}
+
+void ScInputHandler::ShowRefFrame()
+{
+ // Modifying pActiveViewSh here would interfere with the bInEnterHandler / bRepeat
+ // checks in NotifyChange, and lead to keeping the wrong value in pActiveViewSh.
+ // A local variable is used instead.
+ ScTabViewShell* pVisibleSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ if ( !(pRefViewSh && pRefViewSh != pVisibleSh) )
+ return;
+
+ bool bFound = false;
+ SfxViewFrame* pRefFrame = pRefViewSh->GetViewFrame();
+ SfxViewFrame* pOneFrame = SfxViewFrame::GetFirst();
+ while ( pOneFrame && !bFound )
+ {
+ if ( pOneFrame == pRefFrame )
+ bFound = true;
+ pOneFrame = SfxViewFrame::GetNext( *pOneFrame );
+ }
+
+ if (bFound)
+ {
+ // We count on Activate working synchronously here
+ // (pActiveViewSh is set while doing so)
+ pRefViewSh->SetActive(); // Appear and SetViewFrame
+
+ // pLastState is set correctly in the NotifyChange from the Activate
+ }
+ else
+ {
+ OSL_FAIL("ViewFrame for reference input is not here anymore");
+ }
+}
+
+void ScInputHandler::RemoveSelection()
+{
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if (!pActiveView)
+ return;
+
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.nStartPara = aSel.nEndPara;
+ aSel.nStartPos = aSel.nEndPos;
+ if (pTableView)
+ pTableView->SetSelection( aSel );
+ if (pTopView)
+ pTopView->SetSelection( aSel );
+}
+
+void ScInputHandler::InvalidateAttribs()
+{
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (!pViewFrm)
+ return;
+
+ SfxBindings& rBindings = pViewFrm->GetBindings();
+
+ rBindings.Invalidate( SID_ATTR_CHAR_FONT );
+ rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
+
+ rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
+ rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
+ rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
+ rBindings.Invalidate( SID_ATTR_CHAR_OVERLINE );
+ rBindings.Invalidate( SID_ULINE_VAL_NONE );
+ rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
+ rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
+ rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
+
+ rBindings.Invalidate( SID_HYPERLINK_GETLINK );
+
+ rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
+ rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
+ rBindings.Invalidate( SID_SET_SUB_SCRIPT );
+ rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
+ rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
+
+ rBindings.Invalidate( SID_SAVEDOC );
+ rBindings.Invalidate( SID_DOC_MODIFIED );
+}
+
+// --------------- public methods --------------------------------------------
+
+void ScInputHandler::SetMode( ScInputMode eNewMode, const OUString* pInitText, ScEditEngineDefaulter* pTopEngine )
+{
+ if ( eMode == eNewMode )
+ return;
+
+ ImplCreateEditEngine();
+
+ if (bProtected)
+ {
+ eMode = SC_INPUT_NONE;
+ StopInputWinEngine( true );
+ if (pActiveViewSh)
+ pActiveViewSh->GetActiveWin()->GrabFocus();
+ return;
+ }
+
+ if (eNewMode != SC_INPUT_NONE && pActiveViewSh)
+ // Disable paste mode when edit mode starts.
+ pActiveViewSh->GetViewData().SetPasteMode( ScPasteFlags::NONE );
+
+ bInOwnChange = true; // disable ModifyHdl (reset below)
+
+ ScInputMode eOldMode = eMode;
+ eMode = eNewMode;
+ if (eOldMode == SC_INPUT_TOP && eNewMode != eOldMode)
+ StopInputWinEngine( false );
+
+ if (eMode==SC_INPUT_TOP || eMode==SC_INPUT_TABLE)
+ {
+ if (eOldMode == SC_INPUT_NONE) // not if switching between modes
+ {
+ if (StartTable(0, false, eMode == SC_INPUT_TABLE, pTopEngine))
+ {
+ if (pActiveViewSh)
+ pActiveViewSh->GetViewData().GetDocShell()->PostEditView( mpEditEngine.get(), aCursorPos );
+ }
+ }
+
+ if (pInitText)
+ {
+ mpEditEngine->SetTextCurrentDefaults(*pInitText);
+ bModified = true;
+ }
+
+ sal_Int32 nPara = mpEditEngine->GetParagraphCount()-1;
+ sal_Int32 nLen = mpEditEngine->GetText(nPara).getLength();
+ sal_uInt16 nCount = mpEditEngine->GetViewCount();
+
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ if ( eMode == SC_INPUT_TABLE && eOldMode == SC_INPUT_TOP )
+ {
+ // Keep Selection
+ }
+ else
+ {
+ mpEditEngine->GetView(i)->
+ SetSelection( ESelection( nPara, nLen, nPara, nLen ) );
+ }
+ mpEditEngine->GetView(i)->ShowCursor(false);
+ }
+ }
+
+ UpdateActiveView();
+ if (eMode==SC_INPUT_TABLE || eMode==SC_INPUT_TYPE)
+ {
+ if (pTableView)
+ pTableView->SetEditEngineUpdateLayout(true);
+ }
+ else
+ {
+ if (pTopView)
+ pTopView->SetEditEngineUpdateLayout(true);
+ }
+
+ if (eNewMode != eOldMode)
+ UpdateFormulaMode();
+
+ bInOwnChange = false;
+}
+
+/**
+ * @return true if rString only contains digits (no autocorrect then)
+ */
+static bool lcl_IsNumber(const OUString& rString)
+{
+ sal_Int32 nLen = rString.getLength();
+ for (sal_Int32 i=0; i<nLen; i++)
+ {
+ sal_Unicode c = rString[i];
+ if ( c < '0' || c > '9' )
+ return false;
+ }
+ return true;
+}
+
+static void lcl_SelectionToEnd( EditView* pView )
+{
+ if ( pView )
+ {
+ EditEngine* pEngine = pView->GetEditEngine();
+ sal_Int32 nParCnt = pEngine->GetParagraphCount();
+ if ( nParCnt == 0 )
+ nParCnt = 1;
+ ESelection aSel( nParCnt-1, pEngine->GetTextLen(nParCnt-1) ); // empty selection, cursor at the end
+ pView->SetSelection( aSel );
+ }
+}
+
+void ScInputHandler::EnterHandler( ScEnterMode nBlockMode, bool bBeforeSavingInLOK )
+{
+ if (!mbDocumentDisposing && comphelper::LibreOfficeKit::isActive()
+ && pActiveViewSh != SfxViewShell::Current())
+ return;
+
+ // Macro calls for validity can cause a lot of problems, so inhibit
+ // nested calls of EnterHandler().
+ if (bInEnterHandler) return;
+ bInEnterHandler = true;
+ bInOwnChange = true; // disable ModifyHdl (reset below)
+ mbPartialPrefix = false;
+
+ ImplCreateEditEngine();
+
+ bool bMatrix = ( nBlockMode == ScEnterMode::MATRIX );
+
+ SfxApplication* pSfxApp = SfxGetpApp();
+ std::unique_ptr<EditTextObject> pObject;
+ std::unique_ptr<ScPatternAttr> pCellAttrs;
+ bool bForget = false; // Remove due to validity?
+
+ OUString aString = GetEditText(mpEditEngine.get());
+ OUString aPreAutoCorrectString(aString);
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if (bModified && pActiveView && !aString.isEmpty() && !lcl_IsNumber(aString))
+ {
+ if (pColumnData && miAutoPosColumn != pColumnData->end())
+ {
+ // #i47125# If AutoInput appended something, do the final AutoCorrect
+ // with the cursor at the end of the input.
+ lcl_SelectionToEnd(pTopView);
+ lcl_SelectionToEnd(pTableView);
+ }
+
+ vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : nullptr;
+
+ if (pTopView)
+ pTopView->CompleteAutoCorrect(); // CompleteAutoCorrect for both Views
+ if (pTableView)
+ pTableView->CompleteAutoCorrect(pFrameWin);
+ aString = GetEditText(mpEditEngine.get());
+ }
+ lcl_RemoveTabs(aString);
+ lcl_RemoveTabs(aPreAutoCorrectString);
+
+ // Test if valid (always with simple string)
+ if (bModified && nValidation && pActiveViewSh)
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocument();
+ const ScValidationData* pData = rDoc.GetValidationEntry( nValidation );
+ if (pData && pData->HasErrMsg())
+ {
+ // #i67990# don't use pLastPattern in EnterHandler
+ const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
+
+ bool bOk;
+
+ if (pData->GetDataMode() == SC_VALID_CUSTOM)
+ {
+ bOk = pData->IsDataValidCustom( aString, *pPattern, aCursorPos, ScValidationData::CustomValidationPrivateAccess() );
+ }
+ else
+ {
+ bOk = pData->IsDataValid( aString, *pPattern, aCursorPos );
+ }
+
+ if (!bOk)
+ {
+ pActiveViewSh->StopMarking(); // (the InfoBox consumes the MouseButtonUp)
+
+ // tdf#125917 Release the grab that a current mouse-down event being handled
+ // by ScTabView has put on the mouse via its SelectionEngine.
+ // Otherwise the warning box cannot interact with the mouse
+ if (ScTabView* pView = pActiveViewSh->GetViewData().GetView())
+ {
+ if (ScViewSelectionEngine* pSelEngine = pView->GetSelEngine())
+ pSelEngine->ReleaseMouse();
+ }
+
+ if (bBeforeSavingInLOK)
+ {
+ // Invalid entry but not applied to the document model.
+ // Exit to complete the "save", leaving the edit view as it is
+ // for the user to continue after save.
+ bInOwnChange = false;
+ bInEnterHandler = false;
+ return;
+ }
+
+ if (pData->DoError(pActiveViewSh->GetFrameWeld(), aString, aCursorPos))
+ bForget = true; // Do not take over input
+ }
+ }
+ }
+
+ // Check for input into DataPilot table
+ if ( bModified && pActiveViewSh && !bForget )
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocument();
+ ScDPObject* pDPObj = rDoc.GetDPAtCursor( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
+ if ( pDPObj )
+ {
+ // Any input within the DataPilot table is either a valid renaming
+ // or an invalid action - normal cell input is always aborted
+ pActiveViewSh->DataPilotInput( aCursorPos, aString );
+ bForget = true;
+ }
+ }
+
+ std::vector<editeng::MisspellRanges> aMisspellRanges;
+ // UpdateLayout must be true during CompleteOnlineSpelling
+ const bool bUpdateLayout = mpEditEngine->SetUpdateLayout( true );
+ mpEditEngine->CompleteOnlineSpelling();
+ bool bSpellErrors = !bFormulaMode && mpEditEngine->HasOnlineSpellErrors();
+ if ( bSpellErrors )
+ {
+ // #i3820# If the spell checker flags numerical input as error,
+ // it still has to be treated as number, not EditEngine object.
+ if ( pActiveViewSh )
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocument();
+ // #i67990# don't use pLastPattern in EnterHandler
+ const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
+ if (pPattern)
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ // without conditional format, as in ScColumn::SetString
+ sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
+ double nVal;
+ if ( pFormatter->IsNumberFormat( aString, nFormat, nVal ) )
+ {
+ bSpellErrors = false; // ignore the spelling errors
+ }
+ }
+ }
+ }
+
+ // After RemoveAdjust, the EditView must not be repainted (has wrong font size etc).
+ // SetUpdateLayout must come after CompleteOnlineSpelling.
+ // The view is hidden in any case below (Broadcast).
+ mpEditEngine->SetUpdateLayout( false );
+
+ if ( bModified && !bForget ) // What is being entered (text/object)?
+ {
+ sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
+ if ( nParCnt == 0 )
+ nParCnt = 1;
+
+ bool bUniformAttribs = true;
+ SfxItemSet aPara1Attribs = mpEditEngine->GetAttribs(0, 0, mpEditEngine->GetTextLen(0));
+ for (sal_Int32 nPara = 1; nPara < nParCnt; ++nPara)
+ {
+ SfxItemSet aPara2Attribs = mpEditEngine->GetAttribs(nPara, 0, mpEditEngine->GetTextLen(nPara));
+ if (!(aPara1Attribs == aPara2Attribs))
+ {
+ // Paragraph format different from that of the 1st paragraph.
+ bUniformAttribs = false;
+ break;
+ }
+ }
+
+ ESelection aSel( 0, 0, nParCnt-1, mpEditEngine->GetTextLen(nParCnt-1) );
+ SfxItemSet aOldAttribs = mpEditEngine->GetAttribs( aSel );
+ const SfxPoolItem* pItem = nullptr;
+
+ // Find common (cell) attributes before RemoveAdjust
+ if ( pActiveViewSh && bUniformAttribs )
+ {
+ std::optional<SfxItemSet> pCommonAttrs;
+ for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END; nId++)
+ {
+ SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
+ if ( eState == SfxItemState::SET &&
+ nId != EE_CHAR_ESCAPEMENT && nId != EE_CHAR_PAIRKERNING &&
+ nId != EE_CHAR_KERNING && nId != EE_CHAR_XMLATTRIBS &&
+ *pItem != pEditDefaults->Get(nId) )
+ {
+ if ( !pCommonAttrs )
+ pCommonAttrs.emplace( mpEditEngine->GetEmptyItemSet() );
+ pCommonAttrs->Put( *pItem );
+ }
+ }
+
+ if ( pCommonAttrs )
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocument();
+ pCellAttrs = std::make_unique<ScPatternAttr>(rDoc.GetPool());
+ pCellAttrs->GetFromEditItemSet( &*pCommonAttrs );
+ }
+ }
+
+ // Clear ParaAttribs (including adjustment)
+ RemoveAdjust();
+
+ bool bAttrib = false; // Formatting present?
+
+ // check if EditObject is needed
+ if (nParCnt > 1)
+ bAttrib = true;
+ else
+ {
+ for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bAttrib; nId++)
+ {
+ SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
+ if (eState == SfxItemState::DONTCARE)
+ bAttrib = true;
+ else if (eState == SfxItemState::SET)
+ {
+ // Keep same items in EditEngine as in ScEditAttrTester
+ if ( nId == EE_CHAR_ESCAPEMENT || nId == EE_CHAR_PAIRKERNING ||
+ nId == EE_CHAR_KERNING || nId == EE_CHAR_XMLATTRIBS )
+ {
+ if ( *pItem != pEditDefaults->Get(nId) )
+ bAttrib = true;
+ }
+ }
+ }
+
+ // Contains fields?
+ SfxItemState eFieldState = aOldAttribs.GetItemState( EE_FEATURE_FIELD, false );
+ if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
+ bAttrib = true;
+
+ // Not converted characters?
+ SfxItemState eConvState = aOldAttribs.GetItemState( EE_FEATURE_NOTCONV, false );
+ if ( eConvState == SfxItemState::DONTCARE || eConvState == SfxItemState::SET )
+ bAttrib = true;
+
+ // Always recognize formulas as formulas
+ // We still need the preceding test due to cell attributes
+ }
+
+ if (bSpellErrors)
+ mpEditEngine->GetAllMisspellRanges(aMisspellRanges);
+
+ if (bMatrix)
+ bAttrib = false;
+
+ if (bAttrib)
+ {
+ mpEditEngine->ClearSpellErrors();
+ pObject = mpEditEngine->CreateTextObject();
+ }
+ else if (SC_MOD()->GetAppOptions().GetAutoComplete()) // Adjust Upper/Lower case
+ {
+ // Perform case-matching only when the typed text is partial.
+ if (pColumnData && aAutoSearch.getLength() < aString.getLength())
+ aString = getExactMatch(*pColumnData, aString);
+ }
+ }
+
+ // Don't rely on ShowRefFrame switching the active view synchronously
+ // execute the function directly on the correct view's bindings instead
+ // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
+ ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;
+
+ if (bFormulaMode)
+ {
+ ShowRefFrame();
+
+ if (pExecuteSh)
+ {
+ pExecuteSh->SetTabNo(aCursorPos.Tab());
+ pExecuteSh->ActiveGrabFocus();
+ }
+
+ bFormulaMode = false;
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
+ SC_MOD()->SetRefInputHdl(nullptr);
+ if (pInputWin)
+ pInputWin->SetFormulaMode(false);
+ UpdateAutoCorrFlag();
+ }
+ pRefViewSh = nullptr; // Also without FormulaMode due to FunctionsAutoPilot
+ DeleteRangeFinder();
+ ResetAutoPar();
+
+ bool bOldMod = bModified;
+
+ bModified = false;
+ bSelIsRef = false;
+ eMode = SC_INPUT_NONE;
+ StopInputWinEngine(true);
+
+ // Text input (through number formats) or ApplySelectionPattern modify
+ // the cell's attributes, so pLastPattern is no longer valid
+ pLastPattern = nullptr;
+
+ if (bOldMod && !bProtected && !bForget)
+ {
+ bool bInsertPreCorrectedString = true;
+ // No typographic quotes in formulas
+ if (aString.startsWith("="))
+ {
+ SvxAutoCorrect* pAuto = SvxAutoCorrCfg::Get().GetAutoCorrect();
+ if ( pAuto )
+ {
+ bInsertPreCorrectedString = false;
+ OUString aReplace(pAuto->GetStartDoubleQuote());
+ if( aReplace.isEmpty() )
+ aReplace = ScGlobal::getLocaleData().getDoubleQuotationMarkStart();
+ if( aReplace != "\"" )
+ aString = aString.replaceAll( aReplace, "\"" );
+
+ aReplace = OUString(pAuto->GetEndDoubleQuote());
+ if( aReplace.isEmpty() )
+ aReplace = ScGlobal::getLocaleData().getDoubleQuotationMarkEnd();
+ if( aReplace != "\"" )
+ aString = aString.replaceAll( aReplace, "\"" );
+
+ aReplace = OUString(pAuto->GetStartSingleQuote());
+ if( aReplace.isEmpty() )
+ aReplace = ScGlobal::getLocaleData().getQuotationMarkStart();
+ if( aReplace != "'" )
+ aString = aString.replaceAll( aReplace, "'" );
+
+ aReplace = OUString(pAuto->GetEndSingleQuote());
+ if( aReplace.isEmpty() )
+ aReplace = ScGlobal::getLocaleData().getQuotationMarkEnd();
+ if( aReplace != "'" )
+ aString = aString.replaceAll( aReplace, "'");
+ }
+ }
+
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScKillEditViewNoPaint ) );
+
+ if ( pExecuteSh )
+ {
+ SfxBindings& rBindings = pExecuteSh->GetViewFrame()->GetBindings();
+
+ sal_uInt16 nId = FID_INPUTLINE_ENTER;
+ if ( nBlockMode == ScEnterMode::BLOCK )
+ nId = FID_INPUTLINE_BLOCK;
+ else if ( nBlockMode == ScEnterMode::MATRIX )
+ nId = FID_INPUTLINE_MATRIX;
+
+ const SfxPoolItem* aArgs[2];
+ aArgs[1] = nullptr;
+
+ if ( bInsertPreCorrectedString && aString != aPreAutoCorrectString )
+ {
+ ScInputStatusItem aItem(FID_INPUTLINE_STATUS,
+ aCursorPos, aCursorPos, aCursorPos,
+ aPreAutoCorrectString, pObject.get());
+ aArgs[0] = &aItem;
+ rBindings.Execute(nId, aArgs);
+ }
+
+ ScInputStatusItem aItemCorrected(FID_INPUTLINE_STATUS,
+ aCursorPos, aCursorPos, aCursorPos,
+ aString, pObject.get());
+ if ( !aMisspellRanges.empty() )
+ aItemCorrected.SetMisspellRanges(&aMisspellRanges);
+
+ aArgs[0] = &aItemCorrected;
+ rBindings.Execute(nId, aArgs);
+ }
+
+ pLastState.reset(); // pLastState still contains the old text
+ }
+ else
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScKillEditView ) );
+
+ if ( bOldMod && pExecuteSh && pCellAttrs && !bForget )
+ {
+ // Combine with input?
+ pExecuteSh->ApplySelectionPattern( *pCellAttrs, true );
+ pExecuteSh->AdjustBlockHeight();
+ }
+
+ HideTip();
+ HideTipBelow();
+
+ nFormSelStart = nFormSelEnd = 0;
+ aFormText.clear();
+
+ mbEditingExistingContent = false;
+ bInOwnChange = false;
+ bInEnterHandler = false;
+ if (bUpdateLayout)
+ mpEditEngine->SetUpdateLayout( true );
+}
+
+void ScInputHandler::CancelHandler()
+{
+ bInOwnChange = true; // Also without FormulaMode due to FunctionsAutoPilot
+
+ ImplCreateEditEngine();
+
+ bModified = false;
+ mbPartialPrefix = false;
+ mbEditingExistingContent = false;
+
+ // Don't rely on ShowRefFrame switching the active view synchronously
+ // execute the function directly on the correct view's bindings instead
+ // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
+ ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;
+
+ if (bFormulaMode)
+ {
+ ShowRefFrame();
+ if (pExecuteSh)
+ {
+ pExecuteSh->SetTabNo(aCursorPos.Tab());
+ pExecuteSh->ActiveGrabFocus();
+ }
+ bFormulaMode = false;
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
+ SC_MOD()->SetRefInputHdl(nullptr);
+ if (pInputWin)
+ pInputWin->SetFormulaMode(false);
+ UpdateAutoCorrFlag();
+ }
+ pRefViewSh = nullptr; // Also without FormulaMode due to FunctionsAutoPilot
+ DeleteRangeFinder();
+ ResetAutoPar();
+
+ eMode = SC_INPUT_NONE;
+ StopInputWinEngine( true );
+ if (pExecuteSh)
+ pExecuteSh->StopEditShell();
+
+ aCursorPos.Set(pExecuteSh->GetViewData().GetDocument().MaxCol()+1,0,0); // Invalid flag
+ mpEditEngine->SetTextCurrentDefaults(OUString());
+
+ if ( !pLastState && pExecuteSh )
+ pExecuteSh->UpdateInputHandler( true ); // Update status again
+ else
+ NotifyChange( pLastState.get(), true );
+
+ nFormSelStart = nFormSelEnd = 0;
+ aFormText.clear();
+
+ bInOwnChange = false;
+
+ if ( comphelper::LibreOfficeKit::isActive() && pExecuteSh )
+ {
+ // Clear
+ std::vector<ReferenceMark> aReferenceMarks;
+ ScInputHandler::SendReferenceMarks( pActiveViewSh, aReferenceMarks );
+ }
+}
+
+bool ScInputHandler::IsModalMode( const SfxObjectShell* pDocSh )
+{
+ // References to unnamed document; that doesn't work
+ return bFormulaMode && pRefViewSh
+ && pRefViewSh->GetViewData().GetDocument().GetDocumentShell() != pDocSh
+ && !pDocSh->HasName();
+}
+
+void ScInputHandler::AddRefEntry()
+{
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ UpdateActiveView();
+ if (!pTableView && !pTopView)
+ return; // E.g. FillMode
+
+ DataChanging(); // Cannot be new
+
+ RemoveSelection();
+ OUString aText = GetEditText(mpEditEngine.get());
+ sal_Unicode cLastChar = 0;
+ sal_Int32 nPos = aText.getLength() - 1;
+ while (nPos >= 0) //checking space
+ {
+ cLastChar = aText[nPos];
+ if (cLastChar != ' ')
+ break;
+ --nPos;
+ }
+
+ bool bAppendSeparator = (cLastChar != '(' && cLastChar != cSep && cLastChar != '=');
+ if (bAppendSeparator)
+ {
+ if (pTableView)
+ pTableView->InsertText( OUString(cSep) );
+ if (pTopView)
+ pTopView->InsertText( OUString(cSep) );
+ }
+
+ DataChanged();
+}
+
+void ScInputHandler::SetReference( const ScRange& rRef, const ScDocument& rDoc )
+{
+ HideTip();
+
+ const ScDocument* pThisDoc = nullptr;
+ if (pRefViewSh)
+ pThisDoc = &pRefViewSh->GetViewData().GetDocument();
+ bool bOtherDoc = (pThisDoc != &rDoc);
+ if (bOtherDoc && !rDoc.GetDocumentShell()->HasName())
+ {
+ // References to unnamed document; that doesn't work
+ // SetReference should not be called, then
+ return;
+ }
+ if (!pThisDoc)
+ pThisDoc = &rDoc;
+
+ UpdateActiveView();
+ if (!pTableView && !pTopView)
+ return; // E.g. FillMode
+
+ // Never overwrite the "="!
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+ if ( aSel.nStartPara == 0 && aSel.nStartPos == 0 )
+ return;
+
+ DataChanging(); // Cannot be new
+
+ // Turn around selection if backwards.
+ if (pTableView)
+ {
+ ESelection aTabSel = pTableView->GetSelection();
+ if (aTabSel.nStartPos > aTabSel.nEndPos && aTabSel.nStartPara == aTabSel.nEndPara)
+ {
+ aTabSel.Adjust();
+ pTableView->SetSelection(aTabSel);
+ }
+ }
+ if (pTopView)
+ {
+ ESelection aTopSel = pTopView->GetSelection();
+ if (aTopSel.nStartPos > aTopSel.nEndPos && aTopSel.nStartPara == aTopSel.nEndPara)
+ {
+ aTopSel.Adjust();
+ pTopView->SetSelection(aTopSel);
+ }
+ }
+
+ // Create string from reference, in the syntax of the document being edited.
+ OUString aRefStr;
+ const ScAddress::Details aAddrDetails( *pThisDoc, aCursorPos );
+ if (bOtherDoc)
+ {
+ // Reference to other document
+ OSL_ENSURE(rRef.aStart.Tab()==rRef.aEnd.Tab(), "nStartTab!=nEndTab");
+
+ // Always 3D and absolute.
+ OUString aTmp(rRef.Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_ABS_3D, aAddrDetails));
+
+ SfxObjectShell* pObjSh = rDoc.GetDocumentShell();
+ // #i75893# convert escaped URL of the document to something user friendly
+ OUString aFileName = pObjSh->GetMedium()->GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
+
+ switch(aAddrDetails.eConv)
+ {
+ case formula::FormulaGrammar::CONV_XL_A1 :
+ case formula::FormulaGrammar::CONV_XL_OOX :
+ case formula::FormulaGrammar::CONV_XL_R1C1 :
+ aRefStr = "[\'" + aFileName + "']";
+ break;
+ case formula::FormulaGrammar::CONV_OOO :
+ default:
+ aRefStr = "\'" + aFileName + "'#";
+ break;
+ }
+ aRefStr += aTmp;
+ }
+ else
+ {
+ if ( rRef.aStart.Tab() != aCursorPos.Tab() ||
+ rRef.aStart.Tab() != rRef.aEnd.Tab() )
+ // pointer-selected => absolute sheet reference
+ aRefStr = rRef.Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_ABS_3D, aAddrDetails);
+ else
+ aRefStr = rRef.Format(rDoc, ScRefFlags::VALID, aAddrDetails);
+ }
+ bool bLOKShowSelect = true;
+ if(comphelper::LibreOfficeKit::isActive() && pRefViewSh->GetViewData().GetRefTabNo() != pRefViewSh->GetViewData().GetTabNo())
+ bLOKShowSelect = false;
+
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ pTableView->InsertText( aRefStr, true, bLOKShowSelect );
+ if (pTopView)
+ pTopView->InsertText( aRefStr, true, bLOKShowSelect );
+
+ DataChanged();
+ }
+
+ bSelIsRef = true;
+}
+
+void ScInputHandler::InsertFunction( const OUString& rFuncName, bool bAddPar )
+{
+ if ( eMode == SC_INPUT_NONE )
+ {
+ OSL_FAIL("InsertFunction, not during input mode");
+ return;
+ }
+
+ UpdateActiveView();
+ if (!pTableView && !pTopView)
+ return; // E.g. FillMode
+
+ DataChanging(); // Cannot be new
+
+ OUString aText = rFuncName;
+ if (bAddPar)
+ aText += "()";
+
+ if (pTableView)
+ {
+ pTableView->InsertText( aText );
+ if (bAddPar)
+ {
+ ESelection aSel = pTableView->GetSelection();
+ --aSel.nStartPos;
+ --aSel.nEndPos;
+ pTableView->SetSelection(aSel);
+ }
+ }
+ if (pTopView)
+ {
+ pTopView->InsertText( aText );
+ if (bAddPar)
+ {
+ ESelection aSel = pTopView->GetSelection();
+ --aSel.nStartPos;
+ --aSel.nEndPos;
+ pTopView->SetSelection(aSel);
+ }
+ }
+
+ DataChanged();
+
+ if (bAddPar)
+ AutoParAdded();
+}
+
+void ScInputHandler::ClearText()
+{
+ if ( eMode == SC_INPUT_NONE )
+ {
+ OSL_FAIL("ClearText, not during input mode");
+ return;
+ }
+
+ UpdateActiveView();
+ if (!pTableView && !pTopView)
+ return; // E.g. FillMode
+
+ DataChanging(); // Cannot be new
+
+ if (pTableView)
+ {
+ pTableView->GetEditEngine()->SetText( "" );
+ pTableView->SetSelection( ESelection(0,0, 0,0) );
+ }
+ if (pTopView)
+ {
+ pTopView->GetEditEngine()->SetText( "" );
+ pTopView->SetSelection( ESelection(0,0, 0,0) );
+ }
+
+ DataChanged();
+}
+
+bool ScInputHandler::KeyInput( const KeyEvent& rKEvt, bool bStartEdit /* = false */ )
+{
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+ sal_uInt16 nModi = aCode.GetModifier();
+ bool bShift = aCode.IsShift();
+ bool bControl = aCode.IsMod1();
+ bool bAlt = aCode.IsMod2();
+ sal_uInt16 nCode = aCode.GetCode();
+ sal_Unicode nChar = rKEvt.GetCharCode();
+
+ if (bAlt && !bControl && nCode != KEY_RETURN)
+ // Alt-Return and Alt-Ctrl-* are accepted. Everything else with ALT are not.
+ return false;
+
+ // There is a partial autocomplete suggestion.
+ // Allow its completion with right arrow key (without modifiers).
+ if (mbPartialPrefix && nCode == KEY_RIGHT && !bControl && !bShift && !bAlt &&
+ (pTopView || pTableView))
+ {
+ if (pTopView)
+ pTopView->PostKeyEvent(KeyEvent(0, css::awt::Key::MOVE_TO_END_OF_PARAGRAPH));
+ if (pTableView)
+ pTableView->PostKeyEvent(KeyEvent(0, css::awt::Key::MOVE_TO_END_OF_PARAGRAPH));
+
+ mbPartialPrefix = false;
+
+ // Indicate that this event has been consumed and ScTabViewShell should not act on this.
+ return true;
+ }
+
+ if (!bControl && nCode == KEY_TAB)
+ {
+ // Normal TAB moves the cursor right.
+ EnterHandler();
+
+ if (pActiveViewSh)
+ pActiveViewSh->FindNextUnprot( bShift, true );
+ return true;
+ }
+
+ bool bInputLine = ( eMode==SC_INPUT_TOP );
+
+ bool bUsed = false;
+ bool bSkip = false;
+ bool bDoEnter = false;
+
+ switch ( nCode )
+ {
+ case KEY_RETURN:
+ // New line when in the input line and Shift/Ctrl-Enter is pressed,
+ // or when in a cell and Ctrl-Enter is pressed.
+ if ((pInputWin && bInputLine && bControl != bShift) || (!bInputLine && bControl && !bShift))
+ {
+ bDoEnter = true;
+ }
+ else if (nModi == 0 && nTipVisible && pFormulaData && miAutoPosFormula != pFormulaData->end())
+ {
+ PasteFunctionData();
+ bUsed = true;
+ }
+ else if ( nModi == 0 && nTipVisible && !aManualTip.isEmpty() )
+ {
+ PasteManualTip();
+ bUsed = true;
+ }
+ else
+ {
+ ScEnterMode nMode = ScEnterMode::NORMAL;
+ if ( bShift && bControl )
+ nMode = ScEnterMode::MATRIX;
+ else if ( bAlt )
+ nMode = ScEnterMode::BLOCK;
+ EnterHandler( nMode );
+
+ if (pActiveViewSh)
+ pActiveViewSh->MoveCursorEnter( bShift && !bControl );
+
+ bUsed = true;
+ }
+ break;
+ case KEY_TAB:
+ if (bControl && !bAlt)
+ {
+ if (pFormulaData && nTipVisible && miAutoPosFormula != pFormulaData->end())
+ {
+ // Iterate
+ NextFormulaEntry( bShift );
+ bUsed = true;
+ }
+ else if (pColumnData && bUseTab)
+ {
+ // Iterate through AutoInput entries
+ NextAutoEntry( bShift );
+ bUsed = true;
+ }
+ }
+ break;
+ case KEY_ESCAPE:
+ if ( nTipVisible )
+ {
+ HideTip();
+ bUsed = true;
+ }
+ else if( nTipVisibleSec )
+ {
+ HideTipBelow();
+ bUsed = true;
+ }
+ else if (eMode != SC_INPUT_NONE)
+ {
+ CancelHandler();
+ bUsed = true;
+ }
+ else
+ bSkip = true;
+ break;
+ case KEY_F2:
+ if ( !bShift && !bControl && !bAlt && eMode == SC_INPUT_TABLE )
+ {
+ eMode = SC_INPUT_TYPE;
+ bUsed = true;
+ }
+ break;
+ }
+
+ // Only execute cursor keys if already in EditMode
+ // E.g. due to Shift-Ctrl-PageDn (not defined as an accelerator)
+ bool bCursorKey = EditEngine::DoesKeyMoveCursor(rKEvt);
+ bool bInsKey = ( nCode == KEY_INSERT && !nModi ); // Treat Insert like Cursorkeys
+ if ( !bUsed && !bSkip && ( bDoEnter || EditEngine::DoesKeyChangeText(rKEvt) ||
+ ( eMode != SC_INPUT_NONE && ( bCursorKey || bInsKey ) ) ) )
+ {
+ HideTip();
+ HideTipBelow();
+
+ if (bSelIsRef)
+ {
+ RemoveSelection();
+ bSelIsRef = false;
+ }
+
+ UpdateActiveView();
+ bool bNewView = DataChanging( nChar );
+
+ if (bProtected) // Protected cell?
+ bUsed = true; // Don't forward KeyEvent
+ else // Changes allowed
+ {
+ if (bNewView ) // Create anew
+ {
+ if (pActiveViewSh)
+ pActiveViewSh->GetViewData().GetDocShell()->PostEditView( mpEditEngine.get(), aCursorPos );
+ UpdateActiveView();
+ if (eMode==SC_INPUT_NONE)
+ if (pTableView || pTopView)
+ {
+ OUString aStrLoP;
+
+ if (bStartEdit && nCellPercentFormatDecSep != 0 &&
+ ((nChar >= '0' && nChar <= '9') || nChar == '-' || nChar == nCellPercentFormatDecSep))
+ {
+ aStrLoP = "%";
+ }
+
+ if (pTableView)
+ {
+ pTableView->GetEditEngine()->SetText( aStrLoP );
+ if ( !aStrLoP.isEmpty() )
+ pTableView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
+
+ // Don't call SetSelection if the string is empty anyway,
+ // to avoid breaking the bInitial handling in ScViewData::EditGrowY
+ }
+ if (pTopView)
+ {
+ pTopView->GetEditEngine()->SetText( aStrLoP );
+ if ( !aStrLoP.isEmpty() )
+ pTopView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
+ }
+ }
+ SyncViews();
+ }
+
+ if (pTableView || pTopView)
+ {
+ if (bDoEnter)
+ {
+ if (pTableView)
+ if( pTableView->PostKeyEvent( KeyEvent( '\r', vcl::KeyCode(KEY_RETURN) ) ) )
+ bUsed = true;
+ if (pTopView)
+ if( pTopView->PostKeyEvent( KeyEvent( '\r', vcl::KeyCode(KEY_RETURN) ) ) )
+ bUsed = true;
+ }
+ else if ( nAutoPar && nChar == ')' && CursorAtClosingPar() )
+ {
+ SkipClosingPar();
+ bUsed = true;
+ }
+ else
+ {
+ if (pTableView)
+ {
+ if (pTopView)
+ pTableView->SetControlWord(pTableView->GetControlWord() | EVControlBits::SINGLELINEPASTE);
+
+ vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : nullptr;
+ if ( pTableView->PostKeyEvent( rKEvt, pFrameWin ) )
+ bUsed = true;
+
+ pTableView->SetControlWord(pTableView->GetControlWord() & ~EVControlBits::SINGLELINEPASTE);
+ }
+ if (pTopView)
+ {
+ if ( bUsed && rKEvt.GetKeyCode().GetFunction() == KeyFuncType::CUT )
+ pTopView->DeleteSelected();
+ else if ( pTopView->PostKeyEvent( rKEvt ) )
+ bUsed = true;
+ }
+ }
+
+ // AutoInput:
+ if ( bUsed && SC_MOD()->GetAppOptions().GetAutoComplete() )
+ {
+ bUseTab = false;
+ if (pFormulaData)
+ miAutoPosFormula = pFormulaData->end(); // do not search further
+ if (pColumnData)
+ miAutoPosColumn = pColumnData->end();
+
+ KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
+ if ( nChar && nChar != 8 && nChar != 127 && // no 'backspace', no 'delete'
+ KeyFuncType::CUT != eFunc) // and no 'CTRL-X'
+ {
+ if (bFormulaMode)
+ UseFormulaData();
+ else
+ UseColData();
+ }
+ }
+
+ // When the selection is changed manually or an opening parenthesis
+ // is typed, stop overwriting parentheses
+ if ( bUsed && nChar == '(' )
+ ResetAutoPar();
+
+ if ( KEY_INSERT == nCode )
+ {
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
+ }
+ if( bUsed && bFormulaMode && ( bCursorKey || bInsKey || nCode == KEY_DELETE || nCode == KEY_BACKSPACE ) )
+ {
+ ShowTipCursor();
+ }
+ if( bUsed && bFormulaMode && nCode == KEY_BACKSPACE )
+ {
+ UseFormulaData();
+ }
+
+ }
+
+ // #i114511# don't count cursor keys as modification
+ bool bSetModified = !bCursorKey;
+ DataChanged(false, bSetModified); // also calls UpdateParenthesis()
+
+ // In the LOK case, we want to set the document modified state
+ // right away at the start of the edit, so that the content is
+ // saved even when the user leaves the document before hitting
+ // Enter
+ if (comphelper::LibreOfficeKit::isActive() && bSetModified && pActiveViewSh && !pActiveViewSh->GetViewData().GetDocShell()->IsModified())
+ pActiveViewSh->GetViewData().GetDocShell()->SetModified();
+
+ InvalidateAttribs(); //! in DataChanged?
+ }
+ }
+
+ if (pTopView && eMode != SC_INPUT_NONE)
+ SyncViews();
+
+ return bUsed;
+}
+
+OUString ScInputHandler::GetSurroundingText()
+{
+ if (eMode != SC_INPUT_NONE)
+ {
+ UpdateActiveView();
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ return pTableView->GetSurroundingText();
+ else if (pTopView) // call only once
+ return pTopView->GetSurroundingText();
+ }
+ }
+ return OUString();
+}
+
+Selection ScInputHandler::GetSurroundingTextSelection()
+{
+ if (eMode != SC_INPUT_NONE)
+ {
+ UpdateActiveView();
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ return pTableView->GetSurroundingTextSelection();
+ else if (pTopView) // call only once
+ return pTopView->GetSurroundingTextSelection();
+ }
+ }
+ return Selection(0, 0);
+}
+
+bool ScInputHandler::DeleteSurroundingText(const Selection& rSelection)
+{
+ if (eMode != SC_INPUT_NONE)
+ {
+ UpdateActiveView();
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ return pTableView->DeleteSurroundingText(rSelection);
+ else if (pTopView) // call only once
+ return pTopView->DeleteSurroundingText(rSelection);
+ }
+ }
+ return false;
+}
+
+void ScInputHandler::InputCommand( const CommandEvent& rCEvt )
+{
+ if ( rCEvt.GetCommand() == CommandEventId::CursorPos )
+ {
+ // For CommandEventId::CursorPos, do as little as possible, because
+ // with remote VCL, even a ShowCursor will generate another event.
+ if ( eMode != SC_INPUT_NONE )
+ {
+ UpdateActiveView();
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ pTableView->Command( rCEvt );
+ else if (pTopView) // call only once
+ pTopView->Command( rCEvt );
+ }
+ }
+ }
+ else if ( rCEvt.GetCommand() == CommandEventId::QueryCharPosition )
+ {
+ if ( eMode != SC_INPUT_NONE )
+ {
+ UpdateActiveView();
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ pTableView->Command( rCEvt );
+ else if (pTopView) // call only once
+ pTopView->Command( rCEvt );
+ }
+ }
+ }
+ else
+ {
+ HideTip();
+ HideTipBelow();
+
+ if ( bSelIsRef )
+ {
+ RemoveSelection();
+ bSelIsRef = false;
+ }
+
+ UpdateActiveView();
+ bool bNewView = DataChanging( 0, true );
+
+ if (!bProtected) // changes allowed
+ {
+ if (bNewView) // create new edit view
+ {
+ if (pActiveViewSh)
+ pActiveViewSh->GetViewData().GetDocShell()->PostEditView( mpEditEngine.get(), aCursorPos );
+ UpdateActiveView();
+ if (eMode==SC_INPUT_NONE)
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ {
+ pTableView->GetEditEngine()->SetText( "" );
+ pTableView->SetSelection( ESelection(0,0, 0,0) );
+ }
+ if (pTopView)
+ {
+ pTopView->GetEditEngine()->SetText( "" );
+ pTopView->SetSelection( ESelection(0,0, 0,0) );
+ }
+ }
+ SyncViews();
+ }
+
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ pTableView->Command( rCEvt );
+ if (pTopView && !comphelper::LibreOfficeKit::isActive())
+ pTopView->Command( rCEvt );
+
+ if ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput )
+ {
+ // AutoInput after ext text input
+
+ if (pFormulaData)
+ miAutoPosFormula = pFormulaData->end();
+ if (pColumnData)
+ miAutoPosColumn = pColumnData->end();
+
+ if (bFormulaMode)
+ UseFormulaData();
+ else
+ UseColData();
+ }
+ }
+
+ DataChanged(); // calls UpdateParenthesis()
+ InvalidateAttribs(); //! in DataChanged ?
+ }
+
+ if (pTopView && eMode != SC_INPUT_NONE)
+ SyncViews();
+ }
+}
+
+void ScInputHandler::NotifyChange( const ScInputHdlState* pState,
+ bool bForce, ScTabViewShell* pSourceSh,
+ bool bStopEditing)
+{
+ // If the call originates from a macro call in the EnterHandler,
+ // return immediately and don't mess up the status
+ if (bInEnterHandler)
+ return;
+
+ bool bRepeat = (pState == pLastState.get());
+ if (!bRepeat && pState && pLastState)
+ bRepeat = (*pState == *pLastState);
+ if (bRepeat && !bForce)
+ return;
+
+ bInOwnChange = true; // disable ModifyHdl (reset below)
+
+ if ( pState && !pLastState ) // Enable again
+ bForce = true;
+
+ bool bHadObject = pLastState && pLastState->GetEditData();
+
+ //! Before EditEngine gets eventually created (so it gets the right pools)
+ if ( pSourceSh )
+ pActiveViewSh = pSourceSh;
+ else
+ pActiveViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+
+ ImplCreateEditEngine();
+
+ if ( pState != pLastState.get() )
+ {
+ pLastState.reset( pState ? new ScInputHdlState( *pState ) : nullptr);
+ }
+
+ if ( pState && pActiveViewSh )
+ {
+ ScModule* pScMod = SC_MOD();
+
+ ScTabViewShell* pScTabViewShell = dynamic_cast<ScTabViewShell*>(pScMod->GetViewShell());
+
+ // Also take foreign reference input into account here (e.g. FunctionsAutoPilot),
+ // FormEditData, if we're switching from Help to Calc:
+ if ( !bFormulaMode && !pScMod->IsFormulaMode() &&
+ ( !pScTabViewShell || !pScTabViewShell->GetFormEditData() ) )
+ {
+ bool bIgnore = false;
+ if ( bModified )
+ {
+ if (pState->GetPos() != aCursorPos)
+ {
+ if (!bProtected)
+ EnterHandler();
+ }
+ else
+ bIgnore = true;
+ }
+
+ if ( !bIgnore )
+ {
+ const ScAddress& rSPos = pState->GetStartPos();
+ const ScAddress& rEPos = pState->GetEndPos();
+ const EditTextObject* pData = pState->GetEditData();
+ OUString aString = pState->GetString();
+ bool bTxtMod = false;
+ ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ aCursorPos = pState->GetPos();
+
+ if ( pData )
+ bTxtMod = true;
+ else if ( bHadObject )
+ bTxtMod = true;
+ else if ( bTextValid )
+ bTxtMod = ( aString != aCurrentText );
+ else
+ bTxtMod = ( aString != GetEditText(mpEditEngine.get()) );
+
+ if ( bTxtMod || bForce )
+ {
+ if (pData)
+ {
+ mpEditEngine->SetTextCurrentDefaults( *pData );
+ if (pInputWin)
+ aString = ScEditUtil::GetMultilineString(*mpEditEngine);
+ else
+ aString = GetEditText(mpEditEngine.get());
+ lcl_RemoveTabs(aString);
+ bTextValid = false;
+ aCurrentText.clear();
+ }
+ else
+ {
+ aCurrentText = aString;
+ bTextValid = true; //! To begin with remember as a string
+ }
+
+ if ( pInputWin )
+ pInputWin->SetTextString(aString);
+
+ if (comphelper::LibreOfficeKit::isActive() && pActiveViewSh)
+ {
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ ESelection aSel = pActiveView ? pActiveView->GetSelection() : ESelection();
+ ScInputHandler::LOKSendFormulabarUpdate(pActiveViewSh, aString, aSel);
+ // TODO: deprecated?
+ pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_FORMULA, aString.toUtf8().getStr());
+ }
+ }
+
+ if ( pInputWin || comphelper::LibreOfficeKit::isActive()) // Named range input
+ {
+ OUString aPosStr;
+ bool bSheetLocal = false;
+ const ScAddress::Details aAddrDetails( rDoc, aCursorPos );
+
+ // Is the range a name?
+ //! Find by Timer?
+ if ( pActiveViewSh )
+ pActiveViewSh->GetViewData().GetDocument().
+ GetRangeAtBlock( ScRange( rSPos, rEPos ), aPosStr, &bSheetLocal);
+
+ if ( aPosStr.isEmpty() ) // Not a name -> format
+ {
+ ScRefFlags nFlags = ScRefFlags::ZERO;
+ if( aAddrDetails.eConv == formula::FormulaGrammar::CONV_XL_R1C1 )
+ nFlags |= ScRefFlags::COL_ABS | ScRefFlags::ROW_ABS;
+ if ( rSPos != rEPos )
+ {
+ ScRange r(rSPos, rEPos);
+ applyStartToEndFlags(nFlags);
+ aPosStr = r.Format(rDoc, ScRefFlags::VALID | nFlags, aAddrDetails);
+ }
+ else
+ aPosStr = aCursorPos.Format(ScRefFlags::VALID | nFlags, &rDoc, aAddrDetails);
+ }
+ else if (bSheetLocal)
+ {
+ OUString aName;
+ if (rDoc.GetName( rSPos.Tab(), aName))
+ aPosStr = ScPosWnd::createLocalRangeName( aPosStr, aName);
+ }
+
+ if (pInputWin)
+ {
+ // Disable the accessible VALUE_CHANGE event
+ bool bIsSuppressed = pInputWin->IsAccessibilityEventsSuppressed(false);
+ pInputWin->SetAccessibilityEventsSuppressed(true);
+ pInputWin->SetPosString(aPosStr);
+ pInputWin->SetAccessibilityEventsSuppressed(bIsSuppressed);
+ pInputWin->SetSumAssignMode();
+ }
+
+ if (comphelper::LibreOfficeKit::isActive() && pActiveViewSh)
+ pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_ADDRESS, aPosStr.toUtf8().getStr());
+ }
+
+ if (bStopEditing) {
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScKillEditView ) );
+
+ // As long as the content is not edited, turn off online spelling.
+ // Online spelling is turned back on in StartTable, after setting
+ // the right language from cell attributes.
+
+ EEControlBits nCntrl = mpEditEngine->GetControlWord();
+ if ( nCntrl & EEControlBits::ONLINESPELLING )
+ mpEditEngine->SetControlWord( nCntrl & ~EEControlBits::ONLINESPELLING );
+ }
+
+ bModified = false;
+ bSelIsRef = false;
+ bProtected = false;
+ bCommandErrorShown = false;
+ }
+ }
+
+ if ( pInputWin)
+ {
+ // Do not enable if RefDialog is open
+ if(!pScMod->IsFormulaMode()&& !pScMod->IsRefDialogOpen())
+ {
+ if ( !pInputWin->IsEnabled())
+ {
+ pDelayTimer->Stop();
+ pInputWin->Enable();
+ }
+ }
+ else if(pScMod->IsRefDialogOpen())
+ { // Because every document has its own InputWin,
+ // we should start Timer again, because the input line may
+ // still be active
+ if ( !pDelayTimer->IsActive() )
+ pDelayTimer->Start();
+ }
+ }
+ }
+ else // !pState || !pActiveViewSh
+ {
+ if ( !pDelayTimer->IsActive() )
+ pDelayTimer->Start();
+ }
+
+ HideTip();
+ HideTipBelow();
+ bInOwnChange = false;
+}
+
+void ScInputHandler::UpdateCellAdjust( SvxCellHorJustify eJust )
+{
+ eAttrAdjust = eJust;
+ UpdateAdjust( 0 );
+}
+
+void ScInputHandler::ResetDelayTimer()
+{
+ if( pDelayTimer->IsActive() )
+ {
+ pDelayTimer->Stop();
+ if ( pInputWin )
+ pInputWin->Enable();
+ }
+}
+
+IMPL_LINK_NOARG( ScInputHandler, DelayTimer, Timer*, void )
+{
+ if ( !(nullptr == pLastState || SC_MOD()->IsFormulaMode() || SC_MOD()->IsRefDialogOpen()))
+ return;
+
+ //! New method at ScModule to query if function autopilot is open
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if ( pViewFrm && pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
+ {
+ if ( pInputWin)
+ {
+ pInputWin->EnableButtons( false );
+ pInputWin->Disable();
+ }
+ }
+ else if ( !bFormulaMode ) // Keep formula e.g. for help
+ {
+ bInOwnChange = true; // disable ModifyHdl (reset below)
+
+ pActiveViewSh = nullptr;
+ mpEditEngine->SetTextCurrentDefaults( OUString() );
+ if ( pInputWin )
+ {
+ pInputWin->SetPosString( OUString() );
+ pInputWin->SetTextString( OUString() );
+ pInputWin->Disable();
+ }
+
+ bInOwnChange = false;
+ }
+}
+
+void ScInputHandler::InputSelection( const EditView* pView )
+{
+ SyncViews( pView );
+ ShowTipCursor();
+ UpdateParenthesis(); // Selection changed -> update parentheses highlighting
+
+ // When the selection is changed manually, stop overwriting parentheses
+ ResetAutoPar();
+
+ if (comphelper::LibreOfficeKit::isActive() && pActiveViewSh)
+ {
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ ESelection aSel = pActiveView ? pActiveView->GetSelection() : ESelection();
+ ScInputHandler::LOKSendFormulabarUpdate(pActiveViewSh, GetEditString(), aSel);
+ }
+}
+
+void ScInputHandler::InputChanged( const EditView* pView, bool bFromNotify )
+{
+ if ( !pView )
+ return;
+
+ UpdateActiveView();
+
+ // #i20282# DataChanged needs to know if this is from the input line's modify handler
+ bool bFromTopNotify = ( bFromNotify && pView == pTopView );
+
+ bool bNewView = DataChanging(); //FIXME: Is this at all possible?
+ aCurrentText = pView->GetEditEngine()->GetText(); // Also remember the string
+ mpEditEngine->SetTextCurrentDefaults( aCurrentText );
+ DataChanged( bFromTopNotify );
+ bTextValid = true; // Is set to false in DataChanged
+
+ if ( pActiveViewSh )
+ {
+ ScViewData& rViewData = pActiveViewSh->GetViewData();
+ if ( bNewView )
+ rViewData.GetDocShell()->PostEditView( mpEditEngine.get(), aCursorPos );
+
+ rViewData.EditGrowY();
+ rViewData.EditGrowX();
+ }
+
+ SyncViews( pView );
+}
+
+const OUString& ScInputHandler::GetEditString()
+{
+ if (mpEditEngine)
+ {
+ aCurrentText = mpEditEngine->GetText(); // Always new from Engine
+ bTextValid = true;
+ }
+
+ return aCurrentText;
+}
+
+Size ScInputHandler::GetTextSize()
+{
+ Size aSize;
+ if ( mpEditEngine )
+ aSize = Size( mpEditEngine->CalcTextWidth(), mpEditEngine->GetTextHeight() );
+
+ return aSize;
+}
+
+bool ScInputHandler::GetTextAndFields( ScEditEngineDefaulter& rDestEngine )
+{
+ bool bRet = false;
+ if (mpEditEngine)
+ {
+ // Contains field?
+ sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
+ SfxItemSet aSet = mpEditEngine->GetAttribs( ESelection(0,0,nParCnt,0) );
+ SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, false );
+ if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
+ {
+ // Copy content
+ std::unique_ptr<EditTextObject> pObj = mpEditEngine->CreateTextObject();
+ rDestEngine.SetTextCurrentDefaults(*pObj);
+ pObj.reset();
+
+ // Delete attributes
+ for (sal_Int32 i=0; i<nParCnt; i++)
+ rDestEngine.RemoveCharAttribs( i );
+
+ // Combine paragraphs
+ while ( nParCnt > 1 )
+ {
+ sal_Int32 nLen = rDestEngine.GetTextLen( 0 );
+ ESelection aSel( 0,nLen, 1,0 );
+ rDestEngine.QuickInsertText( OUString(' '), aSel ); // Replace line break with space
+ --nParCnt;
+ }
+
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
+/**
+ * Methods for FunctionAutoPilot:
+ * InputGetSelection, InputSetSelection, InputReplaceSelection, InputGetFormulaStr
+ */
+void ScInputHandler::InputGetSelection( sal_Int32& rStart, sal_Int32& rEnd )
+{
+ rStart = nFormSelStart;
+ rEnd = nFormSelEnd;
+}
+
+EditView* ScInputHandler::GetFuncEditView()
+{
+ UpdateActiveView(); // Due to pTableView
+
+ EditView* pView = nullptr;
+ if ( pInputWin )
+ {
+ pInputWin->MakeDialogEditView();
+ pView = pInputWin->GetEditView();
+ }
+ else
+ {
+ if ( eMode != SC_INPUT_TABLE )
+ {
+ bCreatingFuncView = true; // Don't display RangeFinder
+ SetMode( SC_INPUT_TABLE );
+ bCreatingFuncView = false;
+ if ( pTableView )
+ pTableView->GetEditEngine()->SetText( OUString() );
+ }
+ pView = pTableView;
+ }
+
+ return pView;
+}
+
+void ScInputHandler::InputSetSelection( sal_Int32 nStart, sal_Int32 nEnd )
+{
+ if ( nStart <= nEnd )
+ {
+ nFormSelStart = nStart;
+ nFormSelEnd = nEnd;
+ }
+ else
+ {
+ nFormSelEnd = nStart;
+ nFormSelStart = nEnd;
+ }
+
+ EditView* pView = GetFuncEditView();
+ if (pView)
+ pView->SetSelection( ESelection(0,nStart, 0,nEnd) );
+
+ bModified = true;
+}
+
+void ScInputHandler::InputReplaceSelection( const OUString& rStr )
+{
+ if (!pRefViewSh)
+ pRefViewSh = pActiveViewSh;
+
+ OSL_ENSURE(nFormSelEnd>=nFormSelStart,"Selection broken...");
+
+ sal_Int32 nOldLen = nFormSelEnd - nFormSelStart;
+ sal_Int32 nNewLen = rStr.getLength();
+
+ OUStringBuffer aBuf(aFormText);
+ if (nOldLen)
+ aBuf.remove(nFormSelStart, nOldLen);
+ if (nNewLen)
+ aBuf.insert(nFormSelStart, rStr);
+
+ aFormText = aBuf.makeStringAndClear();
+
+ nFormSelEnd = nFormSelStart + nNewLen;
+
+ EditView* pView = GetFuncEditView();
+ if (pView)
+ {
+ pView->SetEditEngineUpdateLayout( false );
+ pView->GetEditEngine()->SetText( aFormText );
+ pView->SetSelection( ESelection(0,nFormSelStart, 0,nFormSelEnd) );
+ pView->SetEditEngineUpdateLayout( true );
+ }
+ bModified = true;
+}
+
+void ScInputHandler::InputTurnOffWinEngine()
+{
+ bInOwnChange = true; // disable ModifyHdl (reset below)
+
+ eMode = SC_INPUT_NONE;
+ /* TODO: it would be better if there was some way to reset the input bar
+ * engine instead of deleting and having it recreate through
+ * GetFuncEditView(), but first least invasively let this fix fdo#71667 and
+ * fdo#72278 without reintroducing fdo#69971. */
+ StopInputWinEngine(true);
+
+ bInOwnChange = false;
+}
+
+/**
+ * ScInputHdlState
+ */
+ScInputHdlState::ScInputHdlState( const ScAddress& rCurPos,
+ const ScAddress& rStartPos,
+ const ScAddress& rEndPos,
+ const OUString& rString,
+ const EditTextObject* pData )
+ : aCursorPos ( rCurPos ),
+ aStartPos ( rStartPos ),
+ aEndPos ( rEndPos ),
+ aString ( rString ),
+ pEditData ( pData ? pData->Clone() : nullptr )
+{
+}
+
+ScInputHdlState::ScInputHdlState( const ScInputHdlState& rCpy )
+{
+ *this = rCpy;
+}
+
+ScInputHdlState::~ScInputHdlState()
+{
+}
+
+bool ScInputHdlState::operator==( const ScInputHdlState& r ) const
+{
+ return ( (aStartPos == r.aStartPos)
+ && (aEndPos == r.aEndPos)
+ && (aCursorPos == r.aCursorPos)
+ && (aString == r.aString)
+ && ScGlobal::EETextObjEqual( pEditData.get(), r.pEditData.get() ) );
+}
+
+ScInputHdlState& ScInputHdlState::operator=( const ScInputHdlState& r )
+{
+ if (this != &r)
+ {
+ aCursorPos = r.aCursorPos;
+ aStartPos = r.aStartPos;
+ aEndPos = r.aEndPos;
+ aString = r.aString;
+ pEditData.reset();
+ if (r.pEditData)
+ pEditData = r.pEditData->Clone();
+ }
+ return *this;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/inputwin.cxx b/sc/source/ui/app/inputwin.cxx
new file mode 100644
index 000000000..0b31b8160
--- /dev/null
+++ b/sc/source/ui/app/inputwin.cxx
@@ -0,0 +1,2703 @@
+/* -*- 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 <algorithm>
+#include <string_view>
+
+#include <editeng/eeitem.hxx>
+
+#include <sfx2/app.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/langitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/event.hxx>
+#include <editeng/scriptspaceitem.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/help.hxx>
+#include <vcl/settings.hxx>
+#include <svl/stritem.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weldutils.hxx>
+#include <unotools/charclass.hxx>
+
+#include <inputwin.hxx>
+#include <scmod.hxx>
+#include <global.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <globstr.hrc>
+#include <bitmaps.hlst>
+#include <reffact.hxx>
+#include <editutil.hxx>
+#include <inputhdl.hxx>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <appoptio.hxx>
+#include <rangenam.hxx>
+#include <rangeutl.hxx>
+#include <docfunc.hxx>
+#include <funcdesc.hxx>
+#include <editeng/fontitem.hxx>
+#include <AccessibleEditObject.hxx>
+#include <AccessibleText.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/string.hxx>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <helpids.h>
+#include <output.hxx>
+
+namespace com::sun::star::accessibility { class XAccessible; }
+
+const tools::Long THESIZE = 1000000; // Should be more than enough!
+const tools::Long INPUTLINE_INSET_MARGIN = 2; // Space between border and interior widgets of input line
+const tools::Long LEFT_OFFSET = 5; // Left offset of input line
+//TODO const long BUTTON_OFFSET = 2; // Space between input line and button to expand/collapse
+const tools::Long INPUTWIN_MULTILINES = 6; // Initial number of lines within multiline dropdown
+const tools::Long TOOLBOX_WINDOW_HEIGHT = 22; // Height of toolbox window in pixels - TODO: The same on all systems?
+const tools::Long POSITION_COMBOBOX_WIDTH = 18; // Width of position combobox in characters
+const int RESIZE_HOTSPOT_HEIGHT = 4;
+
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::UNO_QUERY;
+
+using com::sun::star::frame::XLayoutManager;
+using com::sun::star::beans::XPropertySet;
+
+namespace {
+
+constexpr ToolBoxItemId SID_INPUT_FUNCTION (SC_VIEW_START + 47);
+constexpr ToolBoxItemId SID_INPUT_SUM (SC_VIEW_START + 48);
+constexpr ToolBoxItemId SID_INPUT_EQUAL (SC_VIEW_START + 49);
+constexpr ToolBoxItemId SID_INPUT_CANCEL (SC_VIEW_START + 50);
+constexpr ToolBoxItemId SID_INPUT_OK (SC_VIEW_START + 51);
+
+enum ScNameInputType
+{
+ SC_NAME_INPUT_CELL,
+ SC_NAME_INPUT_RANGE,
+ SC_NAME_INPUT_NAMEDRANGE_LOCAL,
+ SC_NAME_INPUT_NAMEDRANGE_GLOBAL,
+ SC_NAME_INPUT_DATABASE,
+ SC_NAME_INPUT_ROW,
+ SC_NAME_INPUT_SHEET,
+ SC_NAME_INPUT_DEFINE,
+ SC_NAME_INPUT_BAD_NAME,
+ SC_NAME_INPUT_BAD_SELECTION,
+ SC_MANAGE_NAMES
+};
+
+}
+
+SFX_IMPL_CHILDWINDOW_WITHID(ScInputWindowWrapper,FID_INPUTLINE_STATUS)
+
+ScInputWindowWrapper::ScInputWindowWrapper( vcl::Window* pParentP,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* /* pInfo */ )
+ : SfxChildWindow( pParentP, nId )
+{
+ VclPtr<ScInputWindow> pWin = VclPtr<ScInputWindow>::Create( pParentP, pBindings );
+ SetWindow( pWin );
+
+ pWin->Show();
+
+ pWin->SetSizePixel( pWin->CalcWindowSizePixel() );
+
+ SetAlignment(SfxChildAlignment::LOWESTTOP);
+ pBindings->Invalidate( FID_TOGGLEINPUTLINE );
+}
+
+/**
+ * GetInfo is disposed of if there's a SFX_IMPL_TOOLBOX!
+ */
+SfxChildWinInfo ScInputWindowWrapper::GetInfo() const
+{
+ SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
+ return aInfo;
+}
+
+
+static VclPtr<ScInputBarGroup> lcl_chooseRuntimeImpl( vcl::Window* pParent, const SfxBindings* pBind )
+{
+ ScTabViewShell* pViewSh = nullptr;
+ SfxDispatcher* pDisp = pBind->GetDispatcher();
+ if ( pDisp )
+ {
+ SfxViewFrame* pViewFrm = pDisp->GetFrame();
+ if ( pViewFrm )
+ pViewSh = dynamic_cast<ScTabViewShell*>( pViewFrm->GetViewShell() );
+ }
+
+ return VclPtr<ScInputBarGroup>::Create( pParent, pViewSh );
+}
+
+ScInputWindow::ScInputWindow( vcl::Window* pParent, const SfxBindings* pBind ) :
+ // With WB_CLIPCHILDREN otherwise we get flickering
+ ToolBox ( pParent, WinBits(WB_CLIPCHILDREN | WB_BORDER | WB_NOSHADOW) ),
+ aWndPos ( !comphelper::LibreOfficeKit::isActive() ? VclPtr<ScPosWnd>::Create(this) : nullptr ),
+ mxTextWindow ( lcl_chooseRuntimeImpl( this, pBind ) ),
+ pInputHdl ( nullptr ),
+ mpViewShell ( nullptr ),
+ mnMaxY (0),
+ mnStandardItemHeight(0),
+ bIsOkCancelMode ( false ),
+ bInResize ( false )
+{
+ // #i73615# don't rely on SfxViewShell::Current while constructing the input line
+ // (also for GetInputHdl below)
+ ScTabViewShell* pViewSh = nullptr;
+ SfxDispatcher* pDisp = pBind->GetDispatcher();
+ if ( pDisp )
+ {
+ SfxViewFrame* pViewFrm = pDisp->GetFrame();
+ if ( pViewFrm )
+ pViewSh = dynamic_cast<ScTabViewShell*>( pViewFrm->GetViewShell() );
+ }
+ OSL_ENSURE( pViewSh, "no view shell for input window" );
+
+ mpViewShell = pViewSh;
+
+ // Position window, 3 buttons, input window
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ InsertWindow (ToolBoxItemId(1), aWndPos.get(), ToolBoxItemBits::NONE, 0);
+ InsertSeparator (1);
+ InsertItem (SID_INPUT_FUNCTION, Image(StockImage::Yes, RID_BMP_INPUT_FUNCTION), ToolBoxItemBits::NONE, 2);
+ }
+
+ const bool bIsLOKMobilePhone = mpViewShell && mpViewShell->isLOKMobilePhone();
+
+ // sigma and equal buttons
+ if (!bIsLOKMobilePhone)
+ {
+ InsertItem (SID_INPUT_SUM, Image(StockImage::Yes, RID_BMP_INPUT_SUM), ToolBoxItemBits::DROPDOWNONLY, 3);
+ InsertItem (SID_INPUT_EQUAL, Image(StockImage::Yes, RID_BMP_INPUT_EQUAL), ToolBoxItemBits::NONE, 4);
+ InsertItem (SID_INPUT_CANCEL, Image(StockImage::Yes, RID_BMP_INPUT_CANCEL), ToolBoxItemBits::NONE, 5);
+ InsertItem (SID_INPUT_OK, Image(StockImage::Yes, RID_BMP_INPUT_OK), ToolBoxItemBits::NONE, 6);
+ }
+
+ InsertWindow (ToolBoxItemId(7), mxTextWindow.get(), ToolBoxItemBits::NONE, 7);
+ SetDropdownClickHdl( LINK( this, ScInputWindow, DropdownClickHdl ));
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ aWndPos ->SetQuickHelpText(ScResId(SCSTR_QHELP_POSWND));
+ aWndPos ->SetHelpId (HID_INSWIN_POS);
+
+ mxTextWindow->SetQuickHelpText(ScResId(SCSTR_QHELP_INPUTWND));
+ mxTextWindow->SetHelpId (HID_INSWIN_INPUT);
+
+ // No SetHelpText: the helptexts come from the Help
+ SetItemText (SID_INPUT_FUNCTION, ScResId(SCSTR_QHELP_BTNCALC));
+ SetHelpId (SID_INPUT_FUNCTION, HID_INSWIN_CALC);
+ }
+
+ // sigma and equal buttons
+ if (!bIsLOKMobilePhone)
+ {
+ SetHelpId (SID_INPUT_SUM, HID_INSWIN_SUMME);
+ SetHelpId (SID_INPUT_EQUAL, HID_INSWIN_FUNC);
+ SetHelpId (SID_INPUT_CANCEL, HID_INSWIN_CANCEL);
+ SetHelpId (SID_INPUT_OK, HID_INSWIN_OK);
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ SetItemText ( SID_INPUT_SUM, ScResId( SCSTR_QHELP_BTNSUM ) );
+ SetItemText ( SID_INPUT_EQUAL, ScResId( SCSTR_QHELP_BTNEQUAL ) );
+ SetItemText ( SID_INPUT_CANCEL, ScResId( SCSTR_QHELP_BTNCANCEL ) );
+ SetItemText ( SID_INPUT_OK, ScResId( SCSTR_QHELP_BTNOK ) );
+ }
+
+ EnableItem( SID_INPUT_CANCEL, false );
+ EnableItem( SID_INPUT_OK, false );
+
+ HideItem( SID_INPUT_CANCEL );
+ HideItem( SID_INPUT_OK );
+
+ mnStandardItemHeight = GetItemRect(SID_INPUT_SUM).GetHeight();
+ }
+
+ SetHelpId( HID_SC_INPUTWIN ); // For the whole input row
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ aWndPos ->Show();
+ mxTextWindow->Show();
+
+ pInputHdl = SC_MOD()->GetInputHdl( pViewSh, false ); // use own handler even if ref-handler is set
+ if (pInputHdl)
+ pInputHdl->SetInputWindow( this );
+
+ if (pInputHdl && !pInputHdl->GetFormString().isEmpty())
+ {
+ // Switch over while the Function AutoPilot is active
+ // -> show content of the Function AutoPilot again
+ // Also show selection (remember at the InputHdl)
+ mxTextWindow->SetTextString( pInputHdl->GetFormString() );
+ }
+ else if (pInputHdl && pInputHdl->IsInputMode())
+ {
+ // If the input row was hidden while editing (e.g. when editing a formula
+ // and then switching to another document or the help), display the text
+ // we just edited from the InputHandler
+ mxTextWindow->SetTextString( pInputHdl->GetEditString() ); // Display text
+ if ( pInputHdl->IsTopMode() )
+ pInputHdl->SetMode( SC_INPUT_TABLE ); // Focus ends up at the bottom anyways
+ }
+ else if (pViewSh)
+ {
+ // Don't stop editing in LOK a remote user might be editing.
+ const bool bStopEditing = !comphelper::LibreOfficeKit::isActive();
+ pViewSh->UpdateInputHandler(true, bStopEditing); // Absolutely necessary update
+ }
+
+ SetToolbarLayoutMode( ToolBoxLayoutMode::Locked );
+
+ SetAccessibleName(ScResId(STR_ACC_TOOLBAR_FORMULA));
+}
+
+ScInputWindow::~ScInputWindow()
+{
+ disposeOnce();
+}
+
+void ScInputWindow::dispose()
+{
+ bool bDown = !ScGlobal::oSysLocale; // after Clear?
+
+ // if any view's input handler has a pointer to this input window, reset it
+ // (may be several ones, #74522#)
+ // member pInputHdl is not used here
+
+ if ( !bDown )
+ {
+ SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
+ while ( pSh )
+ {
+ ScInputHandler* pHdl = static_cast<ScTabViewShell*>(pSh)->GetInputHandler();
+ if ( pHdl && pHdl->GetInputWindow() == this )
+ {
+ pHdl->SetInputWindow( nullptr );
+ pHdl->StopInputWinEngine( false ); // reset pTopView pointer
+ }
+ pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> );
+ }
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (GetLOKNotifier())
+ ReleaseLOKNotifier();
+ }
+
+ mxTextWindow.disposeAndClear();
+ aWndPos.disposeAndClear();
+
+ ToolBox::dispose();
+}
+
+void ScInputWindow::SetInputHandler( ScInputHandler* pNew )
+{
+ // Is called in the Activate of the View ...
+ if ( pNew != pInputHdl )
+ {
+ // On Reload (last version) the pInputHdl is the InputHandler of the old, deleted
+ // ViewShell: so don't touch it here!
+ pInputHdl = pNew;
+ if (pInputHdl)
+ pInputHdl->SetInputWindow( this );
+ }
+}
+
+void ScInputWindow::Select()
+{
+ ScModule* pScMod = SC_MOD();
+ ToolBox::Select();
+
+ ToolBoxItemId curItemId = GetCurItemId();
+ if (curItemId == SID_INPUT_FUNCTION)
+ {
+ //! new method at ScModule to query if function autopilot is open
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if ( pViewFrm && ( comphelper::LibreOfficeKit::isActive() || !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) ) )
+ {
+ pViewFrm->GetDispatcher()->Execute( SID_OPENDLG_FUNCTION,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
+
+ // The Toolbox will be disabled anyways, so we don't need to switch here,
+ // regardless whether it succeeded or not!
+// SetOkCancelMode();
+ }
+ }
+ else if (curItemId == SID_INPUT_CANCEL)
+ {
+ pScMod->InputCancelHandler();
+ SetSumAssignMode();
+ }
+ else if (curItemId == SID_INPUT_OK)
+ {
+ pScMod->InputEnterHandler();
+ SetSumAssignMode();
+ mxTextWindow->Invalidate(); // Or else the Selection remains
+ }
+ else if (curItemId == SID_INPUT_EQUAL)
+ {
+ StartFormula();
+ }
+}
+
+void ScInputWindow::StartFormula()
+{
+ ScModule* pScMod = SC_MOD();
+ mxTextWindow->StartEditEngine();
+ if ( pScMod->IsEditMode() ) // Isn't if e.g. protected
+ {
+ mxTextWindow->StartEditEngine();
+
+ sal_Int32 nStartPos = 1;
+ sal_Int32 nEndPos = 1;
+
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ if ( pViewSh )
+ {
+ const OUString& rString = mxTextWindow->GetTextString();
+ const sal_Int32 nLen = rString.getLength();
+
+ ScDocument& rDoc = pViewSh->GetViewData().GetDocument();
+ CellType eCellType = rDoc.GetCellType( pViewSh->GetViewData().GetCurPos() );
+ switch ( eCellType )
+ {
+ case CELLTYPE_VALUE:
+ {
+ nEndPos = nLen + 1;
+ mxTextWindow->SetTextString("=" + rString);
+ break;
+ }
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ nStartPos = 0;
+ nEndPos = nLen;
+ break;
+ case CELLTYPE_FORMULA:
+ nEndPos = nLen;
+ break;
+ default:
+ mxTextWindow->SetTextString("=");
+ break;
+ }
+ }
+
+ EditView* pView = mxTextWindow->GetEditView();
+ if (pView)
+ {
+ if (comphelper::LibreOfficeKit::isActive())
+ TextGrabFocus();
+ pView->SetSelection( ESelection(0, nStartPos, 0, nEndPos) );
+ pScMod->InputChanged(pView);
+ SetOkCancelMode();
+ pView->SetEditEngineUpdateLayout(true);
+ }
+ }
+}
+
+void ScInputWindow::PixelInvalidate(const tools::Rectangle* pRectangle)
+{
+ if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
+ return;
+
+ if (pRectangle)
+ {
+ tools::Rectangle aRect(*pRectangle);
+ aRect.Move(-GetOutOffXPixel(), -GetOutOffYPixel());
+ Window::PixelInvalidate(&aRect);
+ }
+ else
+ {
+ Window::PixelInvalidate(nullptr);
+ }
+}
+
+void ScInputWindow::SetSizePixel( const Size& rNewSize )
+{
+ const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier();
+ if (pNotifier)
+ {
+ if (vcl::Window* pFrameWindowImpl = GetParent())
+ {
+ if (vcl::Window* pWorkWindow = pFrameWindowImpl->GetParent())
+ {
+ if (vcl::Window* pImplBorderWindow = pWorkWindow->GetParent())
+ {
+ Size aSize = pImplBorderWindow->GetSizePixel();
+ aSize.setWidth(rNewSize.getWidth());
+ pImplBorderWindow->SetSizePixel(aSize);
+ }
+ }
+ }
+ }
+
+ ToolBox::SetSizePixel(rNewSize);
+}
+
+void ScInputWindow::Resize()
+{
+ ToolBox::Resize();
+
+ Size aStartSize = GetSizePixel();
+ Size aSize = aStartSize;
+
+ auto nLines = mxTextWindow->GetNumLines();
+ //(-10) to allow margin between sidebar and formulabar
+ tools::Long margin = (comphelper::LibreOfficeKit::isActive()) ? 10 : 0;
+ Size aTextWindowSize(aSize.Width() - mxTextWindow->GetPosPixel().X() - LEFT_OFFSET - margin,
+ mxTextWindow->GetPixelHeightForLines(nLines));
+ mxTextWindow->SetSizePixel(aTextWindowSize);
+
+ int nTopOffset = 0;
+ if (nLines > 1)
+ {
+ // Initially there is 1 line and the edit is vertically centered in the toolbar
+ // Later, if expanded then the vertical position of the edit will remain at
+ // that initial position, so when calculating the overall size of the expanded
+ // toolbar we have to include that initial offset in order to not make
+ // the edit overlap the RESIZE_HOTSPOT_HEIGHT area so that dragging to resize
+ // is still possible.
+ int nNormalHeight = mxTextWindow->GetPixelHeightForLines(1);
+ int nInitialTopMargin = (mnStandardItemHeight - nNormalHeight) / 2;
+ if (nInitialTopMargin > 0)
+ nTopOffset = nInitialTopMargin;
+ }
+
+ // add empty space of RESIZE_HOTSPOT_HEIGHT so resize is possible when hovering there
+ aSize.setHeight(CalcWindowSizePixel().Height() + RESIZE_HOTSPOT_HEIGHT + nTopOffset);
+
+ if (aStartSize != aSize)
+ SetSizePixel(aSize);
+
+ Invalidate();
+}
+
+void ScInputWindow::NotifyLOKClient()
+{
+ if (comphelper::LibreOfficeKit::isActive() && !GetLOKNotifier() && mpViewShell)
+ SetLOKNotifier(mpViewShell);
+}
+
+void ScInputWindow::SetFuncString( const OUString& rString, bool bDoEdit )
+{
+ //! new method at ScModule to query if function autopilot is open
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
+ mxTextWindow->StartEditEngine();
+
+ ScModule* pScMod = SC_MOD();
+ if ( !pScMod->IsEditMode() )
+ return;
+
+ if ( bDoEdit )
+ mxTextWindow->TextGrabFocus();
+ mxTextWindow->SetTextString( rString );
+ EditView* pView = mxTextWindow->GetEditView();
+ if (!pView)
+ return;
+
+ sal_Int32 nLen = rString.getLength();
+
+ if ( nLen > 0 )
+ {
+ nLen--;
+ pView->SetSelection( ESelection( 0, nLen, 0, nLen ) );
+ }
+
+ pScMod->InputChanged(pView);
+ if ( bDoEdit )
+ SetOkCancelMode(); // Not the case if immediately followed by Enter/Cancel
+
+ pView->SetEditEngineUpdateLayout(true);
+}
+
+void ScInputWindow::SetPosString( const OUString& rStr )
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ aWndPos->SetPos( rStr );
+}
+
+void ScInputWindow::SetTextString( const OUString& rString )
+{
+ if (rString.getLength() <= 32767)
+ mxTextWindow->SetTextString(rString);
+ else
+ mxTextWindow->SetTextString(rString.copy(0, 32767));
+}
+
+void ScInputWindow::SetOkCancelMode()
+{
+ //! new method at ScModule to query if function autopilot is open
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
+
+ if (bIsOkCancelMode)
+ return;
+
+ EnableItem ( SID_INPUT_SUM, false );
+ EnableItem ( SID_INPUT_EQUAL, false );
+ HideItem ( SID_INPUT_SUM );
+ HideItem ( SID_INPUT_EQUAL );
+
+ ShowItem ( SID_INPUT_CANCEL, true );
+ ShowItem ( SID_INPUT_OK, true );
+ EnableItem ( SID_INPUT_CANCEL, true );
+ EnableItem ( SID_INPUT_OK, true );
+
+ bIsOkCancelMode = true;
+}
+
+void ScInputWindow::SetSumAssignMode()
+{
+ //! new method at ScModule to query if function autopilot is open
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
+
+ if (!bIsOkCancelMode)
+ return;
+
+ EnableItem ( SID_INPUT_CANCEL, false );
+ EnableItem ( SID_INPUT_OK, false );
+ HideItem ( SID_INPUT_CANCEL );
+ HideItem ( SID_INPUT_OK );
+
+ ShowItem ( SID_INPUT_SUM, true );
+ ShowItem ( SID_INPUT_EQUAL, true );
+ EnableItem ( SID_INPUT_SUM, true );
+ EnableItem ( SID_INPUT_EQUAL, true );
+
+ bIsOkCancelMode = false;
+
+ SetFormulaMode(false); // No editing -> no formula
+}
+
+void ScInputWindow::SetFormulaMode( bool bSet )
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ aWndPos->SetFormulaMode(bSet);
+ mxTextWindow->SetFormulaMode(bSet);
+}
+
+bool ScInputWindow::IsInputActive()
+{
+ return mxTextWindow->IsInputActive();
+}
+
+EditView* ScInputWindow::GetEditView()
+{
+ return mxTextWindow->GetEditView();
+}
+
+vcl::Window* ScInputWindow::GetEditWindow()
+{
+ return mxTextWindow;
+}
+
+Point ScInputWindow::GetCursorScreenPixelPos(bool bBelow)
+{
+ return mxTextWindow->GetCursorScreenPixelPos(bBelow);
+}
+
+void ScInputWindow::MakeDialogEditView()
+{
+ mxTextWindow->MakeDialogEditView();
+}
+
+void ScInputWindow::StopEditEngine( bool bAll )
+{
+ mxTextWindow->StopEditEngine( bAll );
+}
+
+void ScInputWindow::TextGrabFocus()
+{
+ mxTextWindow->TextGrabFocus();
+}
+
+void ScInputWindow::TextInvalidate()
+{
+ mxTextWindow->Invalidate();
+}
+
+void ScInputWindow::SwitchToTextWin()
+{
+ // used for shift-ctrl-F2
+
+ mxTextWindow->StartEditEngine();
+ if ( SC_MOD()->IsEditMode() )
+ {
+ mxTextWindow->TextGrabFocus();
+ EditView* pView = mxTextWindow->GetEditView();
+ if (pView)
+ {
+ sal_Int32 nPara = pView->GetEditEngine()->GetParagraphCount() ? ( pView->GetEditEngine()->GetParagraphCount() - 1 ) : 0;
+ sal_Int32 nLen = pView->GetEditEngine()->GetTextLen( nPara );
+ ESelection aSel( nPara, nLen, nPara, nLen );
+ pView->SetSelection( aSel ); // set cursor to end of text
+ }
+ }
+}
+
+void ScInputWindow::PosGrabFocus()
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ aWndPos->GrabFocus();
+}
+
+void ScInputWindow::EnableButtons( bool bEnable )
+{
+ // when enabling buttons, always also enable the input window itself
+ if ( bEnable && !IsEnabled() )
+ Enable();
+
+ EnableItem( SID_INPUT_FUNCTION, bEnable );
+ EnableItem( bIsOkCancelMode ? SID_INPUT_CANCEL : SID_INPUT_SUM, bEnable );
+ EnableItem( bIsOkCancelMode ? SID_INPUT_OK : SID_INPUT_EQUAL, bEnable );
+// Invalidate();
+}
+
+void ScInputWindow::NumLinesChanged()
+{
+ mxTextWindow->NumLinesChanged();
+}
+
+void ScInputWindow::StateChanged( StateChangedType nType )
+{
+ ToolBox::StateChanged( nType );
+
+ if ( nType == StateChangedType::InitShow ) Resize();
+}
+
+void ScInputWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( rDCEvt.GetType() == DataChangedEventType::SETTINGS && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ // update item images
+ SetItemImage(SID_INPUT_FUNCTION, Image(StockImage::Yes, RID_BMP_INPUT_FUNCTION));
+ if ( bIsOkCancelMode )
+ {
+ SetItemImage(SID_INPUT_CANCEL, Image(StockImage::Yes, RID_BMP_INPUT_CANCEL));
+ SetItemImage(SID_INPUT_OK, Image(StockImage::Yes, RID_BMP_INPUT_OK));
+ }
+ else
+ {
+ SetItemImage(SID_INPUT_SUM, Image(StockImage::Yes, RID_BMP_INPUT_SUM));
+ SetItemImage(SID_INPUT_EQUAL, Image(StockImage::Yes, RID_BMP_INPUT_EQUAL));
+ }
+ }
+
+ ToolBox::DataChanged( rDCEvt );
+}
+
+bool ScInputWindow::IsPointerAtResizePos()
+{
+ return GetOutputSizePixel().Height() - GetPointerPosPixel().Y() <= RESIZE_HOTSPOT_HEIGHT;
+}
+
+void ScInputWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ Point aPosPixel = GetPointerPosPixel();
+
+ ScInputBarGroup* pGroupBar = mxTextWindow.get();
+
+ if (bInResize || IsPointerAtResizePos())
+ SetPointer(PointerStyle::WindowSSize);
+ else
+ SetPointer(PointerStyle::Arrow);
+
+ if (bInResize)
+ {
+ // detect direction
+ tools::Long nResizeThreshold = tools::Long(TOOLBOX_WINDOW_HEIGHT * 0.7);
+ bool bResetPointerPos = false;
+
+ // Detect attempt to expand toolbar too much
+ if (aPosPixel.Y() >= mnMaxY)
+ {
+ bResetPointerPos = true;
+ aPosPixel.setY( mnMaxY );
+ } // or expanding down
+ else if (GetOutputSizePixel().Height() - aPosPixel.Y() < -nResizeThreshold)
+ {
+ pGroupBar->IncrementVerticalSize();
+ bResetPointerPos = true;
+ } // or shrinking up
+ else if ((GetOutputSizePixel().Height() - aPosPixel.Y()) > nResizeThreshold)
+ {
+ bResetPointerPos = true;
+ pGroupBar->DecrementVerticalSize();
+ }
+
+ if (bResetPointerPos)
+ {
+ aPosPixel.setY( GetOutputSizePixel().Height() );
+ SetPointerPosPixel(aPosPixel);
+ }
+ }
+
+ ToolBox::MouseMove(rMEvt);
+}
+
+void ScInputWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if (rMEvt.IsLeft())
+ {
+ if (IsPointerAtResizePos())
+ {
+ // Don't leave the mouse pointer leave *this* window
+ CaptureMouse();
+ bInResize = true;
+
+ // find the height of the gridwin, we don't want to be
+ // able to expand the toolbar too far so we need to
+ // calculate an upper limit
+ // I'd prefer to leave at least a single column header and a
+ // row but I don't know how to get that value in pixels.
+ // Use TOOLBOX_WINDOW_HEIGHT for the moment
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ mnMaxY = GetOutputSizePixel().Height() + (pViewSh->GetGridHeight(SC_SPLIT_TOP)
+ + pViewSh->GetGridHeight(SC_SPLIT_BOTTOM)) - TOOLBOX_WINDOW_HEIGHT;
+ }
+ }
+
+ ToolBox::MouseButtonDown( rMEvt );
+}
+void ScInputWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ ReleaseMouse();
+ if ( rMEvt.IsLeft() )
+ {
+ bInResize = false;
+ mnMaxY = 0;
+ }
+
+ ToolBox::MouseButtonUp( rMEvt );
+}
+
+void ScInputWindow::AutoSum( bool& bRangeFinder, bool& bSubTotal, OpCode eCode )
+{
+ ScModule* pScMod = SC_MOD();
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ if ( !pViewSh )
+ return;
+
+ const OUString aFormula = pViewSh->DoAutoSum(bRangeFinder, bSubTotal, eCode);
+ if ( aFormula.isEmpty() )
+ return;
+
+ SetFuncString( aFormula );
+ const sal_Int32 aOpen = aFormula.indexOf('(');
+ const sal_Int32 aLen = aFormula.getLength();
+ if (!(bRangeFinder && pScMod->IsEditMode()))
+ return;
+
+ ScInputHandler* pHdl = pScMod->GetInputHdl( pViewSh );
+ if ( !pHdl )
+ return;
+
+ pHdl->InitRangeFinder( aFormula );
+
+ //! SetSelection at the InputHandler?
+ //! Set bSelIsRef?
+ if ( aOpen != -1 && aLen > aOpen )
+ {
+ ESelection aSel( 0, aOpen + (bSubTotal ? 3 : 1), 0, aLen-1 );
+ EditView* pTableView = pHdl->GetTableView();
+ if ( pTableView )
+ pTableView->SetSelection( aSel );
+ EditView* pTopView = pHdl->GetTopView();
+ if ( pTopView )
+ pTopView->SetSelection( aSel );
+ }
+}
+
+ScInputBarGroup::ScInputBarGroup(vcl::Window* pParent, ScTabViewShell* pViewSh)
+ : InterimItemWindow(pParent, "modules/scalc/ui/inputbar.ui", "InputBar", true, reinterpret_cast<sal_uInt64>(pViewSh))
+ , mxBackground(m_xBuilder->weld_container("background"))
+ , mxTextWndGroup(new ScTextWndGroup(*this, pViewSh))
+ , mxButtonUp(m_xBuilder->weld_button("up"))
+ , mxButtonDown(m_xBuilder->weld_button("down"))
+{
+ InitControlBase(m_xContainer.get());
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ SetPaintTransparent(false);
+ SetBackground(rStyleSettings.GetFaceColor());
+
+ // match to bg used in ScTextWnd::SetDrawingArea to the margin area is drawn with the
+ // same desired bg
+ mxBackground->set_background(rStyleSettings.GetWindowColor());
+
+ mxButtonUp->connect_clicked(LINK(this, ScInputBarGroup, ClickHdl));
+ mxButtonDown->connect_clicked(LINK(this, ScInputBarGroup, ClickHdl));
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ mxButtonUp->set_tooltip_text(ScResId( SCSTR_QHELP_COLLAPSE_FORMULA));
+ mxButtonDown->set_tooltip_text(ScResId(SCSTR_QHELP_EXPAND_FORMULA));
+ }
+
+ int nHeight = mxTextWndGroup->GetPixelHeightForLines(1);
+ mxButtonUp->set_size_request(-1, nHeight);
+ mxButtonDown->set_size_request(-1, nHeight);
+
+ // disable the multiline toggle on the mobile phones
+ const SfxViewShell* pViewShell = SfxViewShell::Current();
+ if (!comphelper::LibreOfficeKit::isActive() || !(pViewShell && pViewShell->isLOKMobilePhone()))
+ mxButtonDown->show();
+
+ // tdf#154042 Use an initial height of one row so the Toolbar positions
+ // this in the same place regardless of how many rows it eventually shows
+ Size aSize(GetSizePixel().Width(), nHeight);
+ SetSizePixel(aSize);
+}
+
+Point ScInputBarGroup::GetCursorScreenPixelPos(bool bBelow)
+{
+ return mxTextWndGroup->GetCursorScreenPixelPos(bBelow);
+}
+
+ScInputBarGroup::~ScInputBarGroup()
+{
+ disposeOnce();
+}
+
+void ScInputBarGroup::dispose()
+{
+ mxTextWndGroup.reset();
+ mxButtonUp.reset();
+ mxButtonDown.reset();
+ mxBackground.reset();
+ InterimItemWindow::dispose();
+}
+
+void ScInputBarGroup::InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
+{
+ mxTextWndGroup->InsertAccessibleTextData(rTextData);
+}
+
+void ScInputBarGroup::RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
+{
+ mxTextWndGroup->RemoveAccessibleTextData(rTextData);
+}
+
+const OUString& ScInputBarGroup::GetTextString() const
+{
+ return mxTextWndGroup->GetTextString();
+}
+
+void ScInputBarGroup::SetTextString( const OUString& rString )
+{
+ mxTextWndGroup->SetTextString(rString);
+}
+
+void ScInputBarGroup::Resize()
+{
+ mxTextWndGroup->SetScrollPolicy();
+ InterimItemWindow::Resize();
+ TriggerToolboxLayout();
+}
+
+void ScInputBarGroup::StopEditEngine(bool bAll)
+{
+ mxTextWndGroup->StopEditEngine(bAll);
+}
+
+void ScInputBarGroup::StartEditEngine()
+{
+ mxTextWndGroup->StartEditEngine();
+}
+
+void ScInputBarGroup::MakeDialogEditView()
+{
+ mxTextWndGroup->MakeDialogEditView();
+}
+
+EditView* ScInputBarGroup::GetEditView() const
+{
+ return mxTextWndGroup->GetEditView();
+}
+
+bool ScInputBarGroup::HasEditView() const
+{
+ return mxTextWndGroup->HasEditView();
+}
+
+bool ScInputBarGroup::IsInputActive()
+{
+ return mxTextWndGroup->IsInputActive();
+}
+
+void ScInputBarGroup::SetFormulaMode(bool bSet)
+{
+ mxTextWndGroup->SetFormulaMode(bSet);
+}
+
+void ScInputBarGroup::IncrementVerticalSize()
+{
+ mxTextWndGroup->SetNumLines(mxTextWndGroup->GetNumLines() + 1);
+ TriggerToolboxLayout();
+}
+
+void ScInputBarGroup::DecrementVerticalSize()
+{
+ if (mxTextWndGroup->GetNumLines() > 1)
+ {
+ mxTextWndGroup->SetNumLines(mxTextWndGroup->GetNumLines() - 1);
+ TriggerToolboxLayout();
+ }
+}
+
+void ScInputWindow::MenuHdl(std::string_view command)
+{
+ if (command.empty())
+ return;
+
+ bool bSubTotal = false;
+ bool bRangeFinder = false;
+ OpCode eCode = ocSum;
+ if ( command == "sum" )
+ {
+ eCode = ocSum;
+ }
+ else if ( command == "average" )
+ {
+ eCode = ocAverage;
+ }
+ else if ( command == "max" )
+ {
+ eCode = ocMax;
+ }
+ else if ( command == "min" )
+ {
+ eCode = ocMin;
+ }
+ else if ( command == "count" )
+ {
+ eCode = ocCount;
+ }
+ else if ( command == "counta" )
+ {
+ eCode = ocCount2;
+ }
+ else if ( command == "product" )
+ {
+ eCode = ocProduct;
+ }
+ else if (command == "stdev")
+ {
+ eCode = ocStDev;
+ }
+ else if (command == "stdevp")
+ {
+ eCode = ocStDevP;
+ }
+ else if (command == "var")
+ {
+ eCode = ocVar;
+ }
+ else if (command == "varp")
+ {
+ eCode = ocVarP;
+ }
+
+ AutoSum( bRangeFinder, bSubTotal, eCode );
+}
+
+IMPL_LINK_NOARG(ScInputWindow, DropdownClickHdl, ToolBox *, void)
+{
+ ToolBoxItemId nCurID = GetCurItemId();
+ EndSelection();
+
+ if (nCurID == SID_INPUT_SUM)
+ {
+ tools::Rectangle aRect(GetItemRect(SID_INPUT_SUM));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "modules/scalc/ui/autosum.ui"));
+ std::unique_ptr<weld::Menu> xPopMenu(xBuilder->weld_menu("menu"));
+ MenuHdl(xPopMenu->popup_at_rect(pPopupParent, aRect));
+ }
+}
+
+IMPL_LINK_NOARG(ScInputBarGroup, ClickHdl, weld::Button&, void)
+{
+ if (mxTextWndGroup->GetNumLines() > 1)
+ mxTextWndGroup->SetNumLines(1);
+ else
+ mxTextWndGroup->SetNumLines(mxTextWndGroup->GetLastNumExpandedLines());
+
+ NumLinesChanged();
+}
+
+void ScInputBarGroup::NumLinesChanged()
+{
+ if (mxTextWndGroup->GetNumLines() > 1)
+ {
+ mxButtonDown->hide();
+ mxButtonUp->show();
+ mxTextWndGroup->SetLastNumExpandedLines(mxTextWndGroup->GetNumLines());
+ }
+ else
+ {
+ mxButtonUp->hide();
+ mxButtonDown->show();
+ }
+ TriggerToolboxLayout();
+
+ // Restore focus to input line(s) if necessary
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+ if ( pHdl && pHdl->IsTopMode() )
+ mxTextWndGroup->TextGrabFocus();
+}
+
+void ScInputBarGroup::TriggerToolboxLayout()
+{
+ vcl::Window *w=GetParent();
+ ScInputWindow &rParent = dynamic_cast<ScInputWindow&>(*w);
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+
+ if ( !pViewFrm )
+ return;
+
+ Reference< css::beans::XPropertySet > xPropSet( pViewFrm->GetFrame().GetFrameInterface(), UNO_QUERY );
+ Reference< css::frame::XLayoutManager > xLayoutManager;
+
+ if ( xPropSet.is() )
+ {
+ css::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
+ aValue >>= xLayoutManager;
+ }
+
+ if ( !xLayoutManager.is() )
+ return;
+
+ xLayoutManager->lock();
+ DataChangedEvent aFakeUpdate( DataChangedEventType::SETTINGS, nullptr, AllSettingsFlags::STYLE );
+
+ // this basically will trigger the repositioning of the
+ // items in the toolbar from ImplFormat ( which is controlled by
+ // mnWinHeight ) which in turn is updated in ImplCalcItem which is
+ // controlled by mbCalc. Additionally the ImplFormat above is
+ // controlled via mbFormat. It seems the easiest way to get these
+ // booleans set is to send in the fake event below.
+ rParent.DataChanged( aFakeUpdate);
+
+ // highest item in toolbar will have been calculated via the
+ // event above. Call resize on InputBar to pick up the height
+ // change
+ rParent.Resize();
+
+ // unlock relayouts the toolbars in the 4 quadrants
+ xLayoutManager->unlock();
+}
+
+void ScInputBarGroup::TextGrabFocus()
+{
+ mxTextWndGroup->TextGrabFocus();
+}
+
+constexpr tools::Long gnBorderWidth = (INPUTLINE_INSET_MARGIN + 1) * 2;
+constexpr tools::Long gnBorderHeight = INPUTLINE_INSET_MARGIN + 1;
+
+ScTextWndGroup::ScTextWndGroup(ScInputBarGroup& rParent, ScTabViewShell* pViewSh)
+ : mxTextWnd(new ScTextWnd(*this, pViewSh))
+ , mxScrollWin(rParent.GetBuilder().weld_scrolled_window("scrolledwindow", true))
+ , mxTextWndWin(new weld::CustomWeld(rParent.GetBuilder(), "sc_input_window", *mxTextWnd))
+ , mrParent(rParent)
+{
+ mxScrollWin->connect_vadjustment_changed(LINK(this, ScTextWndGroup, Impl_ScrollHdl));
+ if (comphelper::LibreOfficeKit::isActive())
+ ScInputHandler::LOKSendFormulabarUpdate(SfxViewShell::Current(), "", ESelection());
+}
+
+Point ScTextWndGroup::GetCursorScreenPixelPos(bool bBelow)
+{
+ Point aPos;
+ if (!HasEditView())
+ return aPos;
+ EditView* pEditView = GetEditView();
+ vcl::Cursor* pCur = pEditView->GetCursor();
+ if (!pCur)
+ return aPos;
+ Point aLogicPos = pCur->GetPos();
+ if (bBelow)
+ aLogicPos.AdjustY(pCur->GetHeight());
+ aPos = GetEditViewDevice().LogicToPixel(aLogicPos);
+ bool bRTL = mrParent.IsRTLEnabled();
+ if (bRTL)
+ aPos.setX(mxTextWnd->GetOutputSizePixel().Width() - aPos.X() + gnBorderWidth);
+ else
+ aPos.AdjustX(gnBorderWidth + 1);
+
+ return mrParent.OutputToScreenPixel(aPos);
+}
+
+ScTextWndGroup::~ScTextWndGroup()
+{
+}
+
+void ScTextWndGroup::InsertAccessibleTextData(ScAccessibleEditLineTextData& rTextData)
+{
+ mxTextWnd->InsertAccessibleTextData(rTextData);
+}
+
+EditView* ScTextWndGroup::GetEditView() const
+{
+ return mxTextWnd->GetEditView();
+}
+
+const OutputDevice& ScTextWndGroup::GetEditViewDevice() const
+{
+ return mxTextWnd->GetEditViewDevice();
+}
+
+tools::Long ScTextWndGroup::GetLastNumExpandedLines() const
+{
+ return mxTextWnd->GetLastNumExpandedLines();
+}
+
+void ScTextWndGroup::SetLastNumExpandedLines(tools::Long nLastExpandedLines)
+{
+ mxTextWnd->SetLastNumExpandedLines(nLastExpandedLines);
+}
+
+tools::Long ScTextWndGroup::GetNumLines() const
+{
+ return mxTextWnd->GetNumLines();
+}
+
+int ScTextWndGroup::GetPixelHeightForLines(tools::Long nLines)
+{
+ return mxTextWnd->GetPixelHeightForLines(nLines) + 2 * gnBorderHeight;
+}
+
+weld::ScrolledWindow& ScTextWndGroup::GetScrollWin()
+{
+ return *mxScrollWin;
+}
+
+const OUString& ScTextWndGroup::GetTextString() const
+{
+ return mxTextWnd->GetTextString();
+}
+
+bool ScTextWndGroup::HasEditView() const
+{
+ return mxTextWnd->HasEditView();
+}
+
+bool ScTextWndGroup::IsInputActive()
+{
+ return mxTextWnd->IsInputActive();
+}
+
+void ScTextWndGroup::MakeDialogEditView()
+{
+ mxTextWnd->MakeDialogEditView();
+}
+
+void ScTextWndGroup::RemoveAccessibleTextData(ScAccessibleEditLineTextData& rTextData)
+{
+ mxTextWnd->RemoveAccessibleTextData(rTextData);
+}
+
+void ScTextWndGroup::SetScrollPolicy()
+{
+ if (mxTextWnd->GetNumLines() > 2)
+ mxScrollWin->set_vpolicy(VclPolicyType::ALWAYS);
+ else
+ mxScrollWin->set_vpolicy(VclPolicyType::NEVER);
+}
+
+void ScTextWndGroup::SetNumLines(tools::Long nLines)
+{
+ mxTextWnd->SetNumLines(nLines);
+}
+
+void ScTextWndGroup::SetFormulaMode(bool bSet)
+{
+ mxTextWnd->SetFormulaMode(bSet);
+}
+
+void ScTextWndGroup::SetTextString(const OUString& rString)
+{
+ mxTextWnd->SetTextString(rString);
+}
+
+void ScTextWndGroup::StartEditEngine()
+{
+ mxTextWnd->StartEditEngine();
+}
+
+void ScTextWndGroup::StopEditEngine(bool bAll)
+{
+ mxTextWnd->StopEditEngine( bAll );
+}
+
+void ScTextWndGroup::TextGrabFocus()
+{
+ mxTextWnd->TextGrabFocus();
+}
+
+IMPL_LINK_NOARG(ScTextWndGroup, Impl_ScrollHdl, weld::ScrolledWindow&, void)
+{
+ mxTextWnd->DoScroll();
+}
+
+void ScTextWnd::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect )
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ Color aBgColor = rStyleSettings.GetWindowColor();
+ rRenderContext.SetBackground(aBgColor);
+
+ // tdf#137713 we rely on GetEditView creating it if it doesn't already exist so
+ // GetEditView() must be called unconditionally
+ if (EditView* pView = GetEditView())
+ {
+ if (mbInvalidate)
+ {
+ pView->Invalidate();
+ mbInvalidate = false;
+ }
+ }
+
+ if (comphelper::LibreOfficeKit::isActive() && m_xEditEngine)
+ {
+ // EditEngine/EditView works in twips logical coordinates, so set the device map-mode to twips before painting
+ // and use twips version of the painting area 'rRect'.
+ // Document zoom should not be included in this conversion.
+ tools::Rectangle aLogicRect = OutputDevice::LogicToLogic(rRect, MapMode(MapUnit::MapPixel), MapMode(MapUnit::MapTwip));
+ MapMode aOriginalMode = rRenderContext.GetMapMode();
+ rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
+ WeldEditView::Paint(rRenderContext, aLogicRect);
+ rRenderContext.SetMapMode(aOriginalMode);
+ }
+ else
+ WeldEditView::Paint(rRenderContext, rRect);
+}
+
+EditView* ScTextWnd::GetEditView() const
+{
+ if ( !m_xEditView )
+ const_cast<ScTextWnd&>(*this).InitEditEngine();
+ return m_xEditView.get();
+}
+
+bool ScTextWnd::HasEditView() const { return m_xEditView != nullptr; }
+
+const OutputDevice& ScTextWnd::GetEditViewDevice() const
+{
+ return EditViewOutputDevice();
+}
+
+int ScTextWnd::GetPixelHeightForLines(tools::Long nLines)
+{
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ return rDevice.LogicToPixel(Size(0, nLines * rDevice.GetTextHeight())).Height() + 1;
+}
+
+tools::Long ScTextWnd::GetNumLines() const
+{
+ ScViewData& rViewData = mpViewShell->GetViewData();
+ return rViewData.GetFormulaBarLines();
+}
+
+void ScTextWnd::SetNumLines(tools::Long nLines)
+{
+ ScViewData& rViewData = mpViewShell->GetViewData();
+ rViewData.SetFormulaBarLines(nLines);
+ if ( nLines > 1 )
+ {
+ // SetFormulaBarLines sanitizes the height, so get the sanitized value
+ mnLastExpandedLines = rViewData.GetFormulaBarLines();
+ Resize();
+ }
+}
+
+void ScTextWnd::Resize()
+{
+ if (m_xEditView)
+ {
+ Size aOutputSize = GetOutputSizePixel();
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ tools::Rectangle aOutputArea = rDevice.PixelToLogic( tools::Rectangle( Point(), aOutputSize ));
+ m_xEditView->SetOutputArea( aOutputArea );
+
+ // Don't leave an empty area at the bottom if we can move the text down.
+ tools::Long nMaxVisAreaTop = m_xEditEngine->GetTextHeight() - aOutputArea.GetHeight();
+ if (m_xEditView->GetVisArea().Top() > nMaxVisAreaTop)
+ {
+ m_xEditView->Scroll(0, m_xEditView->GetVisArea().Top() - nMaxVisAreaTop);
+ }
+
+ m_xEditEngine->SetPaperSize( rDevice.PixelToLogic( Size( aOutputSize.Width(), 10000 ) ) );
+ }
+
+ // skip WeldEditView's Resize();
+ weld::CustomWidgetController::Resize();
+
+ SetScrollBarRange();
+}
+
+int ScTextWnd::GetEditEngTxtHeight() const
+{
+ return m_xEditView ? m_xEditView->GetEditEngine()->GetTextHeight() : 0;
+}
+
+void ScTextWnd::SetScrollBarRange()
+{
+ if (!m_xEditView)
+ return;
+
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ Size aOutputSize = rDevice.GetOutputSize();
+
+ int nUpper = GetEditEngTxtHeight();
+ int nCurrentDocPos = m_xEditView->GetVisArea().Top();
+ int nStepIncrement = GetTextHeight();
+ int nPageIncrement = aOutputSize.Height();
+ int nPageSize = aOutputSize.Height();
+
+ /* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has
+ effectively...
+
+ lower = gtk_adjustment_get_lower
+ upper = gtk_adjustment_get_upper - gtk_adjustment_get_page_size
+
+ and requires that upper > lower or the deceleration animation never ends
+ */
+ nPageSize = std::min(nPageSize, nUpper);
+
+ weld::ScrolledWindow& rVBar = mrGroupBar.GetScrollWin();
+ rVBar.vadjustment_configure(nCurrentDocPos, 0, nUpper,
+ nStepIncrement, nPageIncrement, nPageSize);
+}
+
+void ScTextWnd::DoScroll()
+{
+ if (m_xEditView)
+ {
+ weld::ScrolledWindow& rVBar = mrGroupBar.GetScrollWin();
+ auto currentDocPos = m_xEditView->GetVisArea().Top();
+ auto nDiff = currentDocPos - rVBar.vadjustment_get_value();
+ // we expect SetScrollBarRange callback to be triggered by Scroll
+ // to set where we ended up
+ m_xEditView->Scroll(0, nDiff);
+ }
+}
+
+void ScTextWnd::StartEditEngine()
+{
+ // Don't activate if we're a modal dialog ourselves (Doc-modal dialog)
+ SfxObjectShell* pObjSh = SfxObjectShell::Current();
+ if ( pObjSh && pObjSh->IsInModalMode() )
+ return;
+
+ if ( !m_xEditView || !m_xEditEngine )
+ {
+ InitEditEngine();
+ }
+
+ ScInputHandler* pHdl = mpViewShell->GetInputHandler();
+ if (pHdl)
+ pHdl->SetMode(SC_INPUT_TOP, nullptr, static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get()));
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
+}
+
+static void lcl_ExtendEditFontAttribs( SfxItemSet& rSet )
+{
+ const SfxPoolItem& rFontItem = rSet.Get( EE_CHAR_FONTINFO );
+ std::unique_ptr<SfxPoolItem> pNewItem(rFontItem.Clone());
+ pNewItem->SetWhich(EE_CHAR_FONTINFO_CJK);
+ rSet.Put( *pNewItem );
+ pNewItem->SetWhich(EE_CHAR_FONTINFO_CTL);
+ rSet.Put( *pNewItem );
+ const SfxPoolItem& rHeightItem = rSet.Get( EE_CHAR_FONTHEIGHT );
+ pNewItem.reset(rHeightItem.Clone());
+ pNewItem->SetWhich(EE_CHAR_FONTHEIGHT_CJK);
+ rSet.Put( *pNewItem );
+ pNewItem->SetWhich(EE_CHAR_FONTHEIGHT_CTL);
+ rSet.Put( *pNewItem );
+ const SfxPoolItem& rWeightItem = rSet.Get( EE_CHAR_WEIGHT );
+ pNewItem.reset(rWeightItem.Clone());
+ pNewItem->SetWhich(EE_CHAR_WEIGHT_CJK);
+ rSet.Put( *pNewItem );
+ pNewItem->SetWhich(EE_CHAR_WEIGHT_CTL);
+ rSet.Put( *pNewItem );
+ const SfxPoolItem& rItalicItem = rSet.Get( EE_CHAR_ITALIC );
+ pNewItem.reset(rItalicItem.Clone());
+ pNewItem->SetWhich(EE_CHAR_ITALIC_CJK);
+ rSet.Put( *pNewItem );
+ pNewItem->SetWhich(EE_CHAR_ITALIC_CTL);
+ rSet.Put( *pNewItem );
+ const SfxPoolItem& rLangItem = rSet.Get( EE_CHAR_LANGUAGE );
+ pNewItem.reset(rLangItem.Clone());
+ pNewItem->SetWhich(EE_CHAR_LANGUAGE_CJK);
+ rSet.Put( *pNewItem );
+ pNewItem->SetWhich(EE_CHAR_LANGUAGE_CTL);
+ rSet.Put( *pNewItem );
+}
+
+static void lcl_ModifyRTLDefaults( SfxItemSet& rSet )
+{
+ rSet.Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
+
+ // always using rtl writing direction would break formulas
+ //rSet.Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) );
+
+ // PaperSize width is limited to USHRT_MAX in RTL mode (because of EditEngine's
+ // sal_uInt16 values in EditLine), so the text may be wrapped and line spacing must be
+ // increased to not see the beginning of the next line.
+ SvxLineSpacingItem aItem( LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL );
+ aItem.SetPropLineSpace( 200 );
+ rSet.Put( aItem );
+}
+
+static void lcl_ModifyRTLVisArea( EditView* pEditView )
+{
+ tools::Rectangle aVisArea = pEditView->GetVisArea();
+ Size aPaper = pEditView->GetEditEngine()->GetPaperSize();
+ tools::Long nDiff = aPaper.Width() - aVisArea.Right();
+ aVisArea.AdjustLeft(nDiff );
+ aVisArea.AdjustRight(nDiff );
+ pEditView->SetVisArea(aVisArea);
+}
+
+void ScTextWnd::InitEditEngine()
+{
+ std::unique_ptr<ScFieldEditEngine> pNew;
+ ScDocShell* pDocSh = nullptr;
+ if ( mpViewShell )
+ {
+ pDocSh = mpViewShell->GetViewData().GetDocShell();
+ ScDocument& rDoc = mpViewShell->GetViewData().GetDocument();
+ pNew = std::make_unique<ScFieldEditEngine>(&rDoc, rDoc.GetEnginePool(), rDoc.GetEditPool());
+ }
+ else
+ pNew = std::make_unique<ScFieldEditEngine>(nullptr, EditEngine::CreatePool().get(), nullptr, true);
+ pNew->SetExecuteURL( false );
+ m_xEditEngine = std::move(pNew);
+
+ Size barSize = GetOutputSizePixel();
+ m_xEditEngine->SetUpdateLayout( false );
+ m_xEditEngine->SetPaperSize( GetDrawingArea()->get_ref_device().PixelToLogic(Size(barSize.Width(),10000)) );
+ m_xEditEngine->SetWordDelimiters(
+ ScEditUtil::ModifyDelimiters( m_xEditEngine->GetWordDelimiters() ) );
+ m_xEditEngine->SetReplaceLeadingSingleQuotationMark( false );
+
+ UpdateAutoCorrFlag();
+
+ {
+ auto pSet = std::make_unique<SfxItemSet>( m_xEditEngine->GetEmptyItemSet() );
+ EditEngine::SetFontInfoInItemSet( *pSet, aTextFont );
+ lcl_ExtendEditFontAttribs( *pSet );
+ // turn off script spacing to match DrawText output
+ pSet->Put( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) );
+ if ( bIsRTL )
+ lcl_ModifyRTLDefaults( *pSet );
+ static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetDefaults( std::move(pSet) );
+ }
+
+ // If the Cell contains URLFields, they need to be taken over into the entry row,
+ // or else the position is not correct anymore
+ bool bFilled = false;
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+ if ( pHdl ) //! Test if it's the right InputHdl?
+ bFilled = pHdl->GetTextAndFields(static_cast<ScEditEngineDefaulter&>(*m_xEditEngine));
+
+ m_xEditEngine->SetUpdateLayout( true );
+
+ // aString is the truth ...
+ if (bFilled && m_xEditEngine->GetText() == aString)
+ Invalidate(); // Repaint for (filled) Field
+ else
+ static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetTextCurrentDefaults(aString); // At least the right text then
+
+ m_xEditView = std::make_unique<EditView>(m_xEditEngine.get(), nullptr);
+
+ // we get cursor, selection etc. messages from the VCL/window layer
+ // otherwise these are injected into the document causing confusion.
+ m_xEditView->SuppressLOKMessages(true);
+
+ m_xEditView->setEditViewCallbacks(this);
+ m_xEditView->SetInsertMode(bIsInsertMode);
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ Color aBgColor = rStyleSettings.GetWindowColor();
+ m_xEditView->SetBackgroundColor(aBgColor);
+
+ if (pAcc)
+ {
+ pAcc->InitAcc(nullptr, m_xEditView.get(),
+ ScResId(STR_ACC_EDITLINE_NAME),
+ ScResId(STR_ACC_EDITLINE_DESCR));
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ m_xEditView->RegisterViewShell(mpViewShell);
+
+ // Text from Clipboard is taken over as ASCII in a single row
+ EVControlBits n = m_xEditView->GetControlWord();
+ m_xEditView->SetControlWord( n | EVControlBits::SINGLELINEPASTE );
+
+ m_xEditEngine->InsertView( m_xEditView.get(), EE_APPEND );
+
+ Resize();
+
+ if ( bIsRTL )
+ lcl_ModifyRTLVisArea( m_xEditView.get() );
+
+ m_xEditEngine->SetModifyHdl(LINK(this, ScTextWnd, ModifyHdl));
+ m_xEditEngine->SetStatusEventHdl(LINK(this, ScTextWnd, EditStatusHdl));
+
+ if (!maAccTextDatas.empty())
+ maAccTextDatas.back()->StartEdit();
+
+ // as long as EditEngine and DrawText sometimes differ for CTL text,
+ // repaint now to have the EditEngine's version visible
+ if (pDocSh)
+ {
+ ScDocument& rDoc = pDocSh->GetDocument(); // any document
+ SvtScriptType nScript = rDoc.GetStringScriptType( aString );
+ if ( nScript & SvtScriptType::COMPLEX )
+ Invalidate();
+ }
+}
+
+ScTextWnd::ScTextWnd(ScTextWndGroup& rParent, ScTabViewShell* pViewSh) :
+ bIsRTL(AllSettings::GetLayoutRTL()),
+ bIsInsertMode(true),
+ bFormulaMode (false),
+ bInputMode (false),
+ mpViewShell(pViewSh),
+ mrGroupBar(rParent),
+ mnLastExpandedLines(INPUTWIN_MULTILINES),
+ mbInvalidate(false)
+{
+}
+
+ScTextWnd::~ScTextWnd()
+{
+ while (!maAccTextDatas.empty()) {
+ maAccTextDatas.back()->Dispose();
+ }
+}
+
+bool ScTextWnd::MouseMove( const MouseEvent& rMEvt )
+{
+ return m_xEditView && m_xEditView->MouseMove(rMEvt);
+}
+
+bool ScTextWnd::CanFocus() const
+{
+ return SC_MOD()->IsEditMode();
+}
+
+bool ScTextWnd::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if (!HasFocus())
+ {
+ StartEditEngine();
+ if (CanFocus())
+ TextGrabFocus();
+ }
+
+ bool bClickOnSelection = false;
+ if (m_xEditView)
+ {
+ m_xEditView->SetEditEngineUpdateLayout( true );
+ bClickOnSelection = m_xEditView->IsSelectionAtPoint(rMEvt.GetPosPixel());
+ }
+ if (!bClickOnSelection)
+ {
+ rtl::Reference<TransferDataContainer> xTransferable(new TransferDataContainer);
+ GetDrawingArea()->enable_drag_source(xTransferable, DND_ACTION_NONE);
+ }
+ else
+ {
+ rtl::Reference<TransferDataContainer> xTransferable(m_xHelper);
+ GetDrawingArea()->enable_drag_source(xTransferable, DND_ACTION_COPY);
+ }
+ return WeldEditView::MouseButtonDown(rMEvt);
+}
+
+bool ScTextWnd::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ bool bRet = WeldEditView::MouseButtonUp(rMEvt);
+ if (bRet)
+ {
+ if ( rMEvt.IsMiddle() &&
+ Application::GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection )
+ {
+ // EditView may have pasted from selection
+ SC_MOD()->InputChanged( m_xEditView.get() );
+ }
+ else
+ SC_MOD()->InputSelection( m_xEditView.get() );
+ }
+ return bRet;
+}
+
+bool ScTextWnd::Command( const CommandEvent& rCEvt )
+{
+ bool bConsumed = false;
+
+ bInputMode = true;
+ CommandEventId nCommand = rCEvt.GetCommand();
+ if (m_xEditView)
+ {
+ ScModule* pScMod = SC_MOD();
+ ScTabViewShell* pStartViewSh = ScTabViewShell::GetActiveViewShell();
+
+ // don't modify the font defaults here - the right defaults are
+ // already set in StartEditEngine when the EditEngine is created
+
+ // Prevent that the EditView is lost when switching between Views
+ pScMod->SetInEditCommand( true );
+ m_xEditView->Command( rCEvt );
+ pScMod->SetInEditCommand( false );
+
+ // CommandEventId::StartDrag does not mean by far that the content was actually changed,
+ // so don't trigger an InputChanged.
+ //! Detect if dragged with Move or forbid Drag&Move somehow
+
+ if ( nCommand == CommandEventId::StartDrag )
+ {
+ // Is dragged onto another View?
+ ScTabViewShell* pEndViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pEndViewSh != pStartViewSh && pStartViewSh != nullptr )
+ {
+ ScViewData& rViewData = pStartViewSh->GetViewData();
+ ScInputHandler* pHdl = pScMod->GetInputHdl( pStartViewSh );
+ if ( pHdl && rViewData.HasEditView( rViewData.GetActivePart() ) )
+ {
+ pHdl->CancelHandler();
+ rViewData.GetView()->ShowCursor(); // Missing for KillEditView, due to being inactive
+ }
+ }
+ }
+ else if ( nCommand == CommandEventId::EndExtTextInput )
+ {
+ if (bFormulaMode)
+ {
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+ if (pHdl)
+ pHdl->InputCommand(rCEvt);
+ }
+ }
+ else if ( nCommand == CommandEventId::CursorPos )
+ {
+ // don't call InputChanged for CommandEventId::CursorPos
+ }
+ else if ( nCommand == CommandEventId::InputLanguageChange )
+ {
+ // #i55929# Font and font size state depends on input language if nothing is selected,
+ // so the slots have to be invalidated when the input language is changed.
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ {
+ SfxBindings& rBindings = pViewFrm->GetBindings();
+ rBindings.Invalidate( SID_ATTR_CHAR_FONT );
+ rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ }
+ }
+ else if ( nCommand == CommandEventId::ContextMenu )
+ {
+ bConsumed = true;
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ {
+ Point aPos = rCEvt.GetMousePosPixel();
+ if (!rCEvt.IsMouseEvent())
+ {
+ Size aSize = GetOutputSizePixel();
+ aPos = Point(aSize.Width() / 2, aSize.Height() / 2);
+ }
+ if (IsMouseCaptured())
+ ReleaseMouse();
+ pViewFrm->GetDispatcher()->ExecutePopup("formulabar", &mrGroupBar.GetVclParent(), &aPos);
+ }
+ }
+ else if ( nCommand == CommandEventId::Wheel )
+ {
+ //don't call InputChanged for CommandEventId::Wheel
+ }
+ else if ( nCommand == CommandEventId::Swipe )
+ {
+ //don't call InputChanged for CommandEventId::Swipe
+ }
+ else if ( nCommand == CommandEventId::LongPress )
+ {
+ //don't call InputChanged for CommandEventId::LongPress
+ }
+ else if ( nCommand == CommandEventId::ModKeyChange )
+ {
+ //pass alt press/release to parent impl
+ }
+ else
+ SC_MOD()->InputChanged( m_xEditView.get() );
+ }
+
+ if ( comphelper::LibreOfficeKit::isActive() && nCommand == CommandEventId::CursorPos )
+ {
+ // LOK uses this to setup caret position because drawingarea is replaced
+ // with text input field, it sends logical caret position (start, end) not pixels
+
+ StartEditEngine();
+ TextGrabFocus();
+
+ if (!m_xEditView)
+ return true;
+
+ Point aSelectionStartEnd = rCEvt.GetMousePosPixel();
+ m_xEditView->SetSelection(ESelection(0, aSelectionStartEnd.X(),
+ 0, aSelectionStartEnd.Y()));
+
+ SC_MOD()->InputSelection( m_xEditView.get() );
+
+ bConsumed = true;
+ }
+
+ bInputMode = false;
+
+ return bConsumed;
+}
+
+bool ScTextWnd::StartDrag()
+{
+ // tdf#145248 don't start a drag if actively selecting
+ if (m_xEditView && !m_xEditEngine->IsInSelectionMode())
+ {
+ OUString sSelection = m_xEditView->GetSelected();
+ m_xHelper->SetData(sSelection);
+ return sSelection.isEmpty();
+ }
+ return true;
+}
+
+bool ScTextWnd::KeyInput(const KeyEvent& rKEvt)
+{
+ bool bUsed = true;
+ bInputMode = true;
+ if (!SC_MOD()->InputKeyEvent( rKEvt ))
+ {
+ bUsed = false;
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pViewSh )
+ bUsed = pViewSh->SfxKeyInput(rKEvt); // Only accelerators, no input
+ }
+ bInputMode = false;
+ return bUsed;
+}
+
+void ScTextWnd::GetFocus()
+{
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pViewSh )
+ pViewSh->SetFormShellAtTop( false ); // focus in input line -> FormShell no longer on top
+ WeldEditView::GetFocus();
+}
+
+void ScTextWnd::SetFormulaMode( bool bSet )
+{
+ if ( bSet != bFormulaMode )
+ {
+ bFormulaMode = bSet;
+ UpdateAutoCorrFlag();
+ }
+}
+
+void ScTextWnd::UpdateAutoCorrFlag()
+{
+ if (m_xEditEngine)
+ {
+ EEControlBits nControl = m_xEditEngine->GetControlWord();
+ EEControlBits nOld = nControl;
+ if ( bFormulaMode )
+ nControl &= ~EEControlBits::AUTOCORRECT; // No AutoCorrect in Formulas
+ else
+ nControl |= EEControlBits::AUTOCORRECT; // Else do enable it
+
+ if ( nControl != nOld )
+ m_xEditEngine->SetControlWord( nControl );
+ }
+}
+
+void ScTextWnd::EditViewScrollStateChange()
+{
+ // editengine height has changed or editview scroll pos has changed
+ SetScrollBarRange();
+}
+
+IMPL_LINK_NOARG(ScTextWnd, ModifyHdl, LinkParamNone*, void)
+{
+ if (m_xEditView && !bInputMode)
+ {
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+
+ // Use the InputHandler's InOwnChange flag to prevent calling InputChanged
+ // while an InputHandler method is modifying the EditEngine content
+
+ if ( pHdl && !pHdl->IsInOwnChange() )
+ pHdl->InputChanged( m_xEditView.get(), true ); // #i20282# InputChanged must know if called from modify handler
+ }
+}
+
+IMPL_LINK_NOARG(ScTextWnd, EditStatusHdl, EditStatus&, void)
+{
+ SetScrollBarRange();
+ DoScroll();
+ Invalidate();
+}
+
+void ScTextWnd::StopEditEngine( bool bAll )
+{
+ if (!m_xEditEngine)
+ return;
+
+ if (m_xEditView)
+ {
+ if (!maAccTextDatas.empty())
+ maAccTextDatas.back()->EndEdit();
+
+ ScModule* pScMod = SC_MOD();
+
+ if (!bAll)
+ pScMod->InputSelection( m_xEditView.get() );
+ aString = m_xEditEngine->GetText();
+ bIsInsertMode = m_xEditView->IsInsertMode();
+ bool bSelection = m_xEditView->HasSelection();
+ m_xEditEngine->SetStatusEventHdl(Link<EditStatus&, void>());
+ m_xEditEngine->SetModifyHdl(Link<LinkParamNone*,void>());
+ m_xEditView.reset();
+ m_xEditEngine.reset();
+
+ ScInputHandler* pHdl = mpViewShell->GetInputHandler();
+
+ if (pHdl && pHdl->IsEditMode() && !bAll)
+ pHdl->SetMode(SC_INPUT_TABLE);
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
+
+ if (bSelection)
+ Invalidate(); // So that the Selection is not left there
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // Clear
+ std::vector<ReferenceMark> aReferenceMarks;
+ ScInputHandler::SendReferenceMarks( mpViewShell, aReferenceMarks );
+ }
+}
+
+static sal_Int32 findFirstNonMatchingChar(const OUString& rStr1, const OUString& rStr2)
+{
+ // Search the string for unmatching chars
+ const sal_Unicode* pStr1 = rStr1.getStr();
+ const sal_Unicode* pStr2 = rStr2.getStr();
+ sal_Int32 i = 0;
+ while ( i < rStr1.getLength() )
+ {
+ // Abort on the first unmatching char
+ if ( *pStr1 != *pStr2 )
+ return i;
+ ++pStr1;
+ ++pStr2;
+ ++i;
+ }
+
+ return i;
+}
+
+void ScTextWnd::SetTextString( const OUString& rNewString )
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ESelection aSel = m_xEditView ? m_xEditView->GetSelection() : ESelection();
+ ScInputHandler::LOKSendFormulabarUpdate(SfxViewShell::Current(), rNewString, aSel);
+ }
+
+ // Ideally it would be best to create on demand the EditEngine/EditView here, but... for
+ // the initialisation scenario where a cell is first clicked on we end up with the text in the
+ // inputbar window scrolled to the bottom if we do that here ( because the tableview and topview
+ // are synced I guess ).
+ // should fix that I suppose :-/ need to look a bit further into that
+ mbInvalidate = true; // ensure next Paint ( that uses editengine ) call will call Invalidate first
+
+ if ( rNewString != aString )
+ {
+ bInputMode = true;
+
+ // Find position of the change, only paint the rest
+ if (!m_xEditEngine)
+ {
+ bool bPaintAll = GetNumLines() > 1 || bIsRTL;
+ if (!bPaintAll)
+ {
+ // test if CTL script type is involved
+ SvtScriptType nOldScript = SvtScriptType::NONE;
+ SvtScriptType nNewScript = SvtScriptType::NONE;
+ SfxObjectShell* pObjSh = SfxObjectShell::Current();
+ if ( auto pDocShell = dynamic_cast<ScDocShell*>( pObjSh) )
+ {
+ // any document can be used (used only for its break iterator)
+ ScDocument& rDoc = pDocShell->GetDocument();
+ nOldScript = rDoc.GetStringScriptType( aString );
+ nNewScript = rDoc.GetStringScriptType( rNewString );
+ }
+ bPaintAll = ( nOldScript & SvtScriptType::COMPLEX ) || ( nNewScript & SvtScriptType::COMPLEX );
+ }
+
+ if ( bPaintAll )
+ {
+ // In multiline mode, or if CTL is involved, the whole text has to be redrawn
+ Invalidate();
+ }
+ else
+ {
+ tools::Long nTextSize = 0;
+ sal_Int32 nDifPos;
+ if (rNewString.getLength() > aString.getLength())
+ nDifPos = findFirstNonMatchingChar(rNewString, aString);
+ else
+ nDifPos = findFirstNonMatchingChar(aString, rNewString);
+
+ tools::Long nSize1 = GetTextWidth(aString);
+ tools::Long nSize2 = GetTextWidth(rNewString);
+ if ( nSize1>0 && nSize2>0 )
+ nTextSize = std::max( nSize1, nSize2 );
+ else
+ nTextSize = GetOutputSizePixel().Width(); // Overflow
+
+ Point aLogicStart = GetDrawingArea()->get_ref_device().PixelToLogic(Point(0,0));
+ tools::Long nStartPos = aLogicStart.X();
+ tools::Long nInvPos = nStartPos;
+ if (nDifPos)
+ nInvPos += GetTextWidth(aString.copy(0,nDifPos));
+
+ Invalidate(tools::Rectangle(nInvPos, 0, nStartPos+nTextSize, GetOutputSizePixel().Height() - 1));
+ }
+ }
+ else
+ {
+ static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetTextCurrentDefaults(rNewString);
+ }
+
+ aString = rNewString;
+
+ if (!maAccTextDatas.empty())
+ maAccTextDatas.back()->TextChanged();
+
+ bInputMode = false;
+ }
+
+ SetScrollBarRange();
+ DoScroll();
+}
+
+const OUString& ScTextWnd::GetTextString() const
+{
+ return aString;
+}
+
+bool ScTextWnd::IsInputActive()
+{
+ return HasFocus();
+}
+
+void ScTextWnd::MakeDialogEditView()
+{
+ if ( m_xEditView ) return;
+
+ std::unique_ptr<ScFieldEditEngine> pNew;
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pViewSh )
+ {
+ ScDocument& rDoc = pViewSh->GetViewData().GetDocument();
+ pNew = std::make_unique<ScFieldEditEngine>(&rDoc, rDoc.GetEnginePool(), rDoc.GetEditPool());
+ }
+ else
+ pNew = std::make_unique<ScFieldEditEngine>(nullptr, EditEngine::CreatePool().get(), nullptr, true);
+ pNew->SetExecuteURL( false );
+ m_xEditEngine = std::move(pNew);
+
+ const bool bPrevUpdateLayout = m_xEditEngine->SetUpdateLayout( false );
+ m_xEditEngine->SetWordDelimiters( m_xEditEngine->GetWordDelimiters() + "=" );
+ m_xEditEngine->SetPaperSize( Size( bIsRTL ? USHRT_MAX : THESIZE, 300 ) );
+
+ auto pSet = std::make_unique<SfxItemSet>( m_xEditEngine->GetEmptyItemSet() );
+ EditEngine::SetFontInfoInItemSet( *pSet, aTextFont );
+ lcl_ExtendEditFontAttribs( *pSet );
+ if ( bIsRTL )
+ lcl_ModifyRTLDefaults( *pSet );
+ static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetDefaults( std::move(pSet) );
+ m_xEditEngine->SetUpdateLayout( bPrevUpdateLayout );
+
+ m_xEditView = std::make_unique<EditView>(m_xEditEngine.get(), nullptr);
+ m_xEditView->setEditViewCallbacks(this);
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ Color aBgColor = rStyleSettings.GetWindowColor();
+ m_xEditView->SetBackgroundColor(aBgColor);
+
+ if (pAcc)
+ {
+ pAcc->InitAcc(nullptr, m_xEditView.get(),
+ ScResId(STR_ACC_EDITLINE_NAME),
+ ScResId(STR_ACC_EDITLINE_DESCR));
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ m_xEditView->RegisterViewShell(mpViewShell);
+ m_xEditEngine->InsertView( m_xEditView.get(), EE_APPEND );
+
+ Resize();
+
+ if ( bIsRTL )
+ lcl_ModifyRTLVisArea( m_xEditView.get() );
+
+ if (!maAccTextDatas.empty())
+ maAccTextDatas.back()->StartEdit();
+}
+
+void ScTextWnd::ImplInitSettings()
+{
+ bIsRTL = AllSettings::GetLayoutRTL();
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ Color aBgColor= rStyleSettings.GetWindowColor();
+ Color aTxtColor= rStyleSettings.GetWindowTextColor();
+
+ aTextFont.SetFillColor ( aBgColor );
+ aTextFont.SetColor (aTxtColor);
+ Invalidate();
+}
+
+void ScTextWnd::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ // bypass WeldEditView::SetDrawingArea
+ weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
+
+ // set cursor
+ pDrawingArea->set_cursor(PointerStyle::Text);
+
+ // initialize dnd, deliberately just a simple string so
+ // we don't transfer the happenstance formatting in
+ // the input line
+ m_xHelper.set(new svt::OStringTransferable(OUString()));
+ rtl::Reference<TransferDataContainer> xHelper(m_xHelper);
+ SetDragDataTransferrable(xHelper, DND_ACTION_COPY);
+
+ OutputDevice& rDevice = pDrawingArea->get_ref_device();
+ pDrawingArea->set_margin_start(gnBorderWidth);
+ pDrawingArea->set_margin_end(gnBorderWidth);
+ // leave 1 for the width of the scrolledwindow border
+ pDrawingArea->set_margin_top(gnBorderHeight - 1);
+ pDrawingArea->set_margin_bottom(gnBorderHeight - 1);
+
+ // always use application font, so a font with cjk chars can be installed
+ vcl::Font aAppFont = Application::GetSettings().GetStyleSettings().GetAppFont();
+ weld::SetPointFont(rDevice, aAppFont);
+
+ aTextFont = rDevice.GetFont();
+ Size aFontSize = aTextFont.GetFontSize();
+ aTextFont.SetFontSize(rDevice.PixelToLogic(aFontSize, MapMode(MapUnit::MapTwip)));
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ Color aBgColor = rStyleSettings.GetWindowColor();
+ Color aTxtColor = rStyleSettings.GetWindowTextColor();
+
+ aTextFont.SetTransparent(true);
+ aTextFont.SetFillColor(aBgColor);
+ aTextFont.SetColor(aTxtColor);
+ aTextFont.SetWeight(WEIGHT_NORMAL);
+
+ Size aSize(1, GetPixelHeightForLines(1));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+
+ rDevice.SetBackground(aBgColor);
+ rDevice.SetLineColor(COL_BLACK);
+ rDevice.SetMapMode(MapMode(MapUnit::MapTwip));
+ rDevice.SetFont(aTextFont);
+
+ EnableRTL(false); // EditEngine can't be used with VCL EnableRTL
+}
+
+css::uno::Reference< css::accessibility::XAccessible > ScTextWnd::CreateAccessible()
+{
+ pAcc = new ScAccessibleEditLineObject(this);
+ return pAcc;
+}
+
+void ScTextWnd::InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
+{
+ OSL_ENSURE( ::std::find( maAccTextDatas.begin(), maAccTextDatas.end(), &rTextData ) == maAccTextDatas.end(),
+ "ScTextWnd::InsertAccessibleTextData - passed object already registered" );
+ maAccTextDatas.push_back( &rTextData );
+}
+
+void ScTextWnd::RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
+{
+ AccTextDataVector::iterator aEnd = maAccTextDatas.end();
+ AccTextDataVector::iterator aIt = ::std::find( maAccTextDatas.begin(), aEnd, &rTextData );
+ OSL_ENSURE( aIt != aEnd, "ScTextWnd::RemoveAccessibleTextData - passed object not registered" );
+ if( aIt != aEnd )
+ maAccTextDatas.erase( aIt );
+}
+
+void ScTextWnd::StyleUpdated()
+{
+ ImplInitSettings();
+ CustomWidgetController::Invalidate();
+}
+
+void ScTextWnd::TextGrabFocus()
+{
+ GrabFocus();
+}
+
+// Position window
+ScPosWnd::ScPosWnd(vcl::Window* pParent)
+ : InterimItemWindow(pParent, "modules/scalc/ui/posbox.ui", "PosBox")
+ , m_xWidget(m_xBuilder->weld_combo_box("pos_window"))
+ , m_nAsyncGetFocusId(nullptr)
+ , nTipVisible(nullptr)
+ , bFormulaMode(false)
+{
+ InitControlBase(m_xWidget.get());
+
+ // Use calculation according to tdf#132338 to align combobox width to width of fontname combobox within formatting toolbar;
+ // formatting toolbar is placed above formulabar when using multiple toolbars typically
+
+ m_xWidget->set_entry_width_chars(1);
+ Size aSize(LogicToPixel(Size(POSITION_COMBOBOX_WIDTH * 4, 0), MapMode(MapUnit::MapAppFont)));
+ m_xWidget->set_size_request(aSize.Width(), -1);
+ SetSizePixel(m_xContainer->get_preferred_size());
+
+ FillRangeNames();
+
+ StartListening( *SfxGetpApp() ); // For Navigator rangename updates
+
+ m_xWidget->connect_key_press(LINK(this, ScPosWnd, KeyInputHdl));
+ m_xWidget->connect_entry_activate(LINK(this, ScPosWnd, ActivateHdl));
+ m_xWidget->connect_changed(LINK(this, ScPosWnd, ModifyHdl));
+ m_xWidget->connect_focus_in(LINK(this, ScPosWnd, FocusInHdl));
+ m_xWidget->connect_focus_out(LINK(this, ScPosWnd, FocusOutHdl));
+}
+
+ScPosWnd::~ScPosWnd()
+{
+ disposeOnce();
+}
+
+void ScPosWnd::dispose()
+{
+ EndListening( *SfxGetpApp() );
+
+ HideTip();
+
+ if (m_nAsyncGetFocusId)
+ {
+ Application::RemoveUserEvent(m_nAsyncGetFocusId);
+ m_nAsyncGetFocusId = nullptr;
+ }
+ m_xWidget.reset();
+
+ InterimItemWindow::dispose();
+}
+
+void ScPosWnd::SetFormulaMode( bool bSet )
+{
+ if ( bSet != bFormulaMode )
+ {
+ bFormulaMode = bSet;
+
+ if ( bSet )
+ FillFunctions();
+ else
+ FillRangeNames();
+
+ HideTip();
+ }
+}
+
+void ScPosWnd::SetPos( const OUString& rPosStr )
+{
+ if ( aPosStr != rPosStr )
+ {
+ aPosStr = rPosStr;
+ m_xWidget->set_entry_text(aPosStr);
+ }
+}
+
+// static
+OUString ScPosWnd::createLocalRangeName(std::u16string_view rName, std::u16string_view rTableName)
+{
+ return OUString::Concat(rName) + " (" + rTableName + ")";
+}
+
+void ScPosWnd::FillRangeNames()
+{
+ m_xWidget->clear();
+ m_xWidget->freeze();
+
+ SfxObjectShell* pObjSh = SfxObjectShell::Current();
+ if ( auto pDocShell = dynamic_cast<ScDocShell*>( pObjSh) )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ m_xWidget->append_text(ScResId(STR_MANAGE_NAMES));
+ m_xWidget->append_separator("separator");
+
+ ScRange aDummy;
+ std::set<OUString> aSet;
+ ScRangeName* pRangeNames = rDoc.GetRangeName();
+ for (const auto& rEntry : *pRangeNames)
+ {
+ if (rEntry.second->IsValidReference(aDummy))
+ aSet.insert(rEntry.second->GetName());
+ }
+ for (SCTAB i = 0; i < rDoc.GetTableCount(); ++i)
+ {
+ ScRangeName* pLocalRangeName = rDoc.GetRangeName(i);
+ if (pLocalRangeName && !pLocalRangeName->empty())
+ {
+ OUString aTableName;
+ rDoc.GetName(i, aTableName);
+ for (const auto& rEntry : *pLocalRangeName)
+ {
+ if (rEntry.second->IsValidReference(aDummy))
+ aSet.insert(createLocalRangeName(rEntry.second->GetName(), aTableName));
+ }
+ }
+ }
+
+ for (const auto& rItem : aSet)
+ {
+ m_xWidget->append_text(rItem);
+ }
+ }
+ m_xWidget->thaw();
+ m_xWidget->set_entry_text(aPosStr);
+}
+
+void ScPosWnd::FillFunctions()
+{
+ m_xWidget->clear();
+ m_xWidget->freeze();
+
+ OUString aFirstName;
+ const ScAppOptions& rOpt = SC_MOD()->GetAppOptions();
+ sal_uInt16 nMRUCount = rOpt.GetLRUFuncListCount();
+ const sal_uInt16* pMRUList = rOpt.GetLRUFuncList();
+ if (pMRUList)
+ {
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ sal_uInt32 nListCount = pFuncList->GetCount();
+ for (sal_uInt16 i=0; i<nMRUCount; i++)
+ {
+ sal_uInt16 nId = pMRUList[i];
+ for (sal_uInt32 j=0; j<nListCount; j++)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction( j );
+ if ( pDesc->nFIndex == nId && pDesc->mxFuncName )
+ {
+ m_xWidget->append_text(*pDesc->mxFuncName);
+ if (aFirstName.isEmpty())
+ aFirstName = *pDesc->mxFuncName;
+ break; // Stop searching
+ }
+ }
+ }
+ }
+
+ //! Re-add entry "Other..." for Function AutoPilot if it can work with text that
+ // has been entered so far
+
+ // m_xWidget->append_text(ScResId(STR_FUNCTIONLIST_MORE));
+
+ m_xWidget->thaw();
+ m_xWidget->set_entry_text(aFirstName);
+}
+
+void ScPosWnd::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( bFormulaMode )
+ return;
+
+ // Does the list of range names need updating?
+ if ( auto pEventHint = dynamic_cast<const SfxEventHint*>(&rHint) )
+ {
+ SfxEventHintId nEventId = pEventHint->GetEventId();
+ if ( nEventId == SfxEventHintId::ActivateDoc )
+ FillRangeNames();
+ }
+ else
+ {
+ const SfxHintId nHintId = rHint.GetId();
+ if (nHintId == SfxHintId::ScAreasChanged || nHintId == SfxHintId::ScNavigatorUpdateAll)
+ FillRangeNames();
+ }
+}
+
+void ScPosWnd::HideTip()
+{
+ if (nTipVisible)
+ {
+ Help::HidePopover(this, nTipVisible);
+ nTipVisible = nullptr;
+ }
+}
+
+static ScNameInputType lcl_GetInputType( const OUString& rText )
+{
+ ScNameInputType eRet = SC_NAME_INPUT_BAD_NAME; // the more general error
+
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pViewSh )
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ ScAddress::Details aDetails( rDoc.GetAddressConvention());
+
+ // test in same order as in SID_CURRENTCELL execute
+
+ ScRange aRange;
+ ScAddress aAddress;
+ SCTAB nNameTab;
+ sal_Int32 nNumeric;
+
+ // From the context we know that when testing for a range name
+ // sheet-local scope names have " (sheetname)" appended and global
+ // names don't and can't contain ')', so we can force one or the other.
+ const RutlNameScope eNameScope =
+ ((!rText.isEmpty() && rText[rText.getLength()-1] == ')') ? RUTL_NAMES_LOCAL : RUTL_NAMES_GLOBAL);
+
+ if (rText == ScResId(STR_MANAGE_NAMES))
+ eRet = SC_MANAGE_NAMES;
+ else if ( aRange.Parse( rText, rDoc, aDetails ) & ScRefFlags::VALID )
+ eRet = SC_NAME_INPUT_RANGE;
+ else if ( aAddress.Parse( rText, rDoc, aDetails ) & ScRefFlags::VALID )
+ eRet = SC_NAME_INPUT_CELL;
+ else if ( ScRangeUtil::MakeRangeFromName( rText, rDoc, nTab, aRange, eNameScope, aDetails ) )
+ {
+ eRet = ((eNameScope == RUTL_NAMES_LOCAL) ? SC_NAME_INPUT_NAMEDRANGE_LOCAL :
+ SC_NAME_INPUT_NAMEDRANGE_GLOBAL);
+ }
+ else if ( ScRangeUtil::MakeRangeFromName( rText, rDoc, nTab, aRange, RUTL_DBASE, aDetails ) )
+ eRet = SC_NAME_INPUT_DATABASE;
+ else if ( comphelper::string::isdigitAsciiString( rText ) &&
+ ( nNumeric = rText.toInt32() ) > 0 && nNumeric <= rDoc.MaxRow()+1 )
+ eRet = SC_NAME_INPUT_ROW;
+ else if ( rDoc.GetTable( rText, nNameTab ) )
+ eRet = SC_NAME_INPUT_SHEET;
+ else if (ScRangeData::IsNameValid(rText, rDoc)
+ == ScRangeData::IsNameValidType::NAME_VALID) // nothing found, create new range?
+ {
+ if ( rViewData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
+ eRet = SC_NAME_INPUT_DEFINE;
+ else
+ eRet = SC_NAME_INPUT_BAD_SELECTION;
+ }
+ else
+ eRet = SC_NAME_INPUT_BAD_NAME;
+ }
+
+ return eRet;
+}
+
+IMPL_LINK_NOARG(ScPosWnd, ModifyHdl, weld::ComboBox&, void)
+{
+ HideTip();
+
+ if (m_xWidget->changed_by_direct_pick())
+ {
+ DoEnter();
+ return;
+ }
+
+ if (bFormulaMode)
+ return;
+
+ // determine the action that would be taken for the current input
+
+ ScNameInputType eType = lcl_GetInputType(m_xWidget->get_active_text()); // uses current view
+ TranslateId pStrId;
+ switch ( eType )
+ {
+ case SC_NAME_INPUT_CELL:
+ pStrId = STR_NAME_INPUT_CELL;
+ break;
+ case SC_NAME_INPUT_RANGE:
+ case SC_NAME_INPUT_NAMEDRANGE_LOCAL:
+ case SC_NAME_INPUT_NAMEDRANGE_GLOBAL:
+ pStrId = STR_NAME_INPUT_RANGE; // named range or range reference
+ break;
+ case SC_NAME_INPUT_DATABASE:
+ pStrId = STR_NAME_INPUT_DBRANGE;
+ break;
+ case SC_NAME_INPUT_ROW:
+ pStrId = STR_NAME_INPUT_ROW;
+ break;
+ case SC_NAME_INPUT_SHEET:
+ pStrId = STR_NAME_INPUT_SHEET;
+ break;
+ case SC_NAME_INPUT_DEFINE:
+ pStrId = STR_NAME_INPUT_DEFINE;
+ break;
+ default:
+ // other cases (error): no tip help
+ break;
+ }
+
+ if (!pStrId)
+ return;
+
+ // show the help tip at the text cursor position
+ Point aPos;
+ vcl::Cursor* pCur = GetCursor();
+ if (pCur)
+ aPos = LogicToPixel( pCur->GetPos() );
+ aPos = OutputToScreenPixel( aPos );
+ tools::Rectangle aRect( aPos, aPos );
+
+ OUString aText = ScResId(pStrId);
+ QuickHelpFlags const nAlign = QuickHelpFlags::Left|QuickHelpFlags::Bottom;
+ nTipVisible = Help::ShowPopover(this, aRect, aText, nAlign);
+}
+
+void ScPosWnd::DoEnter()
+{
+ OUString aText = m_xWidget->get_active_text();
+ if ( !aText.isEmpty() )
+ {
+ if ( bFormulaMode )
+ {
+ ScModule* pScMod = SC_MOD();
+ if ( aText == ScResId(STR_FUNCTIONLIST_MORE) )
+ {
+ // Function AutoPilot
+ //! Continue working with the text entered so far
+
+ //! new method at ScModule to query if function autopilot is open
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if ( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
+ pViewFrm->GetDispatcher()->Execute( SID_OPENDLG_FUNCTION,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
+ }
+ else
+ {
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ ScInputHandler* pHdl = pScMod->GetInputHdl( pViewSh );
+ if (pHdl)
+ pHdl->InsertFunction( aText );
+ }
+ }
+ else
+ {
+ // depending on the input, select something or create a new named range
+
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pViewSh )
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScDocShell* pDocShell = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScNameInputType eType = lcl_GetInputType( aText );
+ if ( eType == SC_NAME_INPUT_BAD_NAME || eType == SC_NAME_INPUT_BAD_SELECTION )
+ {
+ TranslateId pId = (eType == SC_NAME_INPUT_BAD_NAME) ? STR_NAME_ERROR_NAME : STR_NAME_ERROR_SELECTION;
+ pViewSh->ErrorMessage(pId);
+ }
+ else if ( eType == SC_NAME_INPUT_DEFINE )
+ {
+ ScRangeName* pNames = rDoc.GetRangeName();
+ ScRange aSelection;
+ if ( pNames && !pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aText)) &&
+ (rViewData.GetSimpleArea( aSelection ) == SC_MARK_SIMPLE) )
+ {
+ ScRangeName aNewRanges( *pNames );
+ ScAddress aCursor( rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo() );
+ OUString aContent(aSelection.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention()));
+ ScRangeData* pNew = new ScRangeData( rDoc, aText, aContent, aCursor );
+ if ( aNewRanges.insert(pNew) )
+ {
+ pDocShell->GetDocFunc().ModifyRangeNames( aNewRanges );
+ pViewSh->UpdateInputHandler(true);
+ }
+ }
+ }
+ else if (eType == SC_MANAGE_NAMES)
+ {
+ sal_uInt16 nId = ScNameDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pViewSh->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ SC_MOD()->SetRefDialog( nId, pWnd == nullptr );
+ }
+ else
+ {
+ bool bForceGlobalName = false;
+ // for all selection types, execute the SID_CURRENTCELL slot.
+ if (eType == SC_NAME_INPUT_CELL || eType == SC_NAME_INPUT_RANGE)
+ {
+ // Note that SID_CURRENTCELL always expects address to
+ // be in Calc A1 format. Convert the text.
+ ScRange aRange(0,0, rViewData.GetTabNo());
+ aRange.ParseAny(aText, rDoc, rDoc.GetAddressConvention());
+ aText = aRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D, ::formula::FormulaGrammar::CONV_OOO);
+ }
+ else if (eType == SC_NAME_INPUT_NAMEDRANGE_GLOBAL)
+ {
+ bForceGlobalName = true;
+ }
+
+ SfxStringItem aPosItem( SID_CURRENTCELL, aText );
+ SfxBoolItem aUnmarkItem( FN_PARAM_1, true ); // remove existing selection
+ // FN_PARAM_2 reserved for AlignToCursor
+ SfxBoolItem aForceGlobalName( FN_PARAM_3, bForceGlobalName );
+
+ pViewSh->GetViewData().GetDispatcher().ExecuteList( SID_CURRENTCELL,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aPosItem, &aUnmarkItem, &aForceGlobalName });
+ }
+ }
+ }
+ }
+ else
+ m_xWidget->set_entry_text(aPosStr);
+
+ ReleaseFocus_Impl();
+}
+
+IMPL_LINK_NOARG(ScPosWnd, ActivateHdl, weld::ComboBox&, bool)
+{
+ DoEnter();
+ return true;
+}
+
+IMPL_LINK(ScPosWnd, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled = true;
+
+ switch (rKEvt.GetKeyCode().GetCode())
+ {
+ case KEY_RETURN:
+ bHandled = ActivateHdl(*m_xWidget);
+ break;
+ case KEY_ESCAPE:
+ if (nTipVisible)
+ {
+ // escape when the tip help is shown: only hide the tip
+ HideTip();
+ }
+ else
+ {
+ if (!bFormulaMode)
+ m_xWidget->set_entry_text(aPosStr);
+ ReleaseFocus_Impl();
+ }
+ break;
+ default:
+ bHandled = false;
+ break;
+ }
+
+ return bHandled || ChildKeyInput(rKEvt);
+}
+
+IMPL_LINK_NOARG(ScPosWnd, OnAsyncGetFocus, void*, void)
+{
+ m_nAsyncGetFocusId = nullptr;
+ m_xWidget->select_entry_region(0, -1);
+}
+
+IMPL_LINK_NOARG(ScPosWnd, FocusInHdl, weld::Widget&, void)
+{
+ if (m_nAsyncGetFocusId)
+ return;
+ // do it async to defeat entry in combobox having its own ideas about the focus
+ m_nAsyncGetFocusId = Application::PostUserEvent(LINK(this, ScPosWnd, OnAsyncGetFocus));
+}
+
+IMPL_LINK_NOARG(ScPosWnd, FocusOutHdl, weld::Widget&, void)
+{
+ if (m_nAsyncGetFocusId)
+ {
+ Application::RemoveUserEvent(m_nAsyncGetFocusId);
+ m_nAsyncGetFocusId = nullptr;
+ }
+
+ HideTip();
+}
+
+void ScPosWnd::ReleaseFocus_Impl()
+{
+ HideTip();
+
+ SfxViewShell* pCurSh = SfxViewShell::Current();
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl( dynamic_cast<ScTabViewShell*>( pCurSh ) );
+ if ( pHdl && pHdl->IsTopMode() )
+ {
+ // Focus back in input row?
+ ScInputWindow* pInputWin = pHdl->GetInputWindow();
+ if (pInputWin)
+ {
+ pInputWin->TextGrabFocus();
+ return;
+ }
+ }
+
+ // Set focus to active View
+ if ( pCurSh )
+ {
+ vcl::Window* pShellWnd = pCurSh->GetWindow();
+
+ if ( pShellWnd )
+ pShellWnd->GrabFocus();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/lnktrans.cxx b/sc/source/ui/app/lnktrans.cxx
new file mode 100644
index 000000000..1ff48e7fe
--- /dev/null
+++ b/sc/source/ui/app/lnktrans.cxx
@@ -0,0 +1,76 @@
+/* -*- 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 <svl/urlbmk.hxx>
+
+#include <lnktrans.hxx>
+#include <scmod.hxx>
+
+using namespace com::sun::star;
+
+ScLinkTransferObj::ScLinkTransferObj()
+{
+}
+
+ScLinkTransferObj::~ScLinkTransferObj()
+{
+}
+
+void ScLinkTransferObj::SetLinkURL( const OUString& rURL, const OUString& rText )
+{
+ aLinkURL = rURL;
+ aLinkText = rText;
+}
+
+void ScLinkTransferObj::AddSupportedFormats()
+{
+ if ( !aLinkURL.isEmpty() )
+ {
+ // TransferableHelper::SetINetBookmark formats
+
+ AddFormat( SotClipboardFormatId::SOLK );
+ AddFormat( SotClipboardFormatId::STRING );
+ AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
+ AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
+ AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::FILECONTENT );
+ }
+}
+
+bool ScLinkTransferObj::GetData(
+ const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+{
+ bool bOK = false;
+ if ( !aLinkURL.isEmpty() )
+ {
+ INetBookmark aBmk( aLinkURL, aLinkText );
+ bOK = SetINetBookmark( aBmk, rFlavor );
+ }
+ return bOK;
+}
+
+void ScLinkTransferObj::DragFinished( sal_Int8 nDropAction )
+{
+ ScModule* pScMod = SC_MOD();
+ pScMod->ResetDragObject();
+
+ TransferDataContainer::DragFinished( nDropAction );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/msgpool.cxx b/sc/source/ui/app/msgpool.cxx
new file mode 100644
index 000000000..58daba682
--- /dev/null
+++ b/sc/source/ui/app/msgpool.cxx
@@ -0,0 +1,93 @@
+/* -*- 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 <sc.hrc>
+#include <docpool.hxx>
+#include <msgpool.hxx>
+
+SfxItemInfo const aMsgItemInfos[] =
+{
+ { 0, true }, // SCITEM_STRING
+ { 0, true }, // SCITEM_SEARCHDATA - stop using this!
+ { SID_SORT, true }, // SCITEM_SORTDATA
+ { SID_QUERY, true }, // SCITEM_QUERYDATA
+ { SID_SUBTOTALS, true }, // SCITEM_SUBTDATA
+ { SID_CONSOLIDATE, true }, // SCITEM_CONSOLIDATEDATA
+ { SID_PIVOT_TABLE, true }, // SCITEM_PIVOTDATA
+ { SID_SOLVE, true }, // SCITEM_SOLVEDATA
+ { SID_SCUSERLISTS, true }, // SCITEM_USERLIST
+ { 0, false } // SCITEM_CONDFORMATDLGDATA
+};
+
+ScMessagePool::ScMessagePool()
+ : SfxItemPool ( "ScMessagePool",
+ MSGPOOL_START, MSGPOOL_END,
+ aMsgItemInfos, nullptr ),
+
+ aGlobalStringItem ( SfxStringItem ( SCITEM_STRING, OUString() ) ),
+ aGlobalSearchItem ( SvxSearchItem ( SCITEM_SEARCHDATA ) ),
+ aGlobalSortItem ( ScSortItem ( SCITEM_SORTDATA, nullptr ) ),
+ aGlobalQueryItem ( ScQueryItem ( SCITEM_QUERYDATA, nullptr, nullptr ) ),
+ aGlobalSubTotalItem ( ScSubTotalItem ( SCITEM_SUBTDATA, nullptr, nullptr ) ),
+ aGlobalConsolidateItem ( ScConsolidateItem ( SCITEM_CONSOLIDATEDATA, nullptr ) ),
+ aGlobalPivotItem ( ScPivotItem ( SCITEM_PIVOTDATA, nullptr, nullptr, false ) ),
+ aGlobalSolveItem ( ScSolveItem ( SCITEM_SOLVEDATA, nullptr ) ),
+ aGlobalUserListItem ( ScUserListItem ( SCITEM_USERLIST ) ),
+ aCondFormatDlgItem ( ScCondFormatDlgItem ( nullptr, -1, false ) ),
+
+ mvPoolDefaults(MSGPOOL_END - MSGPOOL_START + 1),
+ pDocPool(new ScDocumentPool)
+{
+ mvPoolDefaults[SCITEM_STRING - MSGPOOL_START] = &aGlobalStringItem;
+ mvPoolDefaults[SCITEM_SEARCHDATA - MSGPOOL_START] = &aGlobalSearchItem;
+ mvPoolDefaults[SCITEM_SORTDATA - MSGPOOL_START] = &aGlobalSortItem;
+ mvPoolDefaults[SCITEM_QUERYDATA - MSGPOOL_START] = &aGlobalQueryItem;
+ mvPoolDefaults[SCITEM_SUBTDATA - MSGPOOL_START] = &aGlobalSubTotalItem;
+ mvPoolDefaults[SCITEM_CONSOLIDATEDATA - MSGPOOL_START] = &aGlobalConsolidateItem;
+ mvPoolDefaults[SCITEM_PIVOTDATA - MSGPOOL_START] = &aGlobalPivotItem;
+ mvPoolDefaults[SCITEM_SOLVEDATA - MSGPOOL_START] = &aGlobalSolveItem;
+ mvPoolDefaults[SCITEM_USERLIST - MSGPOOL_START] = &aGlobalUserListItem;
+ mvPoolDefaults[SCITEM_CONDFORMATDLGDATA - MSGPOOL_START] = &aCondFormatDlgItem;
+
+ SetDefaults( &mvPoolDefaults );
+
+ SetSecondaryPool( pDocPool.get() );
+}
+
+ScMessagePool::~ScMessagePool()
+{
+ Delete();
+ SetSecondaryPool( nullptr ); // before deleting defaults (accesses defaults)
+
+ for ( sal_uInt16 i=0; i <= MSGPOOL_END-MSGPOOL_START; i++ )
+ ClearRefCount( *mvPoolDefaults[i] );
+}
+
+MapUnit ScMessagePool::GetMetric( sal_uInt16 nWhich ) const
+{
+ // Own attributes: Twips, everything else 1/100 mm
+ if ( nWhich >= ATTR_STARTINDEX && nWhich <= ATTR_ENDINDEX )
+ return MapUnit::MapTwip;
+ else
+ return MapUnit::Map100thMM;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/rfindlst.cxx b/sc/source/ui/app/rfindlst.cxx
new file mode 100644
index 000000000..330b8479b
--- /dev/null
+++ b/sc/source/ui/app/rfindlst.cxx
@@ -0,0 +1,90 @@
+/* -*- 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 <rfindlst.hxx>
+#include <tools/debug.hxx>
+
+#define SC_RANGECOLORS 8
+
+const Color aColNames[SC_RANGECOLORS] =
+ { COL_LIGHTBLUE, COL_LIGHTRED, COL_LIGHTMAGENTA, COL_GREEN,
+ COL_BLUE, COL_RED, COL_MAGENTA, COL_BROWN };
+
+ScRangeFindList::ScRangeFindList(const OUString& rName) :
+ aDocName( rName ),
+ bHidden( false ),
+ nIndexColor( 0 )
+{
+}
+
+Color ScRangeFindList::Insert( const ScRangeFindData &rNew )
+{
+ auto it = std::find_if(maEntries.begin(), maEntries.end(),
+ [&rNew](const ScRangeFindData& rEntry) { return rEntry.aRef == rNew.aRef; });
+ ScRangeFindData insertData(rNew);
+ insertData.nColor = ( it != maEntries.end() ? it->nColor :
+ ScRangeFindList::GetColorName( maEntries.size() ) );
+ maEntries.push_back(insertData);
+ nIndexColor = maEntries.size() - 1;
+ return insertData.nColor;
+}
+
+Color ScRangeFindList::GetColorName( const size_t nIndex )
+{
+ return aColNames[nIndex % SC_RANGECOLORS];
+}
+
+Color ScRangeFindList::FindColor( const ScRange& rRef, const size_t nIndex )
+{
+ sal_Int32 nOldCntr = 0;
+ sal_Int32 nNewCntr = 0;
+ Color nOldColor(0);
+ Color nNewColor(0);
+
+ DBG_ASSERT( (nIndex < maEntries.size()), "nIndex out of range!" );
+
+ nOldColor = maEntries[nIndex].nColor;
+ nNewColor = ScRangeFindList::GetColorName( nIndex );
+
+ std::vector<ScRangeFindData>::iterator it=maEntries.begin();
+ for( ;it!=maEntries.end(); ++it)
+ {
+ if(it->aRef == rRef)
+ break;
+
+ if (it->nColor == nOldColor )
+ nOldCntr++;
+
+ if (it->nColor == nNewColor )
+ nNewCntr++;
+ }
+
+ if ( it != maEntries.end() )
+ return it->nColor;
+
+ if ( nOldCntr == 1 )
+ return nOldColor;
+
+ if ( nNewCntr > 0 )
+ return ScRangeFindList::GetColorName( ++nIndexColor );
+
+ return nNewColor;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/scdll.cxx b/sc/source/ui/app/scdll.cxx
new file mode 100644
index 000000000..2256ee2e1
--- /dev/null
+++ b/sc/source/ui/app/scdll.cxx
@@ -0,0 +1,257 @@
+/* -*- 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 <config_features.h>
+
+#include <svx/fmobjfac.hxx>
+#include <svx/objfac3d.hxx>
+
+#include <comphelper/lok.hxx>
+#include <sfx2/sidebar/SidebarChildWindow.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/devtools/DevelopmentToolChildWindow.hxx>
+#include <avmedia/mediatoolbox.hxx>
+#include <NumberFormatControl.hxx>
+
+#include <unotools/resmgr.hxx>
+
+#include <scmod.hxx>
+#include <scresid.hxx>
+#include <sc.hrc>
+
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <prevwsh.hxx>
+#include <drawsh.hxx>
+#include <drformsh.hxx>
+#include <drtxtob.hxx>
+#include <editsh.hxx>
+#include <pivotsh.hxx>
+#include <auditsh.hxx>
+#include <cellsh.hxx>
+#include <oleobjsh.hxx>
+#include <chartsh.hxx>
+#include <graphsh.hxx>
+#include <mediash.hxx>
+#include <pgbrksh.hxx>
+#include <scdll.hxx>
+#include <SparklineShell.hxx>
+
+#include <appoptio.hxx>
+#include <searchresults.hxx>
+
+// Controls
+
+#include <svx/tbxctl.hxx>
+#include <svx/fillctrl.hxx>
+#include <svx/linectrl.hxx>
+//#include <svx/tbcontrl.hxx>
+#include <svx/selctrl.hxx>
+#include <svx/insctrl.hxx>
+#include <svx/zoomctrl.hxx>
+#include <svx/modctrl.hxx>
+#include <svx/pszctrl.hxx>
+#include <svx/grafctrl.hxx>
+#include <svx/clipboardctl.hxx>
+#include <svx/formatpaintbrushctrl.hxx>
+#include <tbzoomsliderctrl.hxx>
+#include <svx/zoomsliderctrl.hxx>
+
+#include <svx/xmlsecctrl.hxx>
+// Child windows
+#include <reffact.hxx>
+#include <navipi.hxx>
+#include <inputwin.hxx>
+#include <spelldialog.hxx>
+#include <svx/fontwork.hxx>
+#include <svx/srchdlg.hxx>
+#include <svx/hyperdlg.hxx>
+#include <svx/imapdlg.hxx>
+
+#include <filter.hxx>
+#include <scabstdlg.hxx>
+
+OUString ScResId(TranslateId aId)
+{
+ return Translate::get(aId, SC_MOD()->GetResLocale());
+}
+
+OUString ScResId(TranslateNId aContextSingularPlural, int nCardinality)
+{
+ return Translate::nget(aContextSingularPlural, nCardinality, SC_MOD()->GetResLocale());
+}
+
+void ScDLL::Init()
+{
+ if ( SfxApplication::GetModule(SfxToolsModule::Calc) ) // Module already active
+ return;
+
+ auto pUniqueModule = std::make_unique<ScModule>(&ScDocShell::Factory());
+ ScModule* pMod = pUniqueModule.get();
+ SfxApplication::SetModule(SfxToolsModule::Calc, std::move(pUniqueModule));
+
+ ScDocShell::Factory().SetDocumentServiceName( "com.sun.star.sheet.SpreadsheetDocument" );
+
+ // Not until the ResManager is initialized
+ // The AppOptions must be initialized not until after ScGlobal::Init
+ ScGlobal::Init();
+
+ // register your view-factories here
+ ScTabViewShell ::RegisterFactory(SFX_INTERFACE_SFXAPP);
+ ScPreviewShell ::RegisterFactory(SFX_INTERFACE_SFXDOCSH);
+
+ // register your shell-interfaces here
+ ScModule ::RegisterInterface(pMod);
+ ScDocShell ::RegisterInterface(pMod);
+ ScTabViewShell ::RegisterInterface(pMod);
+ ScPreviewShell ::RegisterInterface(pMod);
+ ScDrawShell ::RegisterInterface(pMod);
+ ScDrawFormShell ::RegisterInterface(pMod);
+ ScDrawTextObjectBar ::RegisterInterface(pMod);
+ ScEditShell ::RegisterInterface(pMod);
+ ScPivotShell ::RegisterInterface(pMod);
+ sc::SparklineShell ::RegisterInterface(pMod);
+ ScAuditingShell ::RegisterInterface(pMod);
+ ScFormatShell ::RegisterInterface(pMod);
+ ScCellShell ::RegisterInterface(pMod);
+ ScOleObjectShell ::RegisterInterface(pMod);
+ ScChartShell ::RegisterInterface(pMod);
+ ScGraphicShell ::RegisterInterface(pMod);
+ ScMediaShell ::RegisterInterface(pMod);
+ ScPageBreakShell ::RegisterInterface(pMod);
+
+ // Own Controller
+ ScZoomSliderControl ::RegisterControl(SID_PREVIEW_SCALINGFACTOR, pMod);
+
+ // SvxToolboxController
+ SvxTbxCtlDraw ::RegisterControl(SID_INSERT_DRAW, pMod);
+ SvxFillToolBoxControl ::RegisterControl(0, pMod);
+ SvxLineWidthToolBoxControl ::RegisterControl(0, pMod);
+ SvxClipBoardControl ::RegisterControl(SID_PASTE, pMod );
+ SvxClipBoardControl ::RegisterControl(SID_PASTE_UNFORMATTED, pMod );
+ svx::FormatPaintBrushToolBoxControl::RegisterControl(SID_FORMATPAINTBRUSH, pMod );
+ sc::ScNumberFormatControl ::RegisterControl(SID_NUMBER_TYPE_FORMAT, pMod );
+
+ SvxGrafModeToolBoxControl ::RegisterControl(SID_ATTR_GRAF_MODE, pMod);
+ SvxGrafRedToolBoxControl ::RegisterControl(SID_ATTR_GRAF_RED, pMod);
+ SvxGrafGreenToolBoxControl ::RegisterControl(SID_ATTR_GRAF_GREEN, pMod);
+ SvxGrafBlueToolBoxControl ::RegisterControl(SID_ATTR_GRAF_BLUE, pMod);
+ SvxGrafLuminanceToolBoxControl ::RegisterControl(SID_ATTR_GRAF_LUMINANCE, pMod);
+ SvxGrafContrastToolBoxControl ::RegisterControl(SID_ATTR_GRAF_CONTRAST, pMod);
+ SvxGrafGammaToolBoxControl ::RegisterControl(SID_ATTR_GRAF_GAMMA, pMod);
+ SvxGrafTransparenceToolBoxControl::RegisterControl(SID_ATTR_GRAF_TRANSPARENCE, pMod);
+
+ // Media Controller
+#if HAVE_FEATURE_AVMEDIA
+ ::avmedia::MediaToolBoxControl::RegisterControl( SID_AVMEDIA_TOOLBOX, pMod );
+#endif
+
+ // Common SFX Controller
+ sfx2::sidebar::SidebarChildWindow::RegisterChildWindow(false, pMod);
+ DevelopmentToolChildWindow::RegisterChildWindow(false, pMod);
+
+ // SvxStatusBar Controller
+ SvxInsertStatusBarControl ::RegisterControl(SID_ATTR_INSERT, pMod);
+ SvxSelectionModeControl ::RegisterControl(SID_STATUS_SELMODE, pMod);
+ SvxZoomStatusBarControl ::RegisterControl(SID_ATTR_ZOOM, pMod);
+ SvxZoomSliderControl ::RegisterControl(SID_ATTR_ZOOMSLIDER, pMod);
+ SvxModifyControl ::RegisterControl(SID_DOC_MODIFIED, pMod);
+ XmlSecStatusBarControl ::RegisterControl( SID_SIGNATURE, pMod );
+
+ SvxPosSizeStatusBarControl ::RegisterControl(SID_ATTR_SIZE, pMod);
+
+ // Child Windows
+
+ ScInputWindowWrapper ::RegisterChildWindow(true, pMod, SfxChildWindowFlags::TASK|SfxChildWindowFlags::FORCEDOCK);
+ ScSolverDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScOptSolverDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScXMLSourceDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScNameDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScNameDefDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScPivotLayoutWrapper ::RegisterChildWindow(false, pMod);
+ ScTabOpDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScFilterDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScSpecialFilterDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScDbNameDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScConsolidateDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScPrintAreasDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScColRowNameRangesDlgWrapper::RegisterChildWindow(false, pMod);
+ ScFormulaDlgWrapper ::RegisterChildWindow(false, pMod);
+
+ ScRandomNumberGeneratorDialogWrapper::RegisterChildWindow(false, pMod);
+ ScSamplingDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScDescriptiveStatisticsDialogWrapper::RegisterChildWindow(false, pMod);
+ ScAnalysisOfVarianceDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScCorrelationDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScCovarianceDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScExponentialSmoothingDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScMovingAverageDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScRegressionDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScTTestDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScFTestDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScZTestDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScChiSquareTestDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScFourierAnalysisDialogWrapper ::RegisterChildWindow(false, pMod);
+ sc::SparklineDialogWrapper ::RegisterChildWindow(false, pMod);
+ sc::SparklineDataRangeDialogWrapper ::RegisterChildWindow(false, pMod);
+
+ // Redlining Window
+ ScAcceptChgDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScSimpleRefDlgWrapper ::RegisterChildWindow(false, pMod, SfxChildWindowFlags::ALWAYSAVAILABLE|SfxChildWindowFlags::NEVERHIDE );
+ ScHighlightChgDlgWrapper ::RegisterChildWindow(false, pMod);
+
+ SvxSearchDialogWrapper ::RegisterChildWindow(false, pMod);
+ SvxHlinkDlgWrapper ::RegisterChildWindow(false, pMod);
+ SvxFontWorkChildWindow ::RegisterChildWindow(false, pMod);
+ SvxIMapDlgChildWindow ::RegisterChildWindow(false, pMod);
+ ScSpellDialogChildWindow::RegisterChildWindow(
+ false, pMod, comphelper::LibreOfficeKit::isActive() ? SfxChildWindowFlags::NEVERCLONE
+ : SfxChildWindowFlags::NONE);
+
+ ScValidityRefChildWin::RegisterChildWindow(false, pMod);
+ sc::SearchResultsDlgWrapper::RegisterChildWindow(false, pMod);
+ ScCondFormatDlgWrapper::RegisterChildWindow(false, pMod);
+
+ ScNavigatorWrapper::RegisterChildWindow(false, pMod, SfxChildWindowFlags::NEVERHIDE);
+
+ // Add 3DObject Factory
+ E3dObjFactory();
+
+ // Add css::form::component::FormObject Factory
+ FmFormObjFactory();
+
+ pMod->PutItem( SfxUInt16Item( SID_ATTR_METRIC, sal::static_int_cast<sal_uInt16>(pMod->GetAppOptions().GetAppMetric()) ) );
+
+ // StarOne Services are now handled in the registry
+}
+
+#ifndef DISABLE_DYNLOADING
+
+extern "C" SAL_DLLPUBLIC_EXPORT
+void lok_preload_hook()
+{
+ // scfilt
+ ScFormatFilter::Get();
+ // scui
+ ScAbstractDialogFactory::Create();
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/scmod.cxx b/sc/source/ui/app/scmod.cxx
new file mode 100644
index 000000000..1529f9920
--- /dev/null
+++ b/sc/source/ui/app/scmod.cxx
@@ -0,0 +1,2325 @@
+/* -*- 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 <com/sun/star/ui/dialogs/XSLTFilterDialog.hpp>
+#include <comphelper/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <scitems.hxx>
+#include <sfx2/app.hxx>
+
+#include <editeng/flditem.hxx>
+#include <editeng/outliner.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/objface.hxx>
+
+#include <IAnyRefDialog.hxx>
+
+#include <svtools/ehdl.hxx>
+#include <svtools/accessibilityoptions.hxx>
+#include <svl/ctloptions.hxx>
+#include <unotools/useroptions.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/printer.hxx>
+#include <editeng/langitem.hxx>
+#include <svtools/colorcfg.hxx>
+
+#include <svl/whiter.hxx>
+#include <svx/dialogs.hrc>
+#include <svl/inethist.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/svxerr.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <editeng/unolingu.hxx>
+#include <unotools/lingucfg.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <com/sun/star/linguistic2/XThesaurus.hpp>
+#include <ooo/vba/XSinkCaller.hpp>
+
+#include <scmod.hxx>
+#include <global.hxx>
+#include <viewopti.hxx>
+#include <docoptio.hxx>
+#include <appoptio.hxx>
+#include <defaultsoptions.hxx>
+#include <formulaopt.hxx>
+#include <inputopt.hxx>
+#include <printopt.hxx>
+#include <navicfg.hxx>
+#include <addincfg.hxx>
+#include <tabvwsh.hxx>
+#include <prevwsh.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+#include <uiitems.hxx>
+#include <sc.hrc>
+#include <scerrors.hrc>
+#include <scstyles.hrc>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <bitmaps.hlst>
+#include <inputhdl.hxx>
+#include <inputwin.hxx>
+#include <msgpool.hxx>
+#include <detfunc.hxx>
+#include <preview.hxx>
+#include <dragdata.hxx>
+#include <markdata.hxx>
+#include <transobj.hxx>
+#include <funcdesc.hxx>
+
+#define ShellClass_ScModule
+#include <scslots.hxx>
+
+#include <scabstdlg.hxx>
+#include <formula/errorcodes.hxx>
+#include <documentlinkmgr.hxx>
+
+#define SC_IDLE_MIN 150
+#define SC_IDLE_MAX 3000
+#define SC_IDLE_STEP 75
+#define SC_IDLE_COUNT 50
+
+static sal_uInt16 nIdleCount = 0;
+
+SFX_IMPL_INTERFACE(ScModule, SfxShell)
+
+void ScModule::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_APPLICATION,
+ SfxVisibilityFlags::Standard | SfxVisibilityFlags::Client | SfxVisibilityFlags::Viewer,
+ ToolbarId::Objectbar_App);
+
+ GetStaticInterface()->RegisterStatusBar(StatusBarId::CalcStatusBar);
+}
+
+ScModule::ScModule( SfxObjectFactory* pFact ) :
+ SfxModule("sc", {pFact}),
+ m_aIdleTimer("sc ScModule IdleTimer"),
+ m_pDragData(new ScDragData),
+ m_pSelTransfer( nullptr ),
+ m_pRefInputHandler( nullptr ),
+ m_nCurRefDlgId( 0 ),
+ m_bIsWaterCan( false ),
+ m_bIsInEditCommand( false ),
+ m_bIsInExecuteDrop( false ),
+ m_bIsInSharedDocLoading( false ),
+ m_bIsInSharedDocSaving( false )
+{
+ // The ResManager (DLL data) is not yet initialized in the ctor!
+ SetName("StarCalc"); // for Basic
+
+ ResetDragObject();
+
+ // InputHandler does not need to be created
+
+ // Create ErrorHandler - was in Init()
+ // Between OfficeApplication::Init and ScGlobal::Init
+ SvxErrorHandler::ensure();
+ m_pErrorHdl.reset( new SfxErrorHandler(RID_ERRHDLSC,
+ ErrCodeArea::Sc,
+ ErrCodeArea::Sc,
+ GetResLocale()) );
+
+ m_aIdleTimer.SetTimeout(SC_IDLE_MIN);
+ m_aIdleTimer.SetInvokeHandler( LINK( this, ScModule, IdleHandler ) );
+ m_aIdleTimer.Start();
+
+ m_pMessagePool = new ScMessagePool;
+ m_pMessagePool->FreezeIdRanges();
+ SetPool( m_pMessagePool.get() );
+ ScGlobal::InitTextHeight( m_pMessagePool.get() );
+
+ StartListening( *SfxGetpApp() ); // for SfxHintId::Deinitializing
+}
+
+ScModule::~ScModule()
+{
+ OSL_ENSURE( !m_pSelTransfer, "Selection Transfer object not deleted" );
+
+ // InputHandler does not need to be deleted (there's none in the App anymore)
+
+ m_pMessagePool.clear();
+
+ m_pDragData.reset();
+ m_pErrorHdl.reset();
+
+ ScGlobal::Clear(); // Also calls ScDocumentPool::DeleteVersionMaps();
+
+ DeleteCfg(); // Called from Exit()
+}
+
+void ScModule::ConfigurationChanged( utl::ConfigurationBroadcaster* p, ConfigurationHints )
+{
+ if ( p == m_pColorConfig.get() || p == m_pAccessOptions.get() )
+ {
+ // Test if detective objects have to be updated with new colors
+ // (if the detective colors haven't been used yet, there's nothing to update)
+ if ( ScDetectiveFunc::IsColorsInitialized() )
+ {
+ const svtools::ColorConfig& rColors = GetColorConfig();
+ bool bArrows =
+ ( ScDetectiveFunc::GetArrowColor() != rColors.GetColorValue(svtools::CALCDETECTIVE).nColor ||
+ ScDetectiveFunc::GetErrorColor() != rColors.GetColorValue(svtools::CALCDETECTIVEERROR).nColor );
+ bool bComments =
+ ( ScDetectiveFunc::GetCommentColor() != rColors.GetColorValue(svtools::CALCNOTESBACKGROUND).nColor );
+ if ( bArrows || bComments )
+ {
+ ScDetectiveFunc::InitializeColors(); // get the new colors
+
+ // update detective objects in all open documents
+ SfxObjectShell* pObjSh = SfxObjectShell::GetFirst();
+ while ( pObjSh )
+ {
+ if ( auto pDocSh = dynamic_cast<ScDocShell * >(pObjSh) )
+ {
+ if ( bArrows )
+ ScDetectiveFunc( pDocSh->GetDocument(), 0 ).UpdateAllArrowColors();
+ if ( bComments )
+ ScDetectiveFunc::UpdateAllComments( pDocSh->GetDocument() );
+ }
+ pObjSh = SfxObjectShell::GetNext( *pObjSh );
+ }
+ }
+ }
+
+ // force all views to repaint, using the new options
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while(pViewShell)
+ {
+ if (ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(pViewShell))
+ {
+ pViewSh->PaintGrid();
+ pViewSh->PaintTop();
+ pViewSh->PaintLeft();
+ pViewSh->PaintExtras();
+
+ ScInputHandler* pHdl = pViewSh->GetInputHandler();
+ if ( pHdl )
+ pHdl->ForgetLastPattern(); // EditEngine BackgroundColor may change
+ }
+ else if ( dynamic_cast<const ScPreviewShell*>( pViewShell) != nullptr )
+ {
+ vcl::Window* pWin = pViewShell->GetWindow();
+ if (pWin)
+ pWin->Invalidate();
+ }
+ pViewShell = SfxViewShell::GetNext( *pViewShell );
+ }
+ }
+ else if ( p == m_pCTLOptions.get() )
+ {
+ // for all documents: set digit language for printer, recalc output factor, update row heights
+ SfxObjectShell* pObjSh = SfxObjectShell::GetFirst();
+ while ( pObjSh )
+ {
+ if ( auto pDocSh = dynamic_cast<ScDocShell *>(pObjSh) )
+ {
+ OutputDevice* pPrinter = pDocSh->GetPrinter();
+ if ( pPrinter )
+ pPrinter->SetDigitLanguage( GetOptDigitLanguage() );
+
+ pDocSh->CalcOutputFactor();
+
+ SCTAB nTabCount = pDocSh->GetDocument().GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ pDocSh->AdjustRowHeight( 0, pDocSh->GetDocument().MaxRow(), nTab );
+ }
+ pObjSh = SfxObjectShell::GetNext( *pObjSh );
+ }
+
+ // for all views (table and preview): update digit language
+ SfxViewShell* pSh = SfxViewShell::GetFirst();
+ while ( pSh )
+ {
+ if (ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(pSh))
+ {
+ // set ref-device for EditEngine (re-evaluates digit settings)
+ ScInputHandler* pHdl = GetInputHdl(pViewSh);
+ if (pHdl)
+ pHdl->UpdateRefDevice();
+
+ pViewSh->DigitLanguageChanged();
+ pViewSh->PaintGrid();
+ }
+ else if (ScPreviewShell* pPreviewSh = dynamic_cast<ScPreviewShell*>(pSh))
+ {
+ ScPreview* pPreview = pPreviewSh->GetPreview();
+
+ pPreview->GetOutDev()->SetDigitLanguage( GetOptDigitLanguage() );
+ pPreview->Invalidate();
+ }
+
+ pSh = SfxViewShell::GetNext( *pSh );
+ }
+ }
+}
+
+void ScModule::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Deinitializing )
+ {
+ // ConfigItems must be removed before ConfigManager
+ DeleteCfg();
+ }
+}
+
+void ScModule::DeleteCfg()
+{
+ m_pViewCfg.reset(); // Saving happens automatically before Exit()
+ m_pDocCfg.reset();
+ m_pAppCfg.reset();
+ m_pDefaultsCfg.reset();
+ m_pFormulaCfg.reset();
+ m_pInputCfg.reset();
+ m_pPrintCfg.reset();
+ m_pNavipiCfg.reset();
+ m_pAddInCfg.reset();
+
+ if ( m_pColorConfig )
+ {
+ m_pColorConfig->RemoveListener(this);
+ m_pColorConfig.reset();
+ }
+ if ( m_pAccessOptions )
+ {
+ m_pAccessOptions->RemoveListener(this);
+ m_pAccessOptions.reset();
+ }
+ if ( m_pCTLOptions )
+ {
+ m_pCTLOptions->RemoveListener(this);
+ m_pCTLOptions.reset();
+ }
+ m_pUserOptions.reset();
+}
+
+// Moved here from the App
+
+void ScModule::Execute( SfxRequest& rReq )
+{
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ SfxBindings* pBindings = pViewFrm ? &pViewFrm->GetBindings() : nullptr;
+
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+ switch ( nSlot )
+ {
+ case SID_CHOOSE_DESIGN:
+ SfxApplication::CallAppBasic( "Template.Samples.ShowStyles" );
+ break;
+ case SID_EURO_CONVERTER:
+ SfxApplication::CallAppBasic( "Euro.ConvertRun.Main" );
+ break;
+ case SID_AUTOSPELL_CHECK:
+ {
+ bool bSet;
+ const SfxPoolItem* pItem;
+ if (pReqArgs && SfxItemState::SET == pReqArgs->GetItemState( FN_PARAM_1, true, &pItem ))
+ bSet = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ else if ( pReqArgs && SfxItemState::SET == pReqArgs->GetItemState( nSlot, true, &pItem ) )
+ bSet = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ else
+ { // Toggle
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
+ if ( pDocSh )
+ bSet = !pDocSh->GetDocument().GetDocOptions().IsAutoSpell();
+ else
+ bSet = !GetDocOptions().IsAutoSpell();
+ }
+
+ SfxItemSetFixed<SID_AUTOSPELL_CHECK, SID_AUTOSPELL_CHECK> aSet( GetPool() );
+ aSet.Put( SfxBoolItem( SID_AUTOSPELL_CHECK, bSet ) );
+ ModifyOptions( aSet );
+ rReq.Done();
+ }
+ break;
+
+ case SID_ATTR_METRIC:
+ {
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && SfxItemState::SET == pReqArgs->GetItemState( nSlot, true, &pItem ) )
+ {
+ FieldUnit eUnit = static_cast<FieldUnit>(static_cast<const SfxUInt16Item*>(pItem)->GetValue());
+ switch( eUnit )
+ {
+ case FieldUnit::MM: // Just the units that are also in the dialog
+ case FieldUnit::CM:
+ case FieldUnit::INCH:
+ case FieldUnit::PICA:
+ case FieldUnit::POINT:
+ {
+ PutItem( *pItem );
+ ScAppOptions aNewOpts( GetAppOptions() );
+ aNewOpts.SetAppMetric( eUnit );
+ SetAppOptions( aNewOpts );
+ rReq.Done();
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ break;
+
+ case FID_AUTOCOMPLETE:
+ {
+ ScAppOptions aNewOpts( GetAppOptions() );
+ bool bNew = !aNewOpts.GetAutoComplete();
+ aNewOpts.SetAutoComplete( bNew );
+ SetAppOptions( aNewOpts );
+ if (pBindings)
+ pBindings->Invalidate( FID_AUTOCOMPLETE );
+ rReq.Done();
+ }
+ break;
+
+ case SID_DETECTIVE_AUTO:
+ {
+ ScAppOptions aNewOpts( GetAppOptions() );
+ bool bNew = !aNewOpts.GetDetectiveAuto();
+ const SfxBoolItem* pAuto = rReq.GetArg<SfxBoolItem>(SID_DETECTIVE_AUTO);
+ if ( pAuto )
+ bNew = pAuto->GetValue();
+
+ aNewOpts.SetDetectiveAuto( bNew );
+ SetAppOptions( aNewOpts );
+ if (pBindings)
+ pBindings->Invalidate( SID_DETECTIVE_AUTO );
+ rReq.AppendItem( SfxBoolItem( SID_DETECTIVE_AUTO, bNew ) );
+ rReq.Done();
+ }
+ break;
+
+ case SID_PSZ_FUNCTION:
+ if (pReqArgs)
+ {
+ auto const & p = pReqArgs->Get(SID_PSZ_FUNCTION);
+ assert(dynamic_cast<const SfxUInt32Item*>(&p) && "wrong Parameter");
+ const SfxUInt32Item& rItem = static_cast<const SfxUInt32Item&>(p);
+
+ ScAppOptions aNewOpts( GetAppOptions() );
+ aNewOpts.SetStatusFunc( rItem.GetValue() );
+ SetAppOptions( aNewOpts );
+
+ if (pBindings)
+ {
+ pBindings->Invalidate( SID_TABLE_CELL );
+ pBindings->Update( SID_TABLE_CELL ); // Immediately
+
+ pBindings->Invalidate( SID_PSZ_FUNCTION );
+ pBindings->Update( SID_PSZ_FUNCTION );
+ // If the menu is opened again immediately
+ }
+ }
+ break;
+
+ case SID_ATTR_LANGUAGE:
+ case SID_ATTR_CHAR_CJK_LANGUAGE:
+ case SID_ATTR_CHAR_CTL_LANGUAGE:
+ {
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && SfxItemState::SET == pReqArgs->GetItemState( GetPool().GetWhich(nSlot), true, &pItem ) )
+ {
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ LanguageType eNewLang = static_cast<const SvxLanguageItem*>(pItem)->GetLanguage();
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+ LanguageType eOld = ( nSlot == SID_ATTR_CHAR_CJK_LANGUAGE ) ? eCjk :
+ ( ( nSlot == SID_ATTR_CHAR_CTL_LANGUAGE ) ? eCtl : eLatin );
+ if ( eNewLang != eOld )
+ {
+ if ( nSlot == SID_ATTR_CHAR_CJK_LANGUAGE )
+ eCjk = eNewLang;
+ else if ( nSlot == SID_ATTR_CHAR_CTL_LANGUAGE )
+ eCtl = eNewLang;
+ else
+ eLatin = eNewLang;
+
+ rDoc.SetLanguage( eLatin, eCjk, eCtl );
+
+ ScInputHandler* pInputHandler = GetInputHdl();
+ if ( pInputHandler )
+ pInputHandler->UpdateSpellSettings(); // EditEngine flags
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ if ( pViewSh )
+ pViewSh->UpdateDrawTextOutliner(); // EditEngine flags
+
+ pDocSh->SetDocumentModified();
+ }
+ }
+ }
+ }
+ break;
+
+ case FID_FOCUS_POSWND:
+ {
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ {
+ ScInputWindow* pWin = pHdl->GetInputWindow();
+ if (pWin)
+ pWin->PosGrabFocus();
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_OPEN_XML_FILTERSETTINGS:
+ {
+ try
+ {
+ css::uno::Reference < css::ui::dialogs::XExecutableDialog > xDialog = css::ui::dialogs::XSLTFilterDialog::create( ::comphelper::getProcessComponentContext());
+ xDialog->execute();
+ }
+ catch( css::uno::RuntimeException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("sc.ui");
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL( "ScApplication: Unknown Message." );
+ break;
+ }
+}
+
+void ScModule::GetState( SfxItemSet& rSet )
+{
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
+ bool bTabView = pDocSh && (pDocSh->GetBestViewShell() != nullptr);
+
+ SfxWhichIter aIter(rSet);
+ for (sal_uInt16 nWhich = aIter.FirstWhich(); nWhich; nWhich = aIter.NextWhich())
+ {
+ if (!bTabView)
+ {
+ // Not in the normal calc view shell (most likely in preview shell). Disable all actions.
+ rSet.DisableItem(nWhich);
+ continue;
+ }
+
+ switch ( nWhich )
+ {
+ case FID_AUTOCOMPLETE:
+ rSet.Put( SfxBoolItem( nWhich, GetAppOptions().GetAutoComplete() ) );
+ break;
+ case SID_DETECTIVE_AUTO:
+ rSet.Put( SfxBoolItem( nWhich, GetAppOptions().GetDetectiveAuto() ) );
+ break;
+ case SID_PSZ_FUNCTION:
+ rSet.Put( SfxUInt32Item( nWhich, GetAppOptions().GetStatusFunc() ) );
+ break;
+ case SID_ATTR_METRIC:
+ rSet.Put( SfxUInt16Item( nWhich, sal::static_int_cast<sal_uInt16>(GetAppOptions().GetAppMetric()) ) );
+ break;
+ case SID_AUTOSPELL_CHECK:
+ rSet.Put( SfxBoolItem( nWhich, pDocSh->GetDocument().GetDocOptions().IsAutoSpell()) );
+ break;
+ case SID_ATTR_LANGUAGE:
+ case ATTR_CJK_FONT_LANGUAGE: // WID for SID_ATTR_CHAR_CJK_LANGUAGE
+ case ATTR_CTL_FONT_LANGUAGE: // WID for SID_ATTR_CHAR_CTL_LANGUAGE
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ pDocSh->GetDocument().GetLanguage( eLatin, eCjk, eCtl );
+ LanguageType eLang = ( nWhich == ATTR_CJK_FONT_LANGUAGE ) ? eCjk :
+ ( ( nWhich == ATTR_CTL_FONT_LANGUAGE ) ? eCtl : eLatin );
+ rSet.Put( SvxLanguageItem( eLang, nWhich ) );
+ }
+ break;
+ }
+ }
+}
+
+void ScModule::HideDisabledSlots( SfxItemSet& rSet )
+{
+ if( SfxViewFrame* pViewFrm = SfxViewFrame::Current() )
+ {
+ SfxBindings& rBindings = pViewFrm->GetBindings();
+ SfxWhichIter aIter( rSet );
+ for( sal_uInt16 nWhich = aIter.FirstWhich(); nWhich != 0; nWhich = aIter.NextWhich() )
+ {
+ ScViewUtil::HideDisabledSlot( rSet, rBindings, nWhich );
+ // always disable the slots
+ rSet.DisableItem( nWhich );
+ }
+ }
+}
+
+void ScModule::ResetDragObject()
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->ResetDragObject();
+ }
+ else
+ {
+ m_pDragData->pCellTransfer = nullptr;
+ m_pDragData->pDrawTransfer = nullptr;
+ m_pDragData->pJumpLocalDoc = nullptr;
+ m_pDragData->aLinkDoc.clear();
+ m_pDragData->aLinkTable.clear();
+ m_pDragData->aLinkArea.clear();
+ m_pDragData->aJumpTarget.clear();
+ m_pDragData->aJumpText.clear();
+ }
+}
+
+const ScDragData& ScModule::GetDragData() const
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ assert(pViewShell);
+ return pViewShell->GetDragData();
+ }
+ else
+ return *m_pDragData;
+}
+
+void ScModule::SetDragObject( ScTransferObj* pCellObj, ScDrawTransferObj* pDrawObj )
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetDragObject(pCellObj, pDrawObj);
+ }
+ else
+ {
+ ResetDragObject();
+ m_pDragData->pCellTransfer = pCellObj;
+ m_pDragData->pDrawTransfer = pDrawObj;
+ }
+}
+
+void ScModule::SetDragLink(
+ const OUString& rDoc, const OUString& rTab, const OUString& rArea )
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetDragLink(rDoc, rTab, rArea);
+ }
+ else
+ {
+ ResetDragObject();
+ m_pDragData->aLinkDoc = rDoc;
+ m_pDragData->aLinkTable = rTab;
+ m_pDragData->aLinkArea = rArea;
+ }
+}
+
+void ScModule::SetDragJump(
+ ScDocument* pLocalDoc, const OUString& rTarget, const OUString& rText )
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetDragJump(pLocalDoc, rTarget, rText);
+ }
+ else
+ {
+ ResetDragObject();
+
+ m_pDragData->pJumpLocalDoc = pLocalDoc;
+ m_pDragData->aJumpTarget = rTarget;
+ m_pDragData->aJumpText = rText;
+ }
+}
+
+ScDocument* ScModule::GetClipDoc()
+{
+ // called from document
+ SfxViewFrame* pViewFrame = nullptr;
+ ScTabViewShell* pViewShell = nullptr;
+ css::uno::Reference<css::datatransfer::XTransferable2> xTransferable;
+
+ if ((pViewShell = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current())))
+ xTransferable.set(ScTabViewShell::GetClipData(pViewShell->GetViewData().GetActiveWin()));
+ else if ((pViewShell = dynamic_cast<ScTabViewShell*>(SfxViewShell::GetFirst())))
+ xTransferable.set(ScTabViewShell::GetClipData(pViewShell->GetViewData().GetActiveWin()));
+ else if ((pViewFrame = SfxViewFrame::GetFirst()))
+ {
+ css::uno::Reference<css::datatransfer::clipboard::XClipboard> xClipboard =
+ pViewFrame->GetWindow().GetClipboard();
+ xTransferable.set(xClipboard.is() ? xClipboard->getContents() : nullptr, css::uno::UNO_QUERY);
+ }
+
+ const ScTransferObj* pObj = ScTransferObj::GetOwnClipboard(xTransferable);
+ if (pObj)
+ {
+ ScDocument* pDoc = pObj->GetDocument();
+ assert((!pDoc || pDoc->IsClipboard()) && "Document is not clipboard, how can that be?");
+ return pDoc;
+ }
+
+ return nullptr;
+}
+
+void ScModule::SetSelectionTransfer( ScSelectionTransferObj* pNew )
+{
+ m_pSelTransfer = pNew;
+}
+
+void ScModule::SetViewOptions( const ScViewOptions& rOpt )
+{
+ if ( !m_pViewCfg )
+ m_pViewCfg.reset(new ScViewCfg);
+
+ m_pViewCfg->SetOptions( rOpt );
+}
+
+const ScViewOptions& ScModule::GetViewOptions()
+{
+ if ( !m_pViewCfg )
+ m_pViewCfg.reset( new ScViewCfg );
+
+ return *m_pViewCfg;
+}
+
+void ScModule::SetDocOptions( const ScDocOptions& rOpt )
+{
+ if ( !m_pDocCfg )
+ m_pDocCfg.reset( new ScDocCfg );
+
+ m_pDocCfg->SetOptions( rOpt );
+}
+
+const ScDocOptions& ScModule::GetDocOptions()
+{
+ if ( !m_pDocCfg )
+ m_pDocCfg.reset( new ScDocCfg );
+
+ return *m_pDocCfg;
+}
+
+void ScModule::InsertEntryToLRUList(sal_uInt16 nFIndex)
+{
+ if(nFIndex == 0)
+ return;
+
+ const ScAppOptions& rAppOpt = GetAppOptions();
+ sal_uInt16 nLRUFuncCount = std::min( rAppOpt.GetLRUFuncListCount(), sal_uInt16(LRU_MAX) );
+ sal_uInt16* pLRUListIds = rAppOpt.GetLRUFuncList();
+
+ sal_uInt16 aIdxList[LRU_MAX];
+ sal_uInt16 n = 0;
+ bool bFound = false;
+
+ while ((n < LRU_MAX) && n<nLRUFuncCount) // Iterate through old list
+ {
+ if (!bFound && (pLRUListIds[n]== nFIndex))
+ bFound = true; // First hit!
+ else if (bFound)
+ aIdxList[n ] = pLRUListIds[n]; // Copy after hit
+ else if ((n+1) < LRU_MAX)
+ aIdxList[n+1] = pLRUListIds[n]; // Move before hit
+ n++;
+ }
+ if (!bFound && (n < LRU_MAX)) // Entry not found?
+ n++; // One more
+ aIdxList[0] = nFIndex; // Current on Top
+
+ ScAppOptions aNewOpts(rAppOpt); // Let App know
+ aNewOpts.SetLRUFuncList(aIdxList, n);
+ SetAppOptions(aNewOpts);
+}
+
+void ScModule::SetAppOptions( const ScAppOptions& rOpt )
+{
+ if ( !m_pAppCfg )
+ m_pAppCfg.reset( new ScAppCfg );
+
+ m_pAppCfg->SetOptions( rOpt );
+}
+
+void global_InitAppOptions()
+{
+ SC_MOD()->GetAppOptions();
+}
+
+const ScAppOptions& ScModule::GetAppOptions()
+{
+ if ( !m_pAppCfg )
+ m_pAppCfg.reset( new ScAppCfg );
+
+ return m_pAppCfg->GetOptions();
+}
+
+void ScModule::SetDefaultsOptions( const ScDefaultsOptions& rOpt )
+{
+ if ( !m_pDefaultsCfg )
+ m_pDefaultsCfg.reset( new ScDefaultsCfg );
+
+ m_pDefaultsCfg->SetOptions( rOpt );
+}
+
+const ScDefaultsOptions& ScModule::GetDefaultsOptions()
+{
+ if ( !m_pDefaultsCfg )
+ m_pDefaultsCfg.reset( new ScDefaultsCfg );
+
+ return *m_pDefaultsCfg;
+}
+
+void ScModule::SetFormulaOptions( const ScFormulaOptions& rOpt )
+{
+ if ( !m_pFormulaCfg )
+ m_pFormulaCfg.reset( new ScFormulaCfg );
+
+ m_pFormulaCfg->SetOptions( rOpt );
+}
+
+const ScFormulaOptions& ScModule::GetFormulaOptions()
+{
+ if ( !m_pFormulaCfg )
+ m_pFormulaCfg.reset( new ScFormulaCfg );
+
+ return *m_pFormulaCfg;
+}
+
+void ScModule::SetInputOptions( const ScInputOptions& rOpt )
+{
+ if ( !m_pInputCfg )
+ m_pInputCfg.reset( new ScInputCfg );
+
+ m_pInputCfg->SetOptions( rOpt );
+}
+
+const ScInputOptions& ScModule::GetInputOptions()
+{
+ if ( !m_pInputCfg )
+ m_pInputCfg.reset( new ScInputCfg );
+
+ return m_pInputCfg->GetOptions();
+}
+
+void ScModule::SetPrintOptions( const ScPrintOptions& rOpt )
+{
+ if ( !m_pPrintCfg )
+ m_pPrintCfg.reset( new ScPrintCfg );
+
+ m_pPrintCfg->SetOptions( rOpt );
+}
+
+const ScPrintOptions& ScModule::GetPrintOptions()
+{
+ if ( !m_pPrintCfg )
+ m_pPrintCfg.reset( new ScPrintCfg );
+
+ return m_pPrintCfg->GetOptions();
+}
+
+ScNavipiCfg& ScModule::GetNavipiCfg()
+{
+ if ( !m_pNavipiCfg )
+ m_pNavipiCfg.reset( new ScNavipiCfg );
+
+ return *m_pNavipiCfg;
+}
+
+ScAddInCfg& ScModule::GetAddInCfg()
+{
+ if ( !m_pAddInCfg )
+ m_pAddInCfg.reset( new ScAddInCfg );
+
+ return *m_pAddInCfg;
+}
+
+svtools::ColorConfig& ScModule::GetColorConfig()
+{
+ if ( !m_pColorConfig )
+ {
+ m_pColorConfig.reset( new svtools::ColorConfig );
+ m_pColorConfig->AddListener(this);
+ }
+
+ return *m_pColorConfig;
+}
+
+SvtAccessibilityOptions& ScModule::GetAccessOptions()
+{
+ if ( !m_pAccessOptions )
+ {
+ m_pAccessOptions.reset( new SvtAccessibilityOptions );
+ m_pAccessOptions->AddListener(this);
+ }
+
+ return *m_pAccessOptions;
+}
+
+SvtCTLOptions& ScModule::GetCTLOptions()
+{
+ if ( !m_pCTLOptions )
+ {
+ m_pCTLOptions.reset( new SvtCTLOptions );
+ m_pCTLOptions->AddListener(this);
+ }
+
+ return *m_pCTLOptions;
+}
+
+SvtUserOptions& ScModule::GetUserOptions()
+{
+ if( !m_pUserOptions )
+ {
+ m_pUserOptions.reset( new SvtUserOptions );
+ }
+ return *m_pUserOptions;
+}
+
+LanguageType ScModule::GetOptDigitLanguage()
+{
+ SvtCTLOptions::TextNumerals eNumerals = GetCTLOptions().GetCTLTextNumerals();
+ return ( eNumerals == SvtCTLOptions::NUMERALS_ARABIC ) ? LANGUAGE_ENGLISH_US :
+ ( eNumerals == SvtCTLOptions::NUMERALS_HINDI) ? LANGUAGE_ARABIC_SAUDI_ARABIA :
+ LANGUAGE_SYSTEM;
+}
+
+/**
+ * Options
+ *
+ * Items from Calc options dialog and SID_AUTOSPELL_CHECK
+ */
+void ScModule::ModifyOptions( const SfxItemSet& rOptSet )
+{
+ LanguageType nOldSpellLang, nOldCjkLang, nOldCtlLang;
+ bool bOldAutoSpell;
+ GetSpellSettings( nOldSpellLang, nOldCjkLang, nOldCtlLang, bOldAutoSpell );
+
+ if (!m_pAppCfg)
+ GetAppOptions();
+ OSL_ENSURE( m_pAppCfg, "AppOptions not initialised :-(" );
+
+ if (!m_pInputCfg)
+ GetInputOptions();
+ OSL_ENSURE( m_pInputCfg, "InputOptions not initialised :-(" );
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ SfxBindings* pBindings = pViewFrm ? &pViewFrm->GetBindings() : nullptr;
+
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
+ ScDocument* pDoc = pDocSh ? &pDocSh->GetDocument() : nullptr;
+ bool bRepaint = false;
+ bool bUpdateMarks = false;
+ bool bUpdateRefDev = false;
+ bool bCalcAll = false;
+ bool bSaveAppOptions = false;
+ bool bSaveInputOptions = false;
+ bool bCompileErrorCells = false;
+
+ // SfxGetpApp()->SetOptions( rOptSet );
+
+ ScAppOptions aAppOptions = m_pAppCfg->GetOptions();
+
+ // No more linguistics
+ if (const SfxUInt16Item* pItem = rOptSet.GetItemIfSet(SID_ATTR_METRIC))
+ {
+ PutItem( *pItem );
+ aAppOptions.SetAppMetric( static_cast<FieldUnit>(pItem->GetValue()) );
+ bSaveAppOptions = true;
+ }
+
+ if (const ScUserListItem* pItem = rOptSet.GetItemIfSet(SCITEM_USERLIST))
+ {
+ ScGlobal::SetUserList( pItem->GetUserList() );
+ bSaveAppOptions = true;
+ }
+
+ if (const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_OPT_SYNCZOOM))
+ {
+ aAppOptions.SetSynchronizeZoom( pItem->GetValue() );
+ bSaveAppOptions = true;
+ }
+
+ if (const SfxUInt16Item* pItem = rOptSet.GetItemIfSet(SID_SC_OPT_KEY_BINDING_COMPAT))
+ {
+ sal_uInt16 nVal = pItem->GetValue();
+ ScOptionsUtil::KeyBindingType eOld = aAppOptions.GetKeyBindingType();
+ ScOptionsUtil::KeyBindingType eNew = static_cast<ScOptionsUtil::KeyBindingType>(nVal);
+ if (eOld != eNew)
+ {
+ aAppOptions.SetKeyBindingType(eNew);
+ bSaveAppOptions = true;
+ ScDocShell::ResetKeyBindings(eNew);
+ }
+ }
+
+ // DefaultsOptions
+ if (const ScTpDefaultsItem* pItem = rOptSet.GetItemIfSet(SID_SCDEFAULTSOPTIONS))
+ {
+ const ScDefaultsOptions& rOpt = pItem->GetDefaultsOptions();
+ SetDefaultsOptions( rOpt );
+ }
+
+ // FormulaOptions
+ if (const ScTpFormulaItem* pItem = rOptSet.GetItemIfSet(SID_SCFORMULAOPTIONS))
+ {
+ const ScFormulaOptions& rOpt = pItem->GetFormulaOptions();
+
+ if (!m_pFormulaCfg || (*m_pFormulaCfg != rOpt))
+ // Formula options have changed. Repaint the column headers.
+ bRepaint = true;
+
+ if (m_pFormulaCfg && m_pFormulaCfg->GetUseEnglishFuncName() != rOpt.GetUseEnglishFuncName())
+ {
+ // Re-compile formula cells with error as the error may have been
+ // caused by unresolved function names.
+ bCompileErrorCells = true;
+ }
+
+ // Recalc for interpreter options changes.
+ if (m_pFormulaCfg && m_pFormulaCfg->GetCalcConfig() != rOpt.GetCalcConfig())
+ bCalcAll = true;
+
+ if ( pDocSh )
+ {
+ pDocSh->SetFormulaOptions( rOpt );
+ pDocSh->SetDocumentModified();
+ }
+
+ // ScDocShell::SetFormulaOptions() may check for changed settings, so
+ // set the new options here after that has been called.
+ if (!bCalcAll || rOpt.GetWriteCalcConfig())
+ {
+ // CalcConfig is new, didn't change or is global, simply set all.
+ SetFormulaOptions( rOpt );
+ }
+ else
+ {
+ // If "only for current document" was checked, reset those affected
+ // by that setting to previous values.
+ ScFormulaOptions aNewOpt( rOpt);
+ aNewOpt.GetCalcConfig().MergeDocumentSpecific( m_pFormulaCfg->GetCalcConfig());
+ SetFormulaOptions( aNewOpt);
+ }
+ }
+
+ // ViewOptions
+ if (const ScTpViewItem* pItem = rOptSet.GetItemIfSet(SID_SCVIEWOPTIONS))
+ {
+ const ScViewOptions& rNewOpt = pItem->GetViewOptions();
+
+ if ( pViewSh )
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ const ScViewOptions& rOldOpt = rViewData.GetOptions();
+
+ bool bAnchorList = ( rOldOpt.GetOption( VOPT_ANCHOR ) !=
+ rNewOpt.GetOption( VOPT_ANCHOR ) );
+
+ if ( rOldOpt != rNewOpt )
+ {
+ rViewData.SetOptions( rNewOpt ); // Changes rOldOpt
+ rViewData.GetDocument().SetViewOptions( rNewOpt );
+ if (pDocSh)
+ pDocSh->SetDocumentModified();
+ bRepaint = true;
+ }
+ if ( bAnchorList )
+ pViewSh->UpdateAnchorHandles();
+ }
+ SetViewOptions( rNewOpt );
+ if (pBindings)
+ {
+ pBindings->Invalidate(SID_HELPLINES_MOVE);
+ }
+ }
+
+ // GridOptions
+ // Evaluate after ViewOptions, as GridOptions is a member of ViewOptions
+ if ( const SvxGridItem* pItem = rOptSet.GetItemIfSet(SID_ATTR_GRID_OPTIONS) )
+ {
+ ScGridOptions aNewGridOpt( *pItem );
+
+ if ( pViewSh )
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScViewOptions aNewViewOpt( rViewData.GetOptions() );
+ const ScGridOptions& rOldGridOpt = aNewViewOpt.GetGridOptions();
+
+ if ( rOldGridOpt != aNewGridOpt )
+ {
+ aNewViewOpt.SetGridOptions( aNewGridOpt );
+ rViewData.SetOptions( aNewViewOpt );
+ rViewData.GetDocument().SetViewOptions( aNewViewOpt );
+ if (pDocSh)
+ pDocSh->SetDocumentModified();
+ bRepaint = true;
+ }
+ }
+ ScViewOptions aNewViewOpt ( GetViewOptions() );
+ aNewViewOpt.SetGridOptions( aNewGridOpt );
+ SetViewOptions( aNewViewOpt );
+ if (pBindings)
+ {
+ pBindings->Invalidate(SID_GRID_VISIBLE);
+ pBindings->Invalidate(SID_GRID_USE);
+ }
+ }
+
+ // DocOptions
+ if ( const ScTpCalcItem* pItem = rOptSet.GetItemIfSet(SID_SCDOCOPTIONS) )
+ {
+ const ScDocOptions& rNewOpt = pItem->GetDocOptions();
+
+ if ( pDoc )
+ {
+ const ScDocOptions& rOldOpt = pDoc->GetDocOptions();
+
+ bRepaint = ( bRepaint || ( rOldOpt != rNewOpt ) );
+ bCalcAll = bRepaint &&
+ ( rOldOpt.IsIter() != rNewOpt.IsIter()
+ || rOldOpt.GetIterCount() != rNewOpt.GetIterCount()
+ || rOldOpt.GetIterEps() != rNewOpt.GetIterEps()
+ || rOldOpt.IsIgnoreCase() != rNewOpt.IsIgnoreCase()
+ || rOldOpt.IsCalcAsShown() != rNewOpt.IsCalcAsShown()
+ || (rNewOpt.IsCalcAsShown() &&
+ rOldOpt.GetStdPrecision() != rNewOpt.GetStdPrecision())
+ || rOldOpt.IsMatchWholeCell() != rNewOpt.IsMatchWholeCell()
+ || rOldOpt.GetYear2000() != rNewOpt.GetYear2000()
+ || rOldOpt.IsFormulaRegexEnabled() != rNewOpt.IsFormulaRegexEnabled()
+ || rOldOpt.IsFormulaWildcardsEnabled() != rNewOpt.IsFormulaWildcardsEnabled()
+ );
+ pDoc->SetDocOptions( rNewOpt );
+ pDocSh->SetDocumentModified();
+ }
+ SetDocOptions( rNewOpt );
+ }
+
+ // Set TabDistance after the actual DocOptions
+ if ( const SfxUInt16Item* pItem = rOptSet.GetItemIfSet(SID_ATTR_DEFTABSTOP) )
+ {
+ sal_uInt16 nTabDist = pItem->GetValue();
+ ScDocOptions aOpt(GetDocOptions());
+ aOpt.SetTabDistance(nTabDist);
+ SetDocOptions( aOpt );
+
+ if ( pDoc )
+ {
+ ScDocOptions aDocOpt(pDoc->GetDocOptions());
+ aDocOpt.SetTabDistance(nTabDist);
+ pDoc->SetDocOptions( aDocOpt );
+ pDocSh->SetDocumentModified();
+ if(pDoc->GetDrawLayer())
+ pDoc->GetDrawLayer()->SetDefaultTabulator(nTabDist);
+ }
+ }
+
+ // AutoSpell after the DocOptions (due to being a member)
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_AUTOSPELL_CHECK) ) // At DocOptions
+ {
+ bool bDoAutoSpell = pItem->GetValue();
+
+ if (pDoc)
+ {
+ ScDocOptions aNewOpt = pDoc->GetDocOptions();
+ if ( aNewOpt.IsAutoSpell() != bDoAutoSpell )
+ {
+ aNewOpt.SetAutoSpell( bDoAutoSpell );
+ pDoc->SetDocOptions( aNewOpt );
+
+ if (pViewSh)
+ pViewSh->EnableAutoSpell(bDoAutoSpell);
+
+ bRepaint = true; // Because HideAutoSpell might be invalid
+ //TODO: Paint all Views?
+ }
+ }
+
+ if ( bOldAutoSpell != bDoAutoSpell )
+ SetAutoSpellProperty( bDoAutoSpell );
+ if ( pDocSh )
+ pDocSh->PostPaintGridAll(); // Due to marks
+ ScInputHandler* pInputHandler = GetInputHdl();
+ if ( pInputHandler )
+ pInputHandler->UpdateSpellSettings(); // EditEngine flags
+ if ( pViewSh )
+ pViewSh->UpdateDrawTextOutliner(); // EditEngine flags
+
+ if (pBindings)
+ pBindings->Invalidate( SID_AUTOSPELL_CHECK );
+ }
+
+ // InputOptions
+ ScInputOptions aInputOptions = m_pInputCfg->GetOptions();
+ if ( const SfxUInt16Item* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_SELECTIONPOS) )
+ {
+ aInputOptions.SetMoveDir( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_SELECTION) )
+ {
+ aInputOptions.SetMoveSelection( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_EDITMODE) )
+ {
+ aInputOptions.SetEnterEdit( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_FMT_EXPAND) )
+ {
+ aInputOptions.SetExtendFormat( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_RANGEFINDER) )
+ {
+ aInputOptions.SetRangeFinder( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_REF_EXPAND) )
+ {
+ aInputOptions.SetExpandRefs( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+ if (const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_OPT_SORT_REF_UPDATE))
+ {
+ aInputOptions.SetSortRefUpdate( pItem->GetValue());
+ bSaveInputOptions = true;
+ }
+
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_MARK_HEADER) )
+ {
+ aInputOptions.SetMarkHeader( pItem->GetValue() );
+ bSaveInputOptions = true;
+ bUpdateMarks = true;
+ }
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_TEXTWYSIWYG) )
+ {
+ bool bNew = pItem->GetValue();
+ if ( bNew != aInputOptions.GetTextWysiwyg() )
+ {
+ aInputOptions.SetTextWysiwyg( bNew );
+ bSaveInputOptions = true;
+ bUpdateRefDev = true;
+ }
+ }
+ if( const SfxBoolItem* pItem = rOptSet.GetItemIfSet( SID_SC_INPUT_REPLCELLSWARN ) )
+ {
+ aInputOptions.SetReplaceCellsWarn( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+
+ if( const SfxBoolItem* pItem = rOptSet.GetItemIfSet( SID_SC_INPUT_LEGACY_CELL_SELECTION ) )
+ {
+ aInputOptions.SetLegacyCellSelection( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+
+ if( const SfxBoolItem* pItem = rOptSet.GetItemIfSet( SID_SC_INPUT_ENTER_PASTE_MODE ) )
+ {
+ aInputOptions.SetEnterPasteMode( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+
+ // PrintOptions
+ if ( const ScTpPrintItem* pItem = rOptSet.GetItemIfSet(SID_SCPRINTOPTIONS) )
+ {
+ const ScPrintOptions& rNewOpt = pItem->GetPrintOptions();
+ SetPrintOptions( rNewOpt );
+
+ // broadcast causes all previews to recalc page numbers
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScPrintOptions ) );
+ }
+
+ if ( bSaveAppOptions )
+ m_pAppCfg->SetOptions(aAppOptions);
+
+ if ( bSaveInputOptions )
+ m_pInputCfg->SetOptions(aInputOptions);
+
+ // Kick off recalculation?
+ if (pDoc && bCompileErrorCells)
+ {
+ // Re-compile cells with name error, and recalc if at least one cell
+ // has been re-compiled. In the future we may want to find a way to
+ // recalc only those that are affected.
+ if (pDoc->CompileErrorCells(FormulaError::NoName))
+ bCalcAll = true;
+ }
+
+ if ( pDoc && bCalcAll )
+ {
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+ pDoc->CalcAll();
+ if ( pViewSh )
+ pViewSh->UpdateCharts( true );
+ else
+ ScDBFunc::DoUpdateCharts( ScAddress(), *pDoc, true );
+ if (pBindings)
+ pBindings->Invalidate( SID_ATTR_SIZE ); //SvxPosSize StatusControl Update
+ }
+
+ if ( pViewSh && bUpdateMarks )
+ pViewSh->UpdateAutoFillMark();
+
+ // Repaint View?
+ if ( pViewSh && bRepaint )
+ {
+ pViewSh->UpdateFixPos();
+ pViewSh->PaintGrid();
+ pViewSh->PaintTop();
+ pViewSh->PaintLeft();
+ pViewSh->PaintExtras();
+ pViewSh->InvalidateBorder();
+ if (pBindings)
+ {
+ pBindings->Invalidate( FID_TOGGLEHEADERS ); // -> Checks in menu
+ pBindings->Invalidate( FID_TOGGLESYNTAX );
+ }
+ }
+
+ // update ref device (for all documents)
+ if ( !bUpdateRefDev )
+ return;
+
+ // for all documents: recalc output factor, update row heights
+ SfxObjectShell* pObjSh = SfxObjectShell::GetFirst();
+ while ( pObjSh )
+ {
+ if ( auto pOneDocSh = dynamic_cast<ScDocShell *>(pObjSh) )
+ {
+ pOneDocSh->CalcOutputFactor();
+ SCTAB nTabCount = pOneDocSh->GetDocument().GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ pOneDocSh->AdjustRowHeight( 0, pDocSh->GetDocument().MaxRow(), nTab );
+ }
+ pObjSh = SfxObjectShell::GetNext( *pObjSh );
+ }
+
+ // for all (tab-) views:
+ SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
+ while ( pSh )
+ {
+ ScTabViewShell* pOneViewSh = static_cast<ScTabViewShell*>(pSh);
+
+ // set ref-device for EditEngine
+ ScInputHandler* pHdl = GetInputHdl(pOneViewSh);
+ if (pHdl)
+ pHdl->UpdateRefDevice();
+
+ // update view scale
+ ScViewData& rViewData = pOneViewSh->GetViewData();
+ pOneViewSh->SetZoom( rViewData.GetZoomX(), rViewData.GetZoomY(), false );
+
+ // repaint
+ pOneViewSh->PaintGrid();
+ pOneViewSh->PaintTop();
+ pOneViewSh->PaintLeft();
+
+ pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> );
+ }
+}
+
+/**
+ * Input-Handler
+ */
+ScInputHandler* ScModule::GetInputHdl( ScTabViewShell* pViewSh, bool bUseRef )
+{
+ if ( !comphelper::LibreOfficeKit::isActive() && m_pRefInputHandler && bUseRef )
+ return m_pRefInputHandler;
+
+ ScInputHandler* pHdl = nullptr;
+ if ( !pViewSh )
+ {
+ // in case a UIActive embedded object has no ViewShell (UNO component)
+ // the own calc view shell will be set as current, but no handling should happen
+ ScTabViewShell* pCurViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ if ( pCurViewSh && !pCurViewSh->GetUIActiveClient() )
+ pViewSh = pCurViewSh;
+ }
+
+ if ( pViewSh )
+ pHdl = pViewSh->GetInputHandler(); // Viewshell always has one, from now on
+
+ // If no ViewShell passed or active, we can get NULL
+ OSL_ENSURE( pHdl || !pViewSh, "GetInputHdl: no InputHandler found!" );
+ return pHdl;
+}
+
+void ScModule::ViewShellChanged(bool bStopEditing /*=true*/)
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ ScTabViewShell* pShell = ScTabViewShell::GetActiveViewShell();
+ if ( pShell && pHdl )
+ pShell->UpdateInputHandler(false, bStopEditing);
+}
+
+void ScModule::SetInputMode( ScInputMode eMode, const OUString* pInitText )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->SetMode(eMode, pInitText);
+}
+
+bool ScModule::IsEditMode()
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ return pHdl && pHdl->IsEditMode();
+}
+
+bool ScModule::IsInputMode()
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ return pHdl && pHdl->IsInputMode();
+}
+
+bool ScModule::InputKeyEvent( const KeyEvent& rKEvt, bool bStartEdit )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ return pHdl && pHdl->KeyInput( rKEvt, bStartEdit );
+}
+
+void ScModule::InputEnterHandler( ScEnterMode nBlockMode, bool bBeforeSavingInLOK )
+{
+ if ( !SfxGetpApp()->IsDowning() ) // Not when quitting the program
+ {
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->EnterHandler( nBlockMode, bBeforeSavingInLOK );
+ }
+}
+
+void ScModule::InputCancelHandler()
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->CancelHandler();
+}
+
+void ScModule::InputSelection( const EditView* pView )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->InputSelection( pView );
+}
+
+void ScModule::InputChanged( const EditView* pView )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->InputChanged( pView, false );
+}
+
+void ScModule::ViewShellGone( const ScTabViewShell* pViewSh )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->ViewShellGone( pViewSh );
+}
+
+void ScModule::SetRefInputHdl( ScInputHandler* pNew )
+{
+ m_pRefInputHandler = pNew;
+}
+
+void ScModule::InputGetSelection( sal_Int32& rStart, sal_Int32& rEnd )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->InputGetSelection( rStart, rEnd );
+}
+
+void ScModule::InputSetSelection( sal_Int32 nStart, sal_Int32 nEnd )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->InputSetSelection( nStart, nEnd );
+}
+
+void ScModule::InputReplaceSelection( const OUString& rStr )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->InputReplaceSelection( rStr );
+}
+
+void ScModule::InputTurnOffWinEngine()
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->InputTurnOffWinEngine();
+}
+
+void ScModule::ActivateInputWindow( const OUString* pStrFormula, bool bMatrix )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if ( !pHdl )
+ return;
+
+ ScInputWindow* pWin = pHdl->GetInputWindow();
+ if ( pStrFormula )
+ {
+ // Take over formula
+ if ( pWin )
+ {
+ pWin->SetFuncString( *pStrFormula, false );
+ // SetSumAssignMode due to sal_False not necessary
+ }
+ ScEnterMode nMode = bMatrix ? ScEnterMode::MATRIX : ScEnterMode::NORMAL;
+ pHdl->EnterHandler( nMode );
+
+ // Without Invalidate the selection remains active, if the formula has not changed
+ if (pWin)
+ pWin->TextInvalidate();
+ }
+ else
+ {
+ // Cancel
+ if ( pWin )
+ {
+ pWin->SetFuncString( OUString(), false );
+ // SetSumAssignMode due to sal_False no necessary
+ }
+ pHdl->CancelHandler();
+ }
+}
+
+/**
+ * Reference dialogs
+ */
+void ScModule::SetRefDialog( sal_uInt16 nId, bool bVis, SfxViewFrame* pViewFrm )
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+ if ( !(m_nCurRefDlgId == 0 || ( nId == m_nCurRefDlgId && !bVis )
+ || ( comphelper::LibreOfficeKit::isActive() )) )
+ return;
+
+ if ( !pViewFrm )
+ pViewFrm = SfxViewFrame::Current();
+
+ // bindings update causes problems with update of stylist if
+ // current style family has changed
+ //if ( pViewFrm )
+ // pViewFrm->GetBindings().Update(); // to avoid trouble in LockDispatcher
+
+ // before SetChildWindow
+ if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ if ( bVis )
+ m_nCurRefDlgId = nId;
+ }
+ else
+ {
+ m_nCurRefDlgId = bVis ? nId : 0;
+ }
+
+ if ( pViewFrm )
+ {
+ // store the dialog id also in the view shell
+ SfxViewShell* pViewSh = pViewFrm->GetViewShell();
+ if (ScTabViewShell* pTabViewSh = dynamic_cast<ScTabViewShell*>(pViewSh))
+ pTabViewSh->SetCurRefDlgId(m_nCurRefDlgId);
+ else
+ {
+ // no ScTabViewShell - possible for example from a Basic macro
+ bVis = false;
+ m_nCurRefDlgId = 0; // don't set nCurRefDlgId if no dialog is created
+ }
+
+ pViewFrm->SetChildWindow( nId, bVis );
+ }
+
+ SfxApplication* pSfxApp = SfxGetpApp();
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
+}
+
+static SfxChildWindow* lcl_GetChildWinFromCurrentView( sal_uInt16 nId )
+{
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+
+ // #i46999# current view frame can be null (for example, when closing help)
+ return pViewFrm ? pViewFrm->GetChildWindow( nId ) : nullptr;
+}
+
+static SfxChildWindow* lcl_GetChildWinFromAnyView( sal_uInt16 nId )
+{
+ // First, try the current view
+ SfxChildWindow* pChildWnd = lcl_GetChildWinFromCurrentView( nId );
+ if ( pChildWnd )
+ return pChildWnd; // found in the current view
+
+ // if not found there, get the child window from any open view
+ // it can be open only in one view because nCurRefDlgId is global
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::GetFirst();
+ while ( pViewFrm )
+ {
+ pChildWnd = pViewFrm->GetChildWindow( nId );
+ if ( pChildWnd )
+ return pChildWnd; // found in any view
+
+ pViewFrm = SfxViewFrame::GetNext( *pViewFrm );
+ }
+
+ return nullptr; // none found
+}
+
+bool ScModule::IsModalMode(SfxObjectShell* pDocSh)
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+ bool bIsModal = false;
+
+ if ( m_nCurRefDlgId )
+ {
+ SfxChildWindow* pChildWnd = lcl_GetChildWinFromCurrentView( m_nCurRefDlgId );
+ if ( pChildWnd )
+ {
+ if (pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
+ assert(pRefDlg);
+ bIsModal = pChildWnd->IsVisible() && pRefDlg &&
+ !( pRefDlg->IsRefInputMode() && pRefDlg->IsDocAllowed(pDocSh) );
+ }
+ }
+ else if ( pDocSh && comphelper::LibreOfficeKit::isActive() )
+ {
+ // m_nCurRefDlgId is not deglobalized so it can be set by other view
+ // in LOK case when no ChildWindow for this view was detected -> fallback
+ ScInputHandler* pHdl = GetInputHdl();
+ if ( pHdl )
+ bIsModal = pHdl->IsModalMode(pDocSh);
+ }
+ }
+ else if (pDocSh)
+ {
+ ScInputHandler* pHdl = GetInputHdl();
+ if ( pHdl )
+ bIsModal = pHdl->IsModalMode(pDocSh);
+ }
+
+ return bIsModal;
+}
+
+bool ScModule::IsTableLocked()
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+ bool bLocked = false;
+
+ // Up until now just for ScAnyRefDlg
+ if ( m_nCurRefDlgId )
+ {
+ SfxChildWindow* pChildWnd = lcl_GetChildWinFromAnyView( m_nCurRefDlgId );
+ if ( pChildWnd )
+ {
+ if (pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
+ assert(pRefDlg);
+ if (pRefDlg)
+ bLocked = pRefDlg->IsTableLocked();
+ }
+ }
+ else if (!comphelper::LibreOfficeKit::isActive())
+ bLocked = true; // for other views, see IsModalMode
+ }
+
+ // We can't stop LOK clients from switching part, and getting out of sync.
+ assert(!bLocked || !comphelper::LibreOfficeKit::isActive());
+
+ return bLocked;
+}
+
+bool ScModule::IsRefDialogOpen()
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+ bool bIsOpen = false;
+
+ if ( m_nCurRefDlgId )
+ {
+ SfxChildWindow* pChildWnd = lcl_GetChildWinFromCurrentView( m_nCurRefDlgId );
+ if ( pChildWnd )
+ bIsOpen = pChildWnd->IsVisible();
+ }
+
+ return bIsOpen;
+}
+
+bool ScModule::IsFormulaMode()
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+ bool bIsFormula = false;
+
+ if ( m_nCurRefDlgId )
+ {
+ SfxChildWindow* pChildWnd = nullptr;
+
+ if ( comphelper::LibreOfficeKit::isActive() )
+ pChildWnd = lcl_GetChildWinFromCurrentView( m_nCurRefDlgId );
+ else
+ pChildWnd = lcl_GetChildWinFromAnyView( m_nCurRefDlgId );
+
+ if ( pChildWnd )
+ {
+ if (pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
+ assert(pRefDlg);
+ bIsFormula = pChildWnd->IsVisible() && pRefDlg && pRefDlg->IsRefInputMode();
+ }
+ }
+ else if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ // m_nCurRefDlgId is not deglobalized so it can be set by other view
+ // in LOK case when no ChildWindow for this view was detected -> fallback
+ ScInputHandler* pHdl = GetInputHdl();
+ if ( pHdl )
+ bIsFormula = pHdl->IsFormulaMode();
+ }
+ }
+ else
+ {
+ ScInputHandler* pHdl = GetInputHdl();
+ if ( pHdl )
+ bIsFormula = pHdl->IsFormulaMode();
+ }
+
+ if (m_bIsInEditCommand)
+ bIsFormula = true;
+
+ return bIsFormula;
+}
+
+static void lcl_MarkedTabs( const ScMarkData& rMark, SCTAB& rStartTab, SCTAB& rEndTab )
+{
+ if (rMark.GetSelectCount() > 1)
+ {
+ rEndTab = rMark.GetLastSelected();
+ rStartTab = rMark.GetFirstSelected();
+ }
+}
+
+void ScModule::SetReference( const ScRange& rRef, ScDocument& rDoc,
+ const ScMarkData* pMarkData )
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+
+ // In RefDialogs we also trigger the ZoomIn, if the Ref's Start and End are different
+ ScRange aNew = rRef;
+ aNew.PutInOrder(); // Always in the right direction
+
+ if( m_nCurRefDlgId )
+ {
+ SfxChildWindow* pChildWnd = nullptr;
+
+ if ( comphelper::LibreOfficeKit::isActive() )
+ pChildWnd = lcl_GetChildWinFromCurrentView( m_nCurRefDlgId );
+ else
+ pChildWnd = lcl_GetChildWinFromAnyView( m_nCurRefDlgId );
+
+ OSL_ENSURE( pChildWnd, "NoChildWin" );
+ if ( pChildWnd )
+ {
+ if ( m_nCurRefDlgId == SID_OPENDLG_CONSOLIDATE && pMarkData )
+ {
+ SCTAB nStartTab = aNew.aStart.Tab();
+ SCTAB nEndTab = aNew.aEnd.Tab();
+ lcl_MarkedTabs( *pMarkData, nStartTab, nEndTab );
+ aNew.aStart.SetTab(nStartTab);
+ aNew.aEnd.SetTab(nEndTab);
+ }
+
+ if (pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
+ assert(pRefDlg);
+ if(pRefDlg)
+ {
+ // hide the (color) selection now instead of later from LoseFocus,
+ // don't abort the ref input that causes this call (bDoneRefMode = sal_False)
+ pRefDlg->HideReference( false );
+ pRefDlg->SetReference( aNew, rDoc );
+ }
+ }
+ }
+ else if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ // m_nCurRefDlgId is not deglobalized so it can be set by other view
+ // in LOK case when no ChildWindow for this view was detected -> fallback
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->SetReference( aNew, rDoc );
+ }
+ }
+ else
+ {
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->SetReference( aNew, rDoc );
+ else
+ {
+ OSL_FAIL("SetReference without receiver");
+ }
+ }
+}
+
+/**
+ * Multiple selection
+ */
+void ScModule::AddRefEntry()
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+ if ( m_nCurRefDlgId )
+ {
+ SfxChildWindow* pChildWnd = lcl_GetChildWinFromAnyView( m_nCurRefDlgId );
+ OSL_ENSURE( pChildWnd, "NoChildWin" );
+ if ( pChildWnd )
+ {
+ if (pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
+ assert(pRefDlg);
+ if (pRefDlg)
+ {
+ pRefDlg->AddRefEntry();
+ }
+ }
+ }
+ }
+ else
+ {
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->AddRefEntry();
+ }
+}
+
+void ScModule::EndReference()
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+
+ // We also annul the ZoomIn again in RefDialogs
+
+ //FIXME: ShowRefFrame at InputHdl, if the Function AutoPilot is open?
+ if ( !m_nCurRefDlgId )
+ return;
+
+ SfxChildWindow* pChildWnd = nullptr;
+
+ if ( comphelper::LibreOfficeKit::isActive() )
+ pChildWnd = lcl_GetChildWinFromCurrentView( m_nCurRefDlgId );
+ else
+ pChildWnd = lcl_GetChildWinFromAnyView( m_nCurRefDlgId );
+
+ OSL_ENSURE( pChildWnd, "NoChildWin" );
+ if ( pChildWnd )
+ {
+ if (pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
+ assert(pRefDlg);
+ if(pRefDlg)
+ {
+ pRefDlg->SetActive();
+ }
+ }
+ }
+}
+
+/**
+ * Idle/OnlineSpelling
+ */
+void ScModule::AnythingChanged()
+{
+ sal_uInt64 nOldTime = m_aIdleTimer.GetTimeout();
+ if ( nOldTime != SC_IDLE_MIN )
+ m_aIdleTimer.SetTimeout( SC_IDLE_MIN );
+
+ nIdleCount = 0;
+}
+
+static void lcl_CheckNeedsRepaint( const ScDocShell* pDocShell )
+{
+ SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell );
+ while ( pFrame )
+ {
+ SfxViewShell* p = pFrame->GetViewShell();
+ ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p );
+ if ( pViewSh )
+ pViewSh->CheckNeedsRepaint();
+ pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell );
+ }
+}
+
+IMPL_LINK_NOARG(ScModule, IdleHandler, Timer *, void)
+{
+ if ( Application::AnyInput( VclInputFlags::MOUSE | VclInputFlags::KEYBOARD ) )
+ {
+ m_aIdleTimer.Start(); // Timeout unchanged
+ return;
+ }
+
+ bool bMore = false;
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>(SfxObjectShell::Current());
+
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ sc::DocumentLinkManager& rLinkMgr = rDoc.GetDocLinkManager();
+ bool bLinks = rLinkMgr.idleCheckLinks();
+ bool bWidth = rDoc.IdleCalcTextWidth();
+
+ bMore = bLinks || bWidth; // Still something at all?
+
+ // While calculating a Basic formula, a paint event may have occurred,
+ // so check the bNeedsRepaint flags for this document's views
+ if (bWidth)
+ lcl_CheckNeedsRepaint( pDocSh );
+ }
+
+
+ sal_uInt64 nOldTime = m_aIdleTimer.GetTimeout();
+ sal_uInt64 nNewTime = nOldTime;
+ if ( bMore )
+ {
+ nNewTime = SC_IDLE_MIN;
+ nIdleCount = 0;
+ }
+ else
+ {
+ // Set SC_IDLE_COUNT to initial Timeout - increase afterwards
+ if ( nIdleCount < SC_IDLE_COUNT )
+ ++nIdleCount;
+ else
+ {
+ nNewTime += SC_IDLE_STEP;
+ if ( nNewTime > SC_IDLE_MAX )
+ nNewTime = SC_IDLE_MAX;
+ }
+ }
+ if ( nNewTime != nOldTime )
+ m_aIdleTimer.SetTimeout( nNewTime );
+
+
+ m_aIdleTimer.Start();
+}
+
+/**
+ * Virtual methods for the OptionsDialog
+ */
+std::optional<SfxItemSet> ScModule::CreateItemSet( sal_uInt16 nId )
+{
+ std::optional<SfxItemSet> pRet;
+ if(SID_SC_EDITOPTIONS == nId)
+ {
+ pRet.emplace(
+ GetPool(),
+ svl::Items<
+ // TP_USERLISTS:
+ SCITEM_USERLIST, SCITEM_USERLIST,
+ // TP_GRID:
+ SID_ATTR_GRID_OPTIONS, SID_ATTR_GRID_OPTIONS,
+ SID_ATTR_METRIC, SID_ATTR_METRIC,
+ SID_ATTR_DEFTABSTOP, SID_ATTR_DEFTABSTOP,
+ // TP_INPUT:
+ SID_SC_INPUT_LEGACY_CELL_SELECTION, SID_SC_OPT_SORT_REF_UPDATE,
+ // TP_FORMULA, TP_DEFAULTS:
+ SID_SCFORMULAOPTIONS, SID_SCDEFAULTSOPTIONS,
+ // TP_VIEW, TP_CALC:
+ SID_SCVIEWOPTIONS, SID_SCDOCOPTIONS,
+ // TP_INPUT:
+ SID_SC_INPUT_ENTER_PASTE_MODE, SID_SC_INPUT_ENTER_PASTE_MODE,
+ // TP_PRINT:
+ SID_SCPRINTOPTIONS, SID_SCPRINTOPTIONS,
+ // TP_INPUT:
+ SID_SC_INPUT_SELECTION, SID_SC_INPUT_MARK_HEADER,
+ SID_SC_INPUT_TEXTWYSIWYG, SID_SC_INPUT_TEXTWYSIWYG,
+ SID_SC_INPUT_REPLCELLSWARN, SID_SC_INPUT_REPLCELLSWARN,
+ // TP_VIEW:
+ SID_SC_OPT_SYNCZOOM, SID_SC_OPT_KEY_BINDING_COMPAT>);
+
+ const ScAppOptions& rAppOpt = GetAppOptions();
+
+ ScDocShell* pDocSh = dynamic_cast< ScDocShell *>( SfxObjectShell::Current() );
+ ScDocOptions aCalcOpt = pDocSh
+ ? pDocSh->GetDocument().GetDocOptions()
+ : GetDocOptions();
+
+ ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( SfxViewShell::Current() );
+ ScViewOptions aViewOpt = pViewSh
+ ? pViewSh->GetViewData().GetOptions()
+ : GetViewOptions();
+
+ ScUserListItem aULItem( SCITEM_USERLIST );
+ ScUserList* pUL = ScGlobal::GetUserList();
+
+ // SfxGetpApp()->GetOptions( aSet );
+
+ pRet->Put( SfxUInt16Item( SID_ATTR_METRIC,
+ sal::static_int_cast<sal_uInt16>(rAppOpt.GetAppMetric()) ) );
+
+ // TP_CALC
+ pRet->Put( SfxUInt16Item( SID_ATTR_DEFTABSTOP,
+ aCalcOpt.GetTabDistance()));
+ pRet->Put( ScTpCalcItem( SID_SCDOCOPTIONS, aCalcOpt ) );
+
+ // TP_VIEW
+ pRet->Put( ScTpViewItem( aViewOpt ) );
+ pRet->Put( SfxBoolItem( SID_SC_OPT_SYNCZOOM, rAppOpt.GetSynchronizeZoom() ) );
+
+ // TP_INPUT
+ const ScInputOptions& rInpOpt = GetInputOptions();
+ pRet->Put( SfxUInt16Item( SID_SC_INPUT_SELECTIONPOS,
+ rInpOpt.GetMoveDir() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_SELECTION,
+ rInpOpt.GetMoveSelection() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_EDITMODE,
+ rInpOpt.GetEnterEdit() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_FMT_EXPAND,
+ rInpOpt.GetExtendFormat() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_RANGEFINDER,
+ rInpOpt.GetRangeFinder() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_REF_EXPAND,
+ rInpOpt.GetExpandRefs() ) );
+ pRet->Put( SfxBoolItem(SID_SC_OPT_SORT_REF_UPDATE, rInpOpt.GetSortRefUpdate()));
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_MARK_HEADER,
+ rInpOpt.GetMarkHeader() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_TEXTWYSIWYG,
+ rInpOpt.GetTextWysiwyg() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_REPLCELLSWARN,
+ rInpOpt.GetReplaceCellsWarn() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_LEGACY_CELL_SELECTION,
+ rInpOpt.GetLegacyCellSelection() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_ENTER_PASTE_MODE,
+ rInpOpt.GetEnterPasteMode() ) );
+
+ // RID_SC_TP_PRINT
+ pRet->Put( ScTpPrintItem( GetPrintOptions() ) );
+
+ // TP_GRID
+ pRet->Put( aViewOpt.CreateGridItem() );
+
+ // TP_USERLISTS
+ if ( pUL )
+ {
+ aULItem.SetUserList( *pUL );
+ pRet->Put(aULItem);
+ }
+
+ // TP_COMPATIBILITY
+ pRet->Put( SfxUInt16Item( SID_SC_OPT_KEY_BINDING_COMPAT,
+ rAppOpt.GetKeyBindingType() ) );
+
+ // TP_DEFAULTS
+ pRet->Put( ScTpDefaultsItem( GetDefaultsOptions() ) );
+
+ // TP_FORMULA
+ ScFormulaOptions aOptions = GetFormulaOptions();
+ if (pDocSh)
+ {
+ ScCalcConfig aConfig( aOptions.GetCalcConfig());
+ aConfig.MergeDocumentSpecific( pDocSh->GetDocument().GetCalcConfig());
+ aOptions.SetCalcConfig( aConfig);
+ }
+ pRet->Put( ScTpFormulaItem( aOptions ) );
+ }
+ return pRet;
+}
+
+void ScModule::ApplyItemSet( sal_uInt16 nId, const SfxItemSet& rSet )
+{
+ if(SID_SC_EDITOPTIONS == nId)
+ {
+ ModifyOptions( rSet );
+ }
+}
+
+std::unique_ptr<SfxTabPage> ScModule::CreateTabPage( sal_uInt16 nId, weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet )
+{
+ std::unique_ptr<SfxTabPage> xRet;
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ switch(nId)
+ {
+ case SID_SC_TP_LAYOUT:
+ {
+ ::CreateTabPage ScTpLayoutOptionsCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_LAYOUT);
+ if (ScTpLayoutOptionsCreate)
+ xRet = (*ScTpLayoutOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case SID_SC_TP_CONTENT:
+ {
+ ::CreateTabPage ScTpContentOptionsCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_CONTENT);
+ if (ScTpContentOptionsCreate)
+ xRet = (*ScTpContentOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case SID_SC_TP_GRID:
+ xRet = SvxGridTabPage::Create(pPage, pController, rSet);
+ break;
+ case SID_SC_TP_USERLISTS:
+ {
+ ::CreateTabPage ScTpUserListsCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_USERLISTS);
+ if (ScTpUserListsCreate)
+ xRet = (*ScTpUserListsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case SID_SC_TP_CALC:
+ {
+ ::CreateTabPage ScTpCalcOptionsCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_CALC);
+ if (ScTpCalcOptionsCreate)
+ xRet = (*ScTpCalcOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case SID_SC_TP_FORMULA:
+ {
+ ::CreateTabPage ScTpFormulaOptionsCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_FORMULA);
+ if (ScTpFormulaOptionsCreate)
+ xRet = (*ScTpFormulaOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case SID_SC_TP_COMPATIBILITY:
+ {
+ ::CreateTabPage ScTpCompatOptionsCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_COMPATIBILITY);
+ if (ScTpCompatOptionsCreate)
+ xRet = (*ScTpCompatOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case SID_SC_TP_CHANGES:
+ {
+ ::CreateTabPage ScRedlineOptionsTabPageCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_CHANGES);
+ if (ScRedlineOptionsTabPageCreate)
+ xRet =(*ScRedlineOptionsTabPageCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case RID_SC_TP_PRINT:
+ {
+ ::CreateTabPage ScTpPrintOptionsCreate = pFact->GetTabPageCreatorFunc(RID_SC_TP_PRINT);
+ if (ScTpPrintOptionsCreate)
+ xRet = (*ScTpPrintOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case RID_SC_TP_DEFAULTS:
+ {
+ ::CreateTabPage ScTpDefaultsOptionsCreate = pFact->GetTabPageCreatorFunc(RID_SC_TP_DEFAULTS);
+ if (ScTpDefaultsOptionsCreate)
+ xRet = (*ScTpDefaultsOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ }
+
+ OSL_ENSURE( xRet, "ScModule::CreateTabPage(): no valid ID for TabPage!" );
+
+ return xRet;
+}
+
+IMPL_LINK( ScModule, CalcFieldValueHdl, EditFieldInfo*, pInfo, void )
+{
+ //TODO: Merge with ScFieldEditEngine!
+ if (!pInfo)
+ return;
+
+ const SvxFieldItem& rField = pInfo->GetField();
+ const SvxFieldData* pField = rField.GetField();
+
+ if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
+ {
+ // URLField
+ const OUString& aURL = pURLField->GetURL();
+
+ switch ( pURLField->GetFormat() )
+ {
+ case SvxURLFormat::AppDefault: //TODO: Settable in the App?
+ case SvxURLFormat::Repr:
+ {
+ pInfo->SetRepresentation( pURLField->GetRepresentation() );
+ }
+ break;
+
+ case SvxURLFormat::Url:
+ {
+ pInfo->SetRepresentation( aURL );
+ }
+ break;
+ }
+
+ svtools::ColorConfigEntry eEntry =
+ INetURLHistory::GetOrCreate()->QueryUrl( aURL ) ? svtools::LINKSVISITED : svtools::LINKS;
+ pInfo->SetTextColor( GetColorConfig().GetColorValue(eEntry).nColor );
+ }
+ else
+ {
+ OSL_FAIL("Unknown Field");
+ pInfo->SetRepresentation(OUString('?'));
+ }
+}
+
+void ScModule::RegisterRefController(sal_uInt16 nSlotId, std::shared_ptr<SfxDialogController>& rWnd, weld::Window* pWndAncestor)
+{
+ std::vector<std::pair<std::shared_ptr<SfxDialogController>, weld::Window*>> & rlRefWindow = m_mapRefController[nSlotId];
+
+ if (std::find_if(rlRefWindow.begin(), rlRefWindow.end(),
+ [rWnd](const std::pair<std::shared_ptr<SfxDialogController>, weld::Window*>& rCandidate)
+ {
+ return rCandidate.first.get() == rWnd.get();
+ }) == rlRefWindow.end())
+ {
+ rlRefWindow.emplace_back(rWnd, pWndAncestor);
+ }
+}
+
+void ScModule::UnregisterRefController(sal_uInt16 nSlotId, const std::shared_ptr<SfxDialogController>& rWnd)
+{
+ auto iSlot = m_mapRefController.find( nSlotId );
+
+ if( iSlot == m_mapRefController.end() )
+ return;
+
+ std::vector<std::pair<std::shared_ptr<SfxDialogController>, weld::Window*>> & rlRefWindow = iSlot->second;
+
+ auto i = std::find_if(rlRefWindow.begin(), rlRefWindow.end(),
+ [rWnd](const std::pair<std::shared_ptr<SfxDialogController>, weld::Window*>& rCandidate)
+ {
+ return rCandidate.first.get() == rWnd.get();
+ });
+
+ if( i == rlRefWindow.end() )
+ return;
+
+ rlRefWindow.erase( i );
+
+ if( rlRefWindow.empty() )
+ m_mapRefController.erase( nSlotId );
+}
+
+std::shared_ptr<SfxDialogController> ScModule::Find1RefWindow(sal_uInt16 nSlotId, const weld::Window *pWndAncestor)
+{
+ if (!pWndAncestor)
+ return nullptr;
+
+ auto iSlot = m_mapRefController.find( nSlotId );
+
+ if( iSlot == m_mapRefController.end() )
+ return nullptr;
+
+ std::vector<std::pair<std::shared_ptr<SfxDialogController>, weld::Window*>> & rlRefWindow = iSlot->second;
+
+ for (auto const& refWindow : rlRefWindow)
+ if ( refWindow.second == pWndAncestor )
+ return refWindow.first;
+
+ return nullptr;
+}
+
+using namespace com::sun::star;
+
+constexpr OUStringLiteral LINGUPROP_AUTOSPELL = u"IsSpellAuto";
+
+void ScModule::GetSpellSettings( LanguageType& rDefLang, LanguageType& rCjkLang, LanguageType& rCtlLang,
+ bool& rAutoSpell )
+{
+ // use SvtLinguConfig instead of service LinguProperties to avoid
+ // loading the linguistic component
+ SvtLinguConfig aConfig;
+
+ SvtLinguOptions aOptions;
+ aConfig.GetOptions( aOptions );
+
+ rDefLang = MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage, css::i18n::ScriptType::LATIN);
+ rCjkLang = MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage_CJK, css::i18n::ScriptType::ASIAN);
+ rCtlLang = MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage_CTL, css::i18n::ScriptType::COMPLEX);
+ rAutoSpell = aOptions.bIsSpellAuto;
+}
+
+void ScModule::SetAutoSpellProperty( bool bSet )
+{
+ // use SvtLinguConfig instead of service LinguProperties to avoid
+ // loading the linguistic component
+ SvtLinguConfig aConfig;
+
+ aConfig.SetProperty( LINGUPROP_AUTOSPELL, uno::Any(bSet) );
+}
+
+bool ScModule::HasThesaurusLanguage( LanguageType nLang )
+{
+ if ( nLang == LANGUAGE_NONE )
+ return false;
+
+ bool bHasLang = false;
+ try
+ {
+ uno::Reference< linguistic2::XThesaurus > xThes(LinguMgr::GetThesaurus());
+ if ( xThes.is() )
+ bHasLang = xThes->hasLocale( LanguageTag::convertToLocale( nLang ) );
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL("Error in Thesaurus");
+ }
+
+ return bHasLang;
+}
+
+std::optional<SfxStyleFamilies> ScModule::CreateStyleFamilies()
+{
+ SfxStyleFamilies aStyleFamilies;
+
+ aStyleFamilies.emplace_back(SfxStyleFamilyItem(SfxStyleFamily::Para,
+ ScResId(STR_STYLE_FAMILY_CELL),
+ BMP_STYLES_FAMILY_CELL,
+ RID_CELLSTYLEFAMILY, SC_MOD()->GetResLocale()));
+
+ aStyleFamilies.emplace_back(SfxStyleFamilyItem(SfxStyleFamily::Page,
+ ScResId(STR_STYLE_FAMILY_PAGE),
+ BMP_STYLES_FAMILY_PAGE,
+ RID_PAGESTYLEFAMILY, SC_MOD()->GetResLocale()));
+
+ return aStyleFamilies;
+}
+
+void ScModule::RegisterAutomationApplicationEventsCaller(css::uno::Reference< ooo::vba::XSinkCaller > const& xCaller)
+{
+ mxAutomationApplicationEventsCaller = xCaller;
+}
+
+void ScModule::CallAutomationApplicationEventSinks(const OUString& Method, css::uno::Sequence< css::uno::Any >& Arguments)
+{
+ if (mxAutomationApplicationEventsCaller.is())
+ mxAutomationApplicationEventsCaller->CallSinks(Method, Arguments);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/seltrans.cxx b/sc/source/ui/app/seltrans.cxx
new file mode 100644
index 000000000..6ba63e4dc
--- /dev/null
+++ b/sc/source/ui/app/seltrans.cxx
@@ -0,0 +1,429 @@
+/* -*- 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 <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/form/FormButtonType.hpp>
+
+#include <tools/urlobj.hxx>
+#include <sfx2/docfile.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdouno.hxx>
+#include <osl/diagnose.h>
+
+#include <seltrans.hxx>
+#include <transobj.hxx>
+#include <drwtrans.hxx>
+#include <scmod.hxx>
+#include <dbfunc.hxx>
+#include <docsh.hxx>
+#include <drawview.hxx>
+#include <drwlayer.hxx>
+#include <markdata.hxx>
+
+using namespace com::sun::star;
+
+static bool lcl_IsURLButton( SdrObject* pObject )
+{
+ bool bRet = false;
+
+ SdrUnoObj* pUnoCtrl = dynamic_cast<SdrUnoObj*>( pObject );
+ if (pUnoCtrl && SdrInventor::FmForm == pUnoCtrl->GetObjInventor())
+ {
+ const uno::Reference<awt::XControlModel>& xControlModel = pUnoCtrl->GetUnoControlModel();
+ OSL_ENSURE( xControlModel.is(), "uno control without model" );
+ if ( xControlModel.is() )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY );
+ uno::Reference< beans::XPropertySetInfo > xInfo = xPropSet->getPropertySetInfo();
+
+ OUString sPropButtonType( "ButtonType" );
+ if(xInfo->hasPropertyByName( sPropButtonType ))
+ {
+ uno::Any aAny = xPropSet->getPropertyValue( sPropButtonType );
+ form::FormButtonType eTmp;
+ if ( (aAny >>= eTmp) && eTmp == form::FormButtonType_URL )
+ bRet = true;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+rtl::Reference<ScSelectionTransferObj> ScSelectionTransferObj::CreateFromView( ScTabView* pView )
+{
+ rtl::Reference<ScSelectionTransferObj> pRet;
+
+ try
+ {
+ if ( pView )
+ {
+ ScSelectionTransferMode eMode = SC_SELTRANS_INVALID;
+
+ SdrView* pSdrView = pView->GetScDrawView();
+ if ( pSdrView )
+ {
+ // handle selection on drawing layer
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+ if ( nMarkCount )
+ {
+ if ( nMarkCount == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
+
+ if ( nSdrObjKind == SdrObjKind::Graphic )
+ {
+ if ( static_cast<SdrGrafObj*>(pObj)->GetGraphic().GetType() == GraphicType::Bitmap )
+ eMode = SC_SELTRANS_DRAW_BITMAP;
+ else
+ eMode = SC_SELTRANS_DRAW_GRAPHIC;
+ }
+ else if ( nSdrObjKind == SdrObjKind::OLE2 )
+ eMode = SC_SELTRANS_DRAW_OLE;
+ else if ( lcl_IsURLButton( pObj ) )
+ eMode = SC_SELTRANS_DRAW_BOOKMARK;
+ }
+
+ if ( eMode == SC_SELTRANS_INVALID )
+ eMode = SC_SELTRANS_DRAW_OTHER; // something selected but no special selection
+ }
+ }
+ if ( eMode == SC_SELTRANS_INVALID ) // no drawing object selected
+ {
+ ScViewData& rViewData = pView->GetViewData();
+ const ScMarkData& rMark = rViewData.GetMarkData();
+ // allow MultiMarked because GetSimpleArea may be able to merge into a simple range
+ // (GetSimpleArea modifies a local copy of MarkData)
+ // Also allow simple filtered area.
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ {
+ ScRange aRange;
+ ScMarkType eMarkType = rViewData.GetSimpleArea( aRange );
+ if (eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED)
+ {
+ // only for "real" selection, cursor alone isn't used
+ if ( aRange.aStart == aRange.aEnd )
+ eMode = SC_SELTRANS_CELL;
+ else
+ eMode = SC_SELTRANS_CELLS;
+ }
+ }
+ }
+
+ if ( eMode != SC_SELTRANS_INVALID )
+ pRet = new ScSelectionTransferObj( pView, eMode );
+ }
+ }
+ catch (...)
+ {
+ }
+
+ return pRet;
+}
+
+ScSelectionTransferObj::ScSelectionTransferObj( ScTabView* pSource, ScSelectionTransferMode eNewMode ) :
+ pView( pSource ),
+ eMode( eNewMode )
+{
+ //! store range for StillValid
+}
+
+ScSelectionTransferObj::~ScSelectionTransferObj()
+{
+ ScModule* pScMod = SC_MOD();
+ if (pScMod && pScMod->GetSelectionTransfer() == this)
+ {
+ // this is reached when the object wasn't really copied to the selection
+ // (CopyToSelection has no effect under Windows)
+
+ ForgetView();
+ pScMod->SetSelectionTransfer( nullptr );
+ }
+
+ OSL_ENSURE( !pView, "ScSelectionTransferObj dtor: ForgetView not called" );
+}
+
+void ScSelectionTransferObj::ForgetView()
+{
+ pView = nullptr;
+ eMode = SC_SELTRANS_INVALID;
+
+ mxCellData.clear();
+ mxDrawData.clear();
+}
+
+void ScSelectionTransferObj::AddSupportedFormats()
+{
+ // AddSupportedFormats must work without actually creating the
+ // "real" transfer object
+
+ switch (eMode)
+ {
+ case SC_SELTRANS_CELL:
+ case SC_SELTRANS_CELLS:
+ // same formats as in ScTransferObj::AddSupportedFormats
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ AddFormat( SotClipboardFormatId::HTML );
+ AddFormat( SotClipboardFormatId::SYLK );
+ AddFormat( SotClipboardFormatId::LINK );
+ AddFormat( SotClipboardFormatId::DIF );
+ AddFormat( SotClipboardFormatId::STRING );
+ AddFormat( SotClipboardFormatId::STRING_TSVC );
+ AddFormat( SotClipboardFormatId::RTF );
+ AddFormat( SotClipboardFormatId::RICHTEXT );
+ if ( eMode == SC_SELTRANS_CELL )
+ {
+ AddFormat( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT );
+ }
+ break;
+
+ // different graphic formats as in ScDrawTransferObj::AddSupportedFormats:
+
+ case SC_SELTRANS_DRAW_BITMAP:
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::SVXB );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ break;
+
+ case SC_SELTRANS_DRAW_GRAPHIC:
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::SVXB );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ break;
+
+ case SC_SELTRANS_DRAW_BOOKMARK:
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::SOLK );
+ AddFormat( SotClipboardFormatId::STRING );
+ AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
+ AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
+ AddFormat( SotClipboardFormatId::DRAWING );
+ break;
+
+ case SC_SELTRANS_DRAW_OLE:
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ break;
+
+ case SC_SELTRANS_DRAW_OTHER:
+ // other drawing objects
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::DRAWING );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ break;
+
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+}
+
+void ScSelectionTransferObj::CreateCellData()
+{
+ OSL_ENSURE( !mxCellData.is(), "CreateCellData twice" );
+ if ( pView )
+ {
+ ScViewData& rViewData = pView->GetViewData();
+ ScMarkData aNewMark( rViewData.GetMarkData() ); // use local copy for MarkToSimple
+ aNewMark.MarkToSimple();
+
+ // similar to ScViewFunctionSet::BeginDrag
+ if ( aNewMark.IsMarked() && !aNewMark.IsMultiMarked() )
+ {
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+
+ const ScRange& aSelRange = aNewMark.GetMarkArea();
+ ScDocShellRef aDragShellRef;
+ if ( pDocSh->GetDocument().HasOLEObjectsInArea( aSelRange, &aNewMark ) )
+ {
+ aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately
+ aDragShellRef->DoInitNew();
+ }
+ ScDrawLayer::SetGlobalDrawPersist( aDragShellRef.get() );
+
+ ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
+ // bApi = sal_True -> no error messages
+ // #i18364# bStopEdit = sal_False -> don't end edit mode
+ // (this may be called from pasting into the edit line)
+ bool bCopied = rViewData.GetView()->CopyToClip( pClipDoc.get(), false, true, true, false );
+
+ ScDrawLayer::SetGlobalDrawPersist(nullptr);
+
+ if ( bCopied )
+ {
+ TransferableObjectDescriptor aObjDesc;
+ pDocSh->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScTransferObj ctor
+
+ rtl::Reference<ScTransferObj> pTransferObj = new ScTransferObj( std::move(pClipDoc), aObjDesc );
+
+ // SetDragHandlePos is not used - there is no mouse position
+ //? pTransferObj->SetVisibleTab( nTab );
+
+ SfxObjectShellRef aPersistRef( aDragShellRef.get() );
+ pTransferObj->SetDrawPersist( aPersistRef ); // keep persist for ole objects alive
+
+ pTransferObj->SetDragSource( pDocSh, aNewMark );
+
+ mxCellData = pTransferObj;
+ }
+ }
+ }
+ OSL_ENSURE( mxCellData.is(), "can't create CellData" );
+}
+
+void ScSelectionTransferObj::CreateDrawData()
+{
+ OSL_ENSURE( !mxDrawData.is(), "CreateDrawData twice" );
+ if ( pView )
+ {
+ // similar to ScDrawView::BeginDrag
+
+ ScDrawView* pDrawView = pView->GetScDrawView();
+ if ( pDrawView )
+ {
+ bool bAnyOle, bOneOle;
+ const SdrMarkList& rMarkList = pDrawView->GetMarkedObjectList();
+ ScDrawView::CheckOle( rMarkList, bAnyOle, bOneOle );
+
+ ScDocShellRef aDragShellRef;
+ if (bAnyOle)
+ {
+ aDragShellRef = new ScDocShell; // Without Ref the DocShell does not live
+ aDragShellRef->DoInitNew();
+ }
+
+ ScDrawLayer::SetGlobalDrawPersist( aDragShellRef.get() );
+ std::unique_ptr<SdrModel> pModel(pDrawView->CreateMarkedObjModel());
+ ScDrawLayer::SetGlobalDrawPersist(nullptr);
+
+ ScViewData& rViewData = pView->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+
+ TransferableObjectDescriptor aObjDesc;
+ pDocSh->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScDrawTransferObj ctor
+
+ rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pModel), pDocSh, aObjDesc );
+
+ SfxObjectShellRef aPersistRef( aDragShellRef.get() );
+ pTransferObj->SetDrawPersist( aPersistRef ); // keep persist for ole objects alive
+ pTransferObj->SetDragSource( pDrawView ); // copies selection
+
+ mxDrawData = pTransferObj;
+ }
+ }
+ OSL_ENSURE( mxDrawData.is(), "can't create DrawData" );
+}
+
+ScTransferObj* ScSelectionTransferObj::GetCellData()
+{
+ if ( !mxCellData.is() && ( eMode == SC_SELTRANS_CELL || eMode == SC_SELTRANS_CELLS ) )
+ CreateCellData();
+ return mxCellData.get();
+}
+
+ScDrawTransferObj* ScSelectionTransferObj::GetDrawData()
+{
+ if ( !mxDrawData.is() && ( eMode == SC_SELTRANS_DRAW_BITMAP || eMode == SC_SELTRANS_DRAW_GRAPHIC ||
+ eMode == SC_SELTRANS_DRAW_BOOKMARK || eMode == SC_SELTRANS_DRAW_OLE ||
+ eMode == SC_SELTRANS_DRAW_OTHER ) )
+ CreateDrawData();
+ return mxDrawData.get();
+}
+
+bool ScSelectionTransferObj::GetData(
+ const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc )
+{
+ bool bOK = false;
+
+ uno::Reference<datatransfer::XTransferable> xSource;
+ switch (eMode)
+ {
+ case SC_SELTRANS_CELL:
+ case SC_SELTRANS_CELLS:
+ xSource = GetCellData();
+ break;
+ case SC_SELTRANS_DRAW_BITMAP:
+ case SC_SELTRANS_DRAW_GRAPHIC:
+ case SC_SELTRANS_DRAW_BOOKMARK:
+ case SC_SELTRANS_DRAW_OLE:
+ case SC_SELTRANS_DRAW_OTHER:
+ xSource = GetDrawData();
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if ( xSource.is() )
+ {
+ TransferableDataHelper aHelper( xSource );
+ uno::Any aAny = aHelper.GetAny(rFlavor, rDestDoc);
+ bOK = SetAny( aAny );
+ }
+
+ return bOK;
+}
+
+void ScSelectionTransferObj::ObjectReleased()
+{
+ // called when another selection is set from outside
+
+ ForgetView();
+
+ ScModule* pScMod = SC_MOD();
+ if ( pScMod->GetSelectionTransfer() == this )
+ pScMod->SetSelectionTransfer( nullptr );
+
+ TransferableHelper::ObjectReleased();
+}
+
+sal_Bool SAL_CALL ScSelectionTransferObj::isComplex()
+{
+ switch (eMode)
+ {
+ case SC_SELTRANS_CELL:
+ case SC_SELTRANS_CELLS:
+ return false;
+ default:
+ return true;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/transobj.cxx b/sc/source/ui/app/transobj.cxx
new file mode 100644
index 000000000..d0be7e0ae
--- /dev/null
+++ b/sc/source/ui/app/transobj.cxx
@@ -0,0 +1,921 @@
+/* -*- 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/justifyitem.hxx>
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+
+#include <o3tl/unit_conversion.hxx>
+#include <osl/diagnose.h>
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/lok.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <sot/storage.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/jobset.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <sfx2/docfile.hxx>
+
+#include <transobj.hxx>
+#include <patattr.hxx>
+#include <cellvalue.hxx>
+#include <cellform.hxx>
+#include <document.hxx>
+#include <viewopti.hxx>
+#include <editutil.hxx>
+#include <impex.hxx>
+#include <formulacell.hxx>
+#include <printfun.hxx>
+#include <docfunc.hxx>
+#include <scmod.hxx>
+#include <dragdata.hxx>
+#include <sortparam.hxx>
+#include <tabvwsh.hxx>
+
+#include <editeng/paperinf.hxx>
+#include <editeng/sizeitem.hxx>
+#include <formula/errorcodes.hxx>
+#include <docsh.hxx>
+#include <markdata.hxx>
+#include <stlpool.hxx>
+#include <viewdata.hxx>
+#include <dociter.hxx>
+#include <cellsuno.hxx>
+#include <stringutil.hxx>
+#include <formulaiter.hxx>
+
+using namespace com::sun::star;
+
+constexpr sal_uInt32 SCTRANS_TYPE_IMPEX = 1;
+constexpr sal_uInt32 SCTRANS_TYPE_EDIT_RTF = 2;
+constexpr sal_uInt32 SCTRANS_TYPE_EDIT_BIN = 3;
+constexpr sal_uInt32 SCTRANS_TYPE_EMBOBJ = 4;
+constexpr sal_uInt32 SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT = 5;
+
+void ScTransferObj::GetAreaSize( const ScDocument& rDoc, SCTAB nTab1, SCTAB nTab2, SCROW& nRow, SCCOL& nCol )
+{
+ SCCOL nMaxCol = 0;
+ SCROW nMaxRow = 0;
+ for( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ )
+ {
+ SCCOL nLastCol = 0;
+ SCROW nLastRow = 0;
+ // GetPrintArea instead of GetCellArea - include drawing objects
+ if( rDoc.GetPrintArea( nTab, nLastCol, nLastRow ) )
+ {
+ if( nLastCol > nMaxCol )
+ nMaxCol = nLastCol;
+ if( nLastRow > nMaxRow )
+ nMaxRow = nLastRow;
+ }
+ }
+ nRow = nMaxRow;
+ nCol = nMaxCol;
+}
+
+void ScTransferObj::PaintToDev( OutputDevice* pDev, ScDocument& rDoc, double nPrintFactor,
+ const ScRange& rBlock )
+{
+ tools::Rectangle aBound( Point(), pDev->GetOutputSize() ); //! use size from clip area?
+
+ ScViewData aViewData(rDoc);
+
+ aViewData.SetTabNo( rBlock.aEnd.Tab() );
+ aViewData.SetScreen( rBlock.aStart.Col(), rBlock.aStart.Row(),
+ rBlock.aEnd.Col(), rBlock.aEnd.Row() );
+
+ ScPrintFunc::DrawToDev( rDoc, pDev, nPrintFactor, aBound, &aViewData, false/*bMetaFile*/ );
+}
+
+ScTransferObj::ScTransferObj( const std::shared_ptr<ScDocument>& pClipDoc, const TransferableObjectDescriptor& rDesc ) :
+ m_pDoc( pClipDoc ),
+ m_nNonFiltered(0),
+ m_aObjDesc( rDesc ),
+ m_nDragHandleX( 0 ),
+ m_nDragHandleY( 0 ),
+ m_nSourceCursorX( m_pDoc->MaxCol() + 1 ),
+ m_nSourceCursorY( m_pDoc->MaxRow() + 1 ),
+ m_nDragSourceFlags( ScDragSrc::Undefined ),
+ m_bDragWasInternal( false ),
+ m_bUsedForLink( false ),
+ m_bUseInApi( false )
+{
+ OSL_ENSURE(m_pDoc->IsClipboard(), "wrong document");
+
+ // get aBlock from clipboard doc
+
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ m_pDoc->GetClipStart( nCol1, nRow1 );
+ m_pDoc->GetClipArea( nCol2, nRow2, true ); // real source area - include filtered rows
+ nCol2 = sal::static_int_cast<SCCOL>( nCol2 + nCol1 );
+ nRow2 = sal::static_int_cast<SCROW>( nRow2 + nRow1 );
+
+ SCCOL nDummy;
+ m_pDoc->GetClipArea( nDummy, m_nNonFiltered, false );
+ m_bHasFiltered = (m_nNonFiltered < (nRow2 - nRow1));
+ ++m_nNonFiltered; // to get count instead of diff
+
+ SCTAB nTab1=0;
+ SCTAB nTab2=0;
+ bool bFirst = true;
+ for (SCTAB i=0; i< m_pDoc->GetTableCount(); i++)
+ if (m_pDoc->HasTable(i))
+ {
+ if (bFirst)
+ nTab1 = i;
+ nTab2 = i;
+ bFirst = false;
+ }
+ OSL_ENSURE(!bFirst, "no sheet selected");
+
+ // only limit to used cells if whole sheet was marked
+ // (so empty cell areas can be copied)
+ if ( nCol2>=m_pDoc->MaxCol() && nRow2>=m_pDoc->MaxRow() )
+ {
+ SCROW nMaxRow;
+ SCCOL nMaxCol;
+ GetAreaSize( *m_pDoc, nTab1, nTab2, nMaxRow, nMaxCol );
+ if( nMaxRow < nRow2 )
+ nRow2 = nMaxRow;
+ if( nMaxCol < nCol2 )
+ nCol2 = nMaxCol;
+ }
+
+ m_aBlock = ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ m_nVisibleTab = nTab1; // valid table as default
+
+ tools::Rectangle aMMRect = m_pDoc->GetMMRect( nCol1,nRow1, nCol2,nRow2, nTab1 );
+ m_aObjDesc.maSize = aMMRect.GetSize();
+ PrepareOLE( m_aObjDesc );
+}
+
+ScTransferObj::~ScTransferObj()
+{
+ SolarMutexGuard aSolarGuard;
+
+ bool bIsDisposing = comphelper::LibreOfficeKit::isActive() && !ScTabViewShell::GetActiveViewShell();
+ ScModule* pScMod = SC_MOD();
+ if (pScMod && !bIsDisposing && pScMod->GetDragData().pCellTransfer == this)
+ {
+ OSL_FAIL("ScTransferObj wasn't released");
+ pScMod->ResetDragObject();
+ }
+
+ m_pDoc.reset(); // ScTransferObj is owner of clipboard document
+
+ m_aDocShellRef.clear(); // before releasing the mutex
+
+ m_aDrawPersistRef.clear(); // after the model
+
+}
+
+ScTransferObj* ScTransferObj::GetOwnClipboard(const uno::Reference<datatransfer::XTransferable2>& xTransferable)
+{
+ return comphelper::getFromUnoTunnel<ScTransferObj>(xTransferable);
+}
+
+void ScTransferObj::AddSupportedFormats()
+{
+ // same formats as in ScSelectionTransferObj::AddSupportedFormats
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+
+ // ScImportExport formats
+ AddFormat( SotClipboardFormatId::HTML );
+ AddFormat( SotClipboardFormatId::SYLK );
+ AddFormat( SotClipboardFormatId::LINK );
+ AddFormat( SotClipboardFormatId::DIF );
+ AddFormat( SotClipboardFormatId::STRING );
+ AddFormat( SotClipboardFormatId::STRING_TSVC );
+
+ AddFormat( SotClipboardFormatId::RTF );
+ AddFormat( SotClipboardFormatId::RICHTEXT );
+ if ( m_aBlock.aStart == m_aBlock.aEnd )
+ {
+ AddFormat( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT );
+ }
+}
+
+static ScRange lcl_reduceBlock(const ScDocument& rDoc, ScRange aReducedBlock, bool bIncludeVisual = false)
+{
+ if ((aReducedBlock.aEnd.Col() == rDoc.MaxCol() || aReducedBlock.aEnd.Row() == rDoc.MaxRow()) &&
+ aReducedBlock.aStart.Tab() == aReducedBlock.aEnd.Tab())
+ {
+ // Shrink the block here so we don't waste time creating huge
+ // output when whole columns or rows are selected.
+
+ SCCOL nPrintAreaEndCol = 0;
+ SCROW nPrintAreaEndRow = 0;
+ if (bIncludeVisual)
+ rDoc.GetPrintArea( aReducedBlock.aStart.Tab(), nPrintAreaEndCol, nPrintAreaEndRow, true );
+
+ // Shrink the area to allow pasting to external applications.
+ // Shrink to real data area for HTML, RTF and RICHTEXT, but include
+ // all objects and top-left area for BITMAP and PNG.
+ SCCOL nStartCol = aReducedBlock.aStart.Col();
+ SCROW nStartRow = aReducedBlock.aStart.Row();
+ SCCOL nEndCol = aReducedBlock.aEnd.Col();
+ SCROW nEndRow = aReducedBlock.aEnd.Row();
+
+ if (bIncludeVisual)
+ {
+ ScDataAreaExtras aDataAreaExtras;
+ aDataAreaExtras.mbCellNotes = true;
+ aDataAreaExtras.mbCellDrawObjects = true;
+ bool bShrunk = false;
+ rDoc.ShrinkToUsedDataArea( bShrunk, aReducedBlock.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow,
+ false, true /*bStickyTopRow*/, true /*bStickyLeftCol*/, &aDataAreaExtras);
+ aDataAreaExtras.GetOverallRange( nStartCol, nStartRow, nEndCol, nEndRow, ScDataAreaExtras::Clip::None);
+ }
+ else
+ {
+ bool bShrunk = false;
+ rDoc.ShrinkToUsedDataArea( bShrunk, aReducedBlock.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow,
+ false, false /*bStickyTopRow*/, false /*bStickyLeftCol*/);
+ }
+
+ if ( nPrintAreaEndRow > nEndRow )
+ nEndRow = nPrintAreaEndRow;
+
+ if ( nPrintAreaEndCol > nEndCol )
+ nEndCol = nPrintAreaEndCol;
+
+ aReducedBlock = ScRange(nStartCol, nStartRow, aReducedBlock.aStart.Tab(), nEndCol, nEndRow, aReducedBlock.aEnd.Tab());
+ }
+ return aReducedBlock;
+}
+
+bool ScTransferObj::GetData( const datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+{
+ SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+ bool bOK = false;
+
+ if( HasFormat( nFormat ) )
+ {
+ ScRange aReducedBlock = m_aBlock;
+
+ bool bReduceBlockFormat =
+ nFormat == SotClipboardFormatId::HTML
+ || nFormat == SotClipboardFormatId::RTF
+ || nFormat == SotClipboardFormatId::RICHTEXT
+ || nFormat == SotClipboardFormatId::BITMAP
+ || nFormat == SotClipboardFormatId::PNG;
+
+ const bool bIncludeVisual = (nFormat == SotClipboardFormatId::BITMAP ||
+ nFormat == SotClipboardFormatId::PNG);
+
+ if (bReduceBlockFormat)
+ aReducedBlock = lcl_reduceBlock(*m_pDoc, m_aBlock, bIncludeVisual);
+
+ if ( nFormat == SotClipboardFormatId::LINKSRCDESCRIPTOR || nFormat == SotClipboardFormatId::OBJECTDESCRIPTOR )
+ {
+ bOK = SetTransferableObjectDescriptor( m_aObjDesc );
+ }
+ else if ( ( nFormat == SotClipboardFormatId::RTF || nFormat == SotClipboardFormatId::RICHTEXT ||
+ nFormat == SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT ) && m_aBlock.aStart == m_aBlock.aEnd )
+ {
+ // RTF from a single cell is handled by EditEngine
+
+ SCCOL nCol = m_aBlock.aStart.Col();
+ SCROW nRow = m_aBlock.aStart.Row();
+ SCTAB nTab = m_aBlock.aStart.Tab();
+ ScAddress aPos(nCol, nRow, nTab);
+
+ const ScPatternAttr* pPattern = m_pDoc->GetPattern( nCol, nRow, nTab );
+ ScTabEditEngine aEngine( *pPattern, m_pDoc->GetEditPool(), m_pDoc.get() );
+ ScRefCellValue aCell(*m_pDoc, aPos);
+ if (aCell.meType == CELLTYPE_EDIT)
+ {
+ const EditTextObject* pObj = aCell.mpEditText;
+ aEngine.SetTextCurrentDefaults(*pObj);
+ }
+ else
+ {
+ SvNumberFormatter* pFormatter = m_pDoc->GetFormatTable();
+ sal_uInt32 nNumFmt = pPattern->GetNumberFormat(pFormatter);
+ const Color* pColor;
+ OUString aText = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, *m_pDoc);
+ if (!aText.isEmpty())
+ aEngine.SetTextCurrentDefaults(aText);
+ }
+
+ bOK = SetObject( &aEngine,
+ ((nFormat == SotClipboardFormatId::RTF) ? SCTRANS_TYPE_EDIT_RTF :
+ ((nFormat == SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT) ?
+ SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT : SCTRANS_TYPE_EDIT_BIN)),
+ rFlavor );
+ }
+ else if ( ScImportExport::IsFormatSupported( nFormat ) || nFormat == SotClipboardFormatId::RTF
+ || nFormat == SotClipboardFormatId::RICHTEXT )
+ {
+ // if this transfer object was used to create a DDE link, filtered rows
+ // have to be included for subsequent calls (to be consistent with link data)
+ if ( nFormat == SotClipboardFormatId::LINK )
+ m_bUsedForLink = true;
+
+ bool bIncludeFiltered = m_pDoc->IsCutMode() || m_bUsedForLink;
+
+ ScImportExport aObj( *m_pDoc, aReducedBlock );
+ // Plain text ("Unformatted text") may contain embedded tabs and
+ // line breaks but is not enclosed in quotes. Which makes it
+ // unsuitable for multiple cells, especially if one of them is
+ // multi-line, but otherwise is expected behavior for plain text.
+ // For multiple cells replace embedded line breaks (and tabs) with
+ // space character, otherwise pasting would yield odd results.
+ /* XXX: it's debatable whether this is actually expected, but
+ * there's no way to satisfy all possible requirements when
+ * copy/pasting unformatted text. */
+ const bool bPlainMulti = (nFormat == SotClipboardFormatId::STRING &&
+ aReducedBlock.aStart != aReducedBlock.aEnd);
+ // Add quotes only for STRING_TSVC.
+ /* TODO: a possible future STRING_TSV should not contain embedded
+ * line breaks nor tab (separator) characters and not be quoted.
+ * A possible STRING_CSV should. */
+ ScExportTextOptions aTextOptions( ScExportTextOptions::None, 0,
+ (nFormat == SotClipboardFormatId::STRING_TSVC));
+ if ( bPlainMulti || m_bUsedForLink )
+ {
+ // For a DDE link or plain text multiple cells, convert line
+ // breaks and separators to space.
+ aTextOptions.meNewlineConversion = ScExportTextOptions::ToSpace;
+ aTextOptions.mcSeparatorConvertTo = ' ';
+ aTextOptions.mbAddQuotes = false;
+ }
+ aObj.SetExportTextOptions(aTextOptions);
+ aObj.SetFormulas( m_pDoc->GetViewOptions().GetOption( VOPT_FORMULAS ) );
+ aObj.SetIncludeFiltered( bIncludeFiltered );
+
+ // DataType depends on format type:
+
+ if ( rFlavor.DataType.equals( ::cppu::UnoType<OUString>::get() ) )
+ {
+ OUString aString;
+ if ( aObj.ExportString( aString, nFormat ) )
+ bOK = SetString( aString );
+ }
+ else if ( rFlavor.DataType.equals( cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ) )
+ {
+ // SetObject converts a stream into an Int8-Sequence
+ bOK = SetObject( &aObj, SCTRANS_TYPE_IMPEX, rFlavor );
+ }
+ else
+ {
+ OSL_FAIL("unknown DataType");
+ }
+ }
+ else if ( nFormat == SotClipboardFormatId::BITMAP || nFormat == SotClipboardFormatId::PNG )
+ {
+ tools::Rectangle aMMRect = m_pDoc->GetMMRect( aReducedBlock.aStart.Col(), aReducedBlock.aStart.Row(),
+ aReducedBlock.aEnd.Col(), aReducedBlock.aEnd.Row(),
+ aReducedBlock.aStart.Tab() );
+ ScopedVclPtrInstance< VirtualDevice > pVirtDev;
+ pVirtDev->SetOutputSizePixel(pVirtDev->LogicToPixel(aMMRect.GetSize(), MapMode(MapUnit::Map100thMM)));
+
+ PaintToDev( pVirtDev, *m_pDoc, 1.0, aReducedBlock );
+
+ pVirtDev->SetMapMode( MapMode( MapUnit::MapPixel ) );
+ BitmapEx aBmp = pVirtDev->GetBitmapEx( Point(), pVirtDev->GetOutputSize() );
+ bOK = SetBitmapEx( aBmp, rFlavor );
+ }
+ else if ( nFormat == SotClipboardFormatId::GDIMETAFILE )
+ {
+ // #i123405# Do not limit visual size calculation for metafile creation.
+ // It seems unlikely that removing the limitation causes problems since
+ // metafile creation means that no real pixel device in the needed size is
+ // created.
+ InitDocShell(false);
+
+ SfxObjectShell* pEmbObj = m_aDocShellRef.get();
+
+ // like SvEmbeddedTransfer::GetData:
+ GDIMetaFile aMtf;
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ MapMode aMapMode( pEmbObj->GetMapUnit() );
+ tools::Rectangle aVisArea( pEmbObj->GetVisArea( ASPECT_CONTENT ) );
+
+ pVDev->EnableOutput( false );
+ pVDev->SetMapMode( aMapMode );
+ aMtf.SetPrefSize( aVisArea.GetSize() );
+ aMtf.SetPrefMapMode( aMapMode );
+ aMtf.Record( pVDev );
+
+ pEmbObj->DoDraw( pVDev, Point(), aVisArea.GetSize(), JobSetup() );
+
+ aMtf.Stop();
+ aMtf.WindStart();
+
+ bOK = SetGDIMetaFile( aMtf );
+ }
+ else if ( nFormat == SotClipboardFormatId::EMBED_SOURCE )
+ {
+ //TODO/LATER: differentiate between formats?!
+ // #i123405# Do limit visual size calculation to PageSize
+ InitDocShell(true); // set aDocShellRef
+
+ SfxObjectShell* pEmbObj = m_aDocShellRef.get();
+ bOK = SetObject( pEmbObj, SCTRANS_TYPE_EMBOBJ, rFlavor );
+ }
+ }
+ return bOK;
+}
+
+bool ScTransferObj::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId,
+ const datatransfer::DataFlavor& rFlavor )
+{
+ // called from SetObject, put data into stream
+
+ bool bRet = false;
+ switch (nUserObjectId)
+ {
+ case SCTRANS_TYPE_IMPEX:
+ {
+ ScImportExport* pImpEx = static_cast<ScImportExport*>(pUserObject);
+
+ SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+ // mba: no BaseURL for data exchange
+ if ( pImpEx->ExportStream( *rxOStm, OUString(), nFormat ) )
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+ break;
+
+ case SCTRANS_TYPE_EDIT_RTF:
+ case SCTRANS_TYPE_EDIT_BIN:
+ {
+ ScTabEditEngine* pEngine = static_cast<ScTabEditEngine*>(pUserObject);
+ if ( nUserObjectId == SCTRANS_TYPE_EDIT_RTF )
+ {
+ pEngine->Write( *rxOStm, EETextFormat::Rtf );
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+ else
+ {
+ // can't use Write for EditEngine format because that would
+ // write old format without support for unicode characters.
+ // Get the data from the EditEngine's transferable instead.
+
+ sal_Int32 nParCnt = pEngine->GetParagraphCount();
+ if ( nParCnt == 0 )
+ nParCnt = 1;
+ ESelection aSel( 0, 0, nParCnt-1, pEngine->GetTextLen(nParCnt-1) );
+
+ uno::Reference<datatransfer::XTransferable> xEditTrans = pEngine->CreateTransferable( aSel );
+ TransferableDataHelper aEditHelper( xEditTrans );
+
+ bRet = aEditHelper.GetSotStorageStream( rFlavor, rxOStm );
+ }
+ }
+ break;
+
+ case SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT:
+ {
+ ScTabEditEngine* pEngine = static_cast<ScTabEditEngine*>(pUserObject);
+ pEngine->Write(*rxOStm, EETextFormat::Xml);
+ bRet = (rxOStm->GetError() == ERRCODE_NONE);
+ }
+ break;
+
+ case SCTRANS_TYPE_EMBOBJ:
+ {
+ // TODO/MBA: testing
+ SfxObjectShell* pEmbObj = static_cast<SfxObjectShell*>(pUserObject);
+ ::utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ uno::Reference< embed::XStorage > xWorkStore =
+ ::comphelper::OStorageHelper::GetStorageFromURL( aTempFile.GetURL(), embed::ElementModes::READWRITE );
+
+ // write document storage
+ pEmbObj->SetupStorage( xWorkStore, SOFFICE_FILEFORMAT_CURRENT, false );
+
+ // mba: no relative URLs for clipboard!
+ SfxMedium aMedium( xWorkStore, OUString() );
+ pEmbObj->DoSaveObjectAs( aMedium, false );
+ pEmbObj->DoSaveCompleted();
+
+ uno::Reference< embed::XTransactedObject > xTransact( xWorkStore, uno::UNO_QUERY );
+ if ( xTransact.is() )
+ xTransact->commit();
+
+ std::unique_ptr<SvStream> pSrcStm = ::utl::UcbStreamHelper::CreateStream( aTempFile.GetURL(), StreamMode::READ );
+ if( pSrcStm )
+ {
+ rxOStm->SetBufferSize( 0xff00 );
+ rxOStm->WriteStream( *pSrcStm );
+ pSrcStm.reset();
+ }
+
+ bRet = true;
+
+ xWorkStore->dispose();
+ xWorkStore.clear();
+ }
+ break;
+
+ default:
+ OSL_FAIL("unknown object id");
+ }
+ return bRet;
+}
+
+sal_Bool SAL_CALL ScTransferObj::isComplex()
+{
+ ScRange aReduced = lcl_reduceBlock(*m_pDoc, m_aBlock);
+ size_t nCells = (aReduced.aEnd.Col() - aReduced.aStart.Col() + 1) *
+ (aReduced.aEnd.Row() - aReduced.aStart.Row() + 1) *
+ (aReduced.aEnd.Tab() - aReduced.aStart.Tab() + 1);
+ return nCells > 1000;
+}
+
+void ScTransferObj::DragFinished( sal_Int8 nDropAction )
+{
+ if ( nDropAction == DND_ACTION_MOVE && !m_bDragWasInternal && !(m_nDragSourceFlags & ScDragSrc::Navigator) )
+ {
+ // move: delete source data
+ ScDocShell* pSourceSh = GetSourceDocShell();
+ if (pSourceSh)
+ {
+ ScMarkData aMarkData = GetSourceMarkData();
+ // external drag&drop doesn't copy objects, so they also aren't deleted:
+ // bApi=TRUE, don't show error messages from drag&drop
+ pSourceSh->GetDocFunc().DeleteContents( aMarkData, InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS, true, true );
+ }
+ }
+
+ ScModule* pScMod = SC_MOD();
+ if ( pScMod->GetDragData().pCellTransfer == this )
+ pScMod->ResetDragObject();
+
+ m_xDragSourceRanges = nullptr; // don't keep source after dropping
+
+ TransferDataContainer::DragFinished( nDropAction );
+}
+
+void ScTransferObj::SetDragHandlePos( SCCOL nX, SCROW nY )
+{
+ m_nDragHandleX = nX;
+ m_nDragHandleY = nY;
+}
+
+void ScTransferObj::SetSourceCursorPos( SCCOL nX, SCROW nY )
+{
+ m_nSourceCursorX = nX;
+ m_nSourceCursorY = nY;
+}
+
+bool ScTransferObj::WasSourceCursorInSelection() const
+{
+ return
+ m_nSourceCursorX >= m_aBlock.aStart.Col() && m_nSourceCursorX <= m_aBlock.aEnd.Col() &&
+ m_nSourceCursorY >= m_aBlock.aStart.Row() && m_nSourceCursorY <= m_aBlock.aEnd.Row();
+}
+
+void ScTransferObj::SetVisibleTab( SCTAB nNew )
+{
+ m_nVisibleTab = nNew;
+}
+
+void ScTransferObj::SetDrawPersist( const SfxObjectShellRef& rRef )
+{
+ m_aDrawPersistRef = rRef;
+}
+
+void ScTransferObj::SetDragSource( ScDocShell* pSourceShell, const ScMarkData& rMark )
+{
+ ScRangeList aRanges;
+ rMark.FillRangeListWithMarks( &aRanges, false );
+ m_xDragSourceRanges = new ScCellRangesObj( pSourceShell, aRanges );
+}
+
+void ScTransferObj::SetDragSourceFlags(ScDragSrc nFlags)
+{
+ m_nDragSourceFlags = nFlags;
+}
+
+void ScTransferObj::SetDragWasInternal()
+{
+ m_bDragWasInternal = true;
+}
+
+void ScTransferObj::SetUseInApi( bool bSet )
+{
+ m_bUseInApi = bSet;
+}
+
+ScDocument* ScTransferObj::GetSourceDocument()
+{
+ ScDocShell* pSourceDocSh = GetSourceDocShell();
+ if (pSourceDocSh)
+ return &pSourceDocSh->GetDocument();
+ return nullptr;
+}
+
+ScDocShell* ScTransferObj::GetSourceDocShell()
+{
+ ScCellRangesBase* pRangesObj = comphelper::getFromUnoTunnel<ScCellRangesBase>( m_xDragSourceRanges );
+ if (pRangesObj)
+ return pRangesObj->GetDocShell();
+
+ return nullptr; // none set
+}
+
+ScMarkData ScTransferObj::GetSourceMarkData() const
+{
+ ScMarkData aMarkData(m_pDoc->GetSheetLimits());
+ ScCellRangesBase* pRangesObj = comphelper::getFromUnoTunnel<ScCellRangesBase>( m_xDragSourceRanges );
+ if (pRangesObj)
+ {
+ const ScRangeList& rRanges = pRangesObj->GetRangeList();
+ aMarkData.MarkFromRangeList( rRanges, false );
+ }
+ return aMarkData;
+}
+
+// initialize aDocShellRef with a live document from the ClipDoc
+
+// #i123405# added parameter to allow size calculation without limitation
+// to PageSize, e.g. used for Metafile creation for clipboard.
+
+void ScTransferObj::InitDocShell(bool bLimitToPageSize)
+{
+ if ( m_aDocShellRef.is() )
+ return;
+
+ ScDocShell* pDocSh = new ScDocShell;
+ m_aDocShellRef = pDocSh; // ref must be there before InitNew
+
+ pDocSh->DoInitNew();
+
+ ScDocument& rDestDoc = pDocSh->GetDocument();
+ ScMarkData aDestMark(rDestDoc.GetSheetLimits());
+ aDestMark.SelectTable( 0, true );
+
+ rDestDoc.SetDocOptions( m_pDoc->GetDocOptions() ); // #i42666#
+
+ OUString aTabName;
+ m_pDoc->GetName( m_aBlock.aStart.Tab(), aTabName );
+ rDestDoc.RenameTab( 0, aTabName );
+
+ rDestDoc.CopyStdStylesFrom(*m_pDoc);
+
+ SCCOL nStartX = m_aBlock.aStart.Col();
+ SCROW nStartY = m_aBlock.aStart.Row();
+ SCCOL nEndX = m_aBlock.aEnd.Col();
+ SCROW nEndY = m_aBlock.aEnd.Row();
+
+ // widths / heights
+ // (must be copied before CopyFromClip, for drawing objects)
+
+ SCCOL nCol;
+ SCTAB nSrcTab = m_aBlock.aStart.Tab();
+ rDestDoc.SetLayoutRTL(0, m_pDoc->IsLayoutRTL(nSrcTab));
+ for (nCol=nStartX; nCol<=nEndX; nCol++)
+ if ( m_pDoc->ColHidden(nCol, nSrcTab) )
+ rDestDoc.ShowCol( nCol, 0, false );
+ else
+ rDestDoc.SetColWidth( nCol, 0, m_pDoc->GetColWidth( nCol, nSrcTab ) );
+
+ if (nStartY > 0)
+ {
+ // Set manual height for all previous rows so we can ensure
+ // that visible area will not change due to autoheight
+ rDestDoc.SetManualHeight(0, nStartY - 1, 0, true);
+ }
+ for (SCROW nRow = nStartY; nRow <= nEndY; ++nRow)
+ {
+ if ( m_pDoc->RowHidden(nRow, nSrcTab) )
+ rDestDoc.ShowRow( nRow, 0, false );
+ else
+ {
+ rDestDoc.SetRowHeight( nRow, 0, m_pDoc->GetOriginalHeight( nRow, nSrcTab ) );
+
+ // if height was set manually, that flag has to be copied, too
+ bool bManual = m_pDoc->IsManualRowHeight(nRow, nSrcTab);
+ rDestDoc.SetManualHeight(nRow, nRow, 0, bManual);
+ }
+ }
+
+ if (m_pDoc->GetDrawLayer() || m_pDoc->HasNotes())
+ pDocSh->MakeDrawLayer();
+
+ // cell range is copied to the original position, but on the first sheet
+ // -> bCutMode must be set
+ // pDoc is always a Clipboard-document
+
+ ScRange aDestRange( nStartX,nStartY,0, nEndX,nEndY,0 );
+ bool bWasCut = m_pDoc->IsCutMode();
+ if (!bWasCut)
+ m_pDoc->SetClipArea( aDestRange, true ); // Cut
+ rDestDoc.CopyFromClip( aDestRange, aDestMark, InsertDeleteFlags::ALL, nullptr, m_pDoc.get(), false );
+ m_pDoc->SetClipArea( aDestRange, bWasCut );
+
+ StripRefs(*m_pDoc, nStartX,nStartY, nEndX,nEndY, rDestDoc);
+
+ ScRange aMergeRange = aDestRange;
+ rDestDoc.ExtendMerge( aMergeRange, true );
+
+ m_pDoc->CopyDdeLinks( rDestDoc ); // copy values of DDE Links
+
+ // page format (grid etc) and page size (maximum size for ole object)
+
+ Size aPaperSize = SvxPaperInfo::GetPaperSize( PAPER_A4 ); // Twips
+ ScStyleSheetPool* pStylePool = m_pDoc->GetStyleSheetPool();
+ OUString aStyleName = m_pDoc->GetPageStyle( m_aBlock.aStart.Tab() );
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName, SfxStyleFamily::Page );
+ if (pStyleSheet)
+ {
+ const SfxItemSet& rSourceSet = pStyleSheet->GetItemSet();
+ aPaperSize = rSourceSet.Get(ATTR_PAGE_SIZE).GetSize();
+
+ // CopyStyleFrom copies SetItems with correct pool
+ ScStyleSheetPool* pDestPool = rDestDoc.GetStyleSheetPool();
+ pDestPool->CopyStyleFrom( pStylePool, aStyleName, SfxStyleFamily::Page );
+ }
+
+ ScViewData aViewData( *pDocSh, nullptr );
+ aViewData.SetScreen( nStartX,nStartY, nEndX,nEndY );
+ aViewData.SetCurX( nStartX );
+ aViewData.SetCurY( nStartY );
+
+ rDestDoc.SetViewOptions( m_pDoc->GetViewOptions() );
+
+ // Size
+ //! get while copying sizes
+
+ tools::Long nPosX = 0;
+ tools::Long nPosY = 0;
+
+ for (nCol=0; nCol<nStartX; nCol++)
+ nPosX += rDestDoc.GetColWidth( nCol, 0 );
+ nPosY += rDestDoc.GetRowHeight( 0, nStartY-1, 0 );
+ nPosX = o3tl::convert(nPosX, o3tl::Length::twip, o3tl::Length::mm100);
+ nPosY = o3tl::convert(nPosY, o3tl::Length::twip, o3tl::Length::mm100);
+
+ aPaperSize.setWidth( aPaperSize.Width() * 2 ); // limit OLE object to double of page size
+ aPaperSize.setHeight( aPaperSize.Height() * 2 );
+
+ tools::Long nSizeX = 0;
+ tools::Long nSizeY = 0;
+ for (nCol=nStartX; nCol<=nEndX; nCol++)
+ {
+ tools::Long nAdd = rDestDoc.GetColWidth( nCol, 0 );
+ if ( bLimitToPageSize && nSizeX+nAdd > aPaperSize.Width() && nSizeX ) // above limit?
+ break;
+ nSizeX += nAdd;
+ }
+ for (SCROW nRow=nStartY; nRow<=nEndY; nRow++)
+ {
+ tools::Long nAdd = rDestDoc.GetRowHeight( nRow, 0 );
+ if ( bLimitToPageSize && nSizeY+nAdd > aPaperSize.Height() && nSizeY ) // above limit?
+ break;
+ nSizeY += nAdd;
+ }
+ nSizeX = o3tl::convert(nSizeX, o3tl::Length::twip, o3tl::Length::mm100);
+ nSizeY = o3tl::convert(nSizeY, o3tl::Length::twip, o3tl::Length::mm100);
+
+// pDocSh->SetVisAreaSize( Size(nSizeX,nSizeY) );
+
+ tools::Rectangle aNewArea( Point(nPosX,nPosY), Size(nSizeX,nSizeY) );
+ //TODO/LATER: why twice?!
+ //pDocSh->SvInPlaceObject::SetVisArea( aNewArea );
+ pDocSh->SetVisArea( aNewArea );
+
+ pDocSh->UpdateOle(aViewData, true);
+
+ //! SetDocumentModified?
+ if ( rDestDoc.IsChartListenerCollectionNeedsUpdate() )
+ rDestDoc.UpdateChartListenerCollection();
+}
+
+SfxObjectShell* ScTransferObj::SetDrawClipDoc( bool bAnyOle, const std::shared_ptr<ScDocument>& pDoc )
+{
+ // update ScGlobal::xDrawClipDocShellRef
+
+ ScGlobal::xDrawClipDocShellRef.clear();
+ if (bAnyOle)
+ {
+ ScGlobal::xDrawClipDocShellRef = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS, pDoc); // there must be a ref
+ ScGlobal::xDrawClipDocShellRef->DoInitNew();
+ }
+
+ return ScGlobal::xDrawClipDocShellRef.get();
+}
+
+void ScTransferObj::StripRefs( ScDocument& rDoc,
+ SCCOL nStartX, SCROW nStartY, SCCOL nEndX, SCROW nEndY,
+ ScDocument& rDestDoc )
+{
+ // In a clipboard doc the data don't have to be on the first sheet
+
+ SCTAB nSrcTab = 0;
+ while (nSrcTab < rDoc.GetTableCount() && !rDoc.HasTable(nSrcTab))
+ ++nSrcTab;
+ SCTAB nDestTab = 0;
+ while (nDestTab < rDestDoc.GetTableCount() && !rDestDoc.HasTable(nDestTab))
+ ++nDestTab;
+
+ if (!rDoc.HasTable(nSrcTab) || !rDestDoc.HasTable(nDestTab))
+ {
+ OSL_FAIL("Sheet not found in ScTransferObj::StripRefs");
+ return;
+ }
+
+ ScRange aRef;
+
+ ScCellIterator aIter( rDoc, ScRange(nStartX, nStartY, nSrcTab, nEndX, nEndY, nSrcTab) );
+ for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
+ {
+ if (aIter.getType() != CELLTYPE_FORMULA)
+ continue;
+
+ ScFormulaCell* pFCell = aIter.getFormulaCell();
+ bool bOut = false;
+ ScDetectiveRefIter aRefIter( rDoc, pFCell );
+ while ( !bOut && aRefIter.GetNextRef( aRef ) )
+ {
+ if ( aRef.aStart.Tab() != nSrcTab || aRef.aEnd.Tab() != nSrcTab ||
+ aRef.aStart.Col() < nStartX || aRef.aEnd.Col() > nEndX ||
+ aRef.aStart.Row() < nStartY || aRef.aEnd.Row() > nEndY )
+ bOut = true;
+ }
+ if (bOut)
+ {
+ SCCOL nCol = aIter.GetPos().Col();
+ SCROW nRow = aIter.GetPos().Row();
+
+ FormulaError nErrCode = pFCell->GetErrCode();
+ ScAddress aPos(nCol, nRow, nDestTab);
+ if (nErrCode != FormulaError::NONE)
+ {
+ if ( rDestDoc.GetAttr( nCol,nRow,nDestTab, ATTR_HOR_JUSTIFY)->GetValue() ==
+ SvxCellHorJustify::Standard )
+ rDestDoc.ApplyAttr( nCol,nRow,nDestTab,
+ SvxHorJustifyItem(SvxCellHorJustify::Right, ATTR_HOR_JUSTIFY) );
+
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDestDoc.SetString(aPos, ScGlobal::GetErrorString(nErrCode), &aParam);
+ }
+ else if (pFCell->IsValue())
+ {
+ rDestDoc.SetValue(aPos, pFCell->GetValue());
+ }
+ else
+ {
+ OUString aStr = pFCell->GetString().getString();
+ if ( pFCell->IsMultilineResult() )
+ {
+ ScFieldEditEngine& rEngine = rDestDoc.GetEditEngine();
+ rEngine.SetTextCurrentDefaults(aStr);
+ rDestDoc.SetEditText(ScAddress(nCol,nRow,nDestTab), rEngine.CreateTextObject());
+ }
+ else
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDestDoc.SetString(aPos, aStr, &aParam);
+ }
+ }
+ }
+ }
+}
+
+const css::uno::Sequence< sal_Int8 >& ScTransferObj::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theScTransferUnoTunnelId;
+ return theScTransferUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL ScTransferObj::getSomething( const css::uno::Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(
+ rId, this, comphelper::FallbackToGetSomethingOf<TransferDataContainer>{});
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/typemap.cxx b/sc/source/ui/app/typemap.cxx
new file mode 100644
index 000000000..ac98c6fc4
--- /dev/null
+++ b/sc/source/ui/app/typemap.cxx
@@ -0,0 +1,140 @@
+/* -*- 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 <mid.h>
+#include <editeng/memberids.h>
+#include <svx/unomid.hxx>
+
+#include <sfx2/msg.hxx>
+#include <svl/slstitm.hxx>
+#include <editeng/fontitem.hxx>
+#include <svx/hlnkitem.hxx>
+#include <svl/srchitem.hxx>
+#include <svx/postattr.hxx>
+#include <editeng/postitem.hxx>
+#include <sfx2/tplpitem.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/lineitem.hxx>
+#include <svl/ptitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <svx/algitem.hxx>
+#include <svx/clipfmtitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xtextit0.hxx>
+#include <svx/xftadit.hxx>
+#include <svx/xftdiit.hxx>
+#include <svx/xftstit.hxx>
+#include <svx/xftmrit.hxx>
+#include <svx/xftouit.hxx>
+#include <svx/xftshit.hxx>
+#include <svx/xftshcit.hxx>
+#include <svx/xftshxy.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/shaditem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/kernitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <svx/drawitem.hxx>
+#include <svl/ilstitem.hxx>
+#include <svl/globalnameitem.hxx>
+#include <svx/chrtitem.hxx>
+#include <svx/zoomslideritem.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlinjoit.hxx>
+#include <svx/galleryitem.hxx>
+#include <svx/sdooitm.hxx>
+#include <avmedia/mediaitem.hxx>
+#include <sfx2/frame.hxx>
+#include <attrib.hxx>
+#include <svx/sdprcitm.hxx>
+#include <svx/sdmetitm.hxx>
+
+#define avmedia_MediaItem ::avmedia::MediaItem
+
+#ifdef DISABLE_DYNLOADING
+/* Avoid clash with the ones from svx/source/form/typemap.cxx */
+#define aSfxBoolItem_Impl sc_source_ui_appl_typemap_aSfxBoolItem_Impl
+#define aSfxInt32Item_Impl sc_source_ui_appl_typemap_aSfxInt32Item_Impl
+#define aSfxStringItem_Impl sc_source_ui_appl_typemap_aSfxStringItem_Impl
+#define aSfxUInt16Item_Impl sc_source_ui_appl_typemap_aSfxUInt16Item_Impl
+#define aSfxUInt32Item_Impl sc_source_ui_appl_typemap_aSfxUInt32Item_Impl
+#define aSfxVoidItem_Impl sc_source_ui_appl_typemap_aSfxVoidItem_Impl
+#define aSvxCharReliefItem_Impl sc_source_ui_appl_typemap_aSvxCharReliefItem_Impl
+#define aSvxClipboardFormatItem_Impl sc_source_ui_appl_typemap_aSvxClipboardFormatItem_Impl
+#define aSvxColorItem_Impl sc_source_ui_appl_typemap_aSvxColorItem_Impl
+#define aSvxContourItem_Impl sc_source_ui_appl_typemap_aSvxContourItem_Impl
+#define aSvxCrossedOutItem_Impl sc_source_ui_appl_typemap_aSvxCrossedOutItem_Impl
+#define aSvxFontHeightItem_Impl sc_source_ui_appl_typemap_aSvxFontHeightItem_Impl
+#define aSvxFontItem_Impl sc_source_ui_appl_typemap_aSvxFontItem_Impl
+#define aSvxLanguageItem_Impl sc_source_ui_appl_typemap_aSvxLanguageItem_Impl
+#define aSvxPostureItem_Impl sc_source_ui_appl_typemap_aSvxPostureItem_Impl
+#define aSvxShadowedItem_Impl sc_source_ui_appl_typemap_aSvxShadowedItem_Impl
+#define aSvxUnderlineItem_Impl sc_source_ui_appl_typemap_aSvxUnderlineItem_Impl
+#define aSvxOverlineItem_Impl sc_source_ui_appl_typemap_aSvxOverlineItem_Impl
+#define aSvxWeightItem_Impl sc_source_ui_appl_typemap_aSvxWeightItem_Impl
+#endif
+
+#define SFX_TYPEMAP
+#include <scslots.hxx>
+
+#ifdef DISABLE_DYNLOADING
+#undef aSfxBoolItem_Impl
+#undef aSfxInt32Item_Impl
+#undef aSfxStringItem_Impl
+#undef aSfxUInt16Item_Impl
+#undef aSfxUInt32Item_Impl
+#undef aSfxVoidItem_Impl
+#undef aSvxCharReliefItem_Impl
+#undef aSvxClipboardFormatItem_Impl
+#undef aSvxColorItem_Impl
+#undef aSvxContourItem_Impl
+#undef aSvxCrossedOutItem_Impl
+#undef aSvxFontHeightItem_Impl
+#undef aSvxFontItem_Impl
+#undef aSvxLanguageItem_Impl
+#undef aSvxPostureItem_Impl
+#undef aSvxShadowedItem_Impl
+#undef aSvxTextLineItem_Impl
+#undef aSvxWeightItem_Impl
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/uiitems.cxx b/sc/source/ui/app/uiitems.cxx
new file mode 100644
index 000000000..91cb50b07
--- /dev/null
+++ b/sc/source/ui/app/uiitems.cxx
@@ -0,0 +1,438 @@
+/* -*- 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 <uiitems.hxx>
+
+#include <userlist.hxx>
+#include <dpsave.hxx>
+#include <queryparam.hxx>
+
+#include <osl/diagnose.h>
+#include <editeng/editobj.hxx>
+
+/**
+ * Status update for entry field
+ */
+ScInputStatusItem::ScInputStatusItem(
+ sal_uInt16 nWhichP, const ScAddress& rCurPos, const ScAddress& rStartPos,
+ const ScAddress& rEndPos, const OUString& rString, const EditTextObject* pData ) :
+ SfxPoolItem ( nWhichP ),
+ aCursorPos ( rCurPos ),
+ aStartPos ( rStartPos ),
+ aEndPos ( rEndPos ),
+ aString ( rString ),
+ pEditData ( pData ? pData->Clone() : nullptr ),
+ mpMisspellRanges(nullptr)
+{
+}
+
+ScInputStatusItem::ScInputStatusItem( const ScInputStatusItem& rItem ) :
+ SfxPoolItem ( rItem ),
+ aCursorPos ( rItem.aCursorPos ),
+ aStartPos ( rItem.aStartPos ),
+ aEndPos ( rItem.aEndPos ),
+ aString ( rItem.aString ),
+ pEditData ( rItem.pEditData ? rItem.pEditData->Clone() : nullptr ),
+ mpMisspellRanges(rItem.mpMisspellRanges)
+{
+}
+
+ScInputStatusItem::~ScInputStatusItem()
+{
+}
+
+bool ScInputStatusItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ return (aStartPos == static_cast<const ScInputStatusItem&>(rItem).aStartPos)
+ && (aEndPos == static_cast<const ScInputStatusItem&>(rItem).aEndPos)
+ && (aCursorPos == static_cast<const ScInputStatusItem&>(rItem).aCursorPos)
+ && (aString == static_cast<const ScInputStatusItem&>(rItem).aString);
+ //TODO: Compare Edit data!
+}
+
+ScInputStatusItem* ScInputStatusItem::Clone( SfxItemPool * ) const
+{
+ return new ScInputStatusItem( *this );
+}
+
+void ScInputStatusItem::SetMisspellRanges( const std::vector<editeng::MisspellRanges>* pRanges )
+{
+ mpMisspellRanges = pRanges;
+}
+
+// ScPaintHint was moved to hints.cxx
+
+/**
+ * Adapt Views when inserting/deleting a table
+ */
+ScTablesHint::ScTablesHint(sal_uInt16 nNewId, SCTAB nTable1, SCTAB nTable2) :
+ nId( nNewId ),
+ nTab1( nTable1 ),
+ nTab2( nTable2 )
+{
+}
+
+ScTablesHint::~ScTablesHint()
+{
+}
+
+ScIndexHint::ScIndexHint(SfxHintId nNewId, sal_uInt16 nIdx) :
+ SfxHint( nNewId ),
+ nIndex( nIdx )
+{
+}
+
+ScIndexHint::~ScIndexHint()
+{
+}
+
+/**
+ * Create new EditView for Cursorposition
+ */
+ScEditViewHint::ScEditViewHint( ScEditEngineDefaulter* pEngine, const ScAddress& rCurPos ) :
+ pEditEngine( pEngine ),
+ aCursorPos( rCurPos )
+{
+}
+
+ScEditViewHint::~ScEditViewHint()
+{
+}
+
+/**
+ * Data for the sorting dialog
+ */
+ScSortItem::ScSortItem( sal_uInt16 nWhichP,
+ ScViewData* ptrViewData,
+ const ScSortParam* pSortData ) :
+ SfxPoolItem ( nWhichP ),
+ pViewData ( ptrViewData )
+{
+ if ( pSortData ) theSortData = *pSortData;
+}
+
+ScSortItem::ScSortItem( sal_uInt16 nWhichP,
+ const ScSortParam* pSortData ) :
+ SfxPoolItem ( nWhichP ),
+ pViewData ( nullptr )
+{
+ if ( pSortData ) theSortData = *pSortData;
+}
+
+bool ScSortItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScSortItem& rOther = static_cast<const ScSortItem&>(rItem);
+
+ return ( (pViewData == rOther.pViewData)
+ && (theSortData == rOther.theSortData) );
+}
+
+ScSortItem* ScSortItem::Clone( SfxItemPool * ) const
+{
+ return new ScSortItem( *this );
+}
+
+bool ScSortItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /* nMemberUd */ ) const
+{
+ // Return empty value as there is no useful conversion
+ rVal = css::uno::Any();
+ return true;
+}
+
+/**
+ * Data for the Filter dialog
+ */
+ScQueryItem::ScQueryItem( sal_uInt16 nWhichP,
+ ScViewData* ptrViewData,
+ const ScQueryParam* pQueryData ) :
+ SfxPoolItem ( nWhichP ),
+ pViewData ( ptrViewData ),
+ bIsAdvanced ( false )
+{
+ if (pQueryData)
+ mpQueryData.reset(new ScQueryParam(*pQueryData));
+ else
+ mpQueryData.reset(new ScQueryParam);
+}
+
+ScQueryItem::ScQueryItem( sal_uInt16 nWhichP,
+ const ScQueryParam* pQueryData ) :
+ SfxPoolItem ( nWhichP ),
+ pViewData ( nullptr ),
+ bIsAdvanced ( false )
+{
+ if (pQueryData)
+ mpQueryData.reset(new ScQueryParam(*pQueryData));
+ else
+ mpQueryData.reset(new ScQueryParam);
+}
+
+ScQueryItem::ScQueryItem( const ScQueryItem& rItem ) :
+ SfxPoolItem ( rItem ),
+ mpQueryData(new ScQueryParam(*rItem.mpQueryData)),
+ pViewData ( rItem.pViewData ),
+ aAdvSource ( rItem.aAdvSource ),
+ bIsAdvanced ( rItem.bIsAdvanced )
+{
+}
+
+ScQueryItem::~ScQueryItem()
+{
+}
+
+void ScQueryItem::SetAdvancedQuerySource(const ScRange* pSource)
+{
+ if (pSource)
+ {
+ aAdvSource = *pSource;
+ bIsAdvanced = true;
+ }
+ else
+ bIsAdvanced = false;
+}
+
+const ScQueryParam& ScQueryItem::GetQueryData() const
+{
+ return *mpQueryData;
+}
+
+bool ScQueryItem::GetAdvancedQuerySource(ScRange& rSource) const
+{
+ rSource = aAdvSource;
+ return bIsAdvanced;
+}
+
+bool ScQueryItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScQueryItem& rQueryItem = static_cast<const ScQueryItem&>(rItem);
+
+ return ( (pViewData == rQueryItem.pViewData)
+ && (bIsAdvanced == rQueryItem.bIsAdvanced)
+ && (aAdvSource == rQueryItem.aAdvSource)
+ && (*mpQueryData == *rQueryItem.mpQueryData) );
+}
+
+ScQueryItem* ScQueryItem::Clone( SfxItemPool * ) const
+{
+ return new ScQueryItem( *this );
+}
+
+/**
+ * Data for the SubTotal dialog
+ */
+ScSubTotalItem::ScSubTotalItem( sal_uInt16 nWhichP,
+ ScViewData* ptrViewData,
+ const ScSubTotalParam* pSubTotalData ) :
+ SfxPoolItem ( nWhichP ),
+ pViewData ( ptrViewData )
+{
+ if ( pSubTotalData ) theSubTotalData = *pSubTotalData;
+}
+
+bool ScSubTotalItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScSubTotalItem& rSTItem = static_cast<const ScSubTotalItem&>(rItem);
+
+ return ( (pViewData == rSTItem.pViewData)
+ && (theSubTotalData == rSTItem.theSubTotalData) );
+}
+
+ScSubTotalItem* ScSubTotalItem::Clone( SfxItemPool * ) const
+{
+ return new ScSubTotalItem( *this );
+}
+
+bool ScSubTotalItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /* nMemberUd */ ) const
+{
+ // Return empty value as there is no useful conversion
+ rVal = css::uno::Any();
+ return true;
+}
+
+/**
+ * Transporter for the UserLIst dialog
+ */
+ScUserListItem::ScUserListItem( sal_uInt16 nWhichP )
+ : SfxPoolItem ( nWhichP )
+{
+}
+
+ScUserListItem::ScUserListItem( const ScUserListItem& rItem )
+ : SfxPoolItem ( rItem )
+{
+ if ( rItem.pUserList )
+ pUserList.reset( new ScUserList( *(rItem.pUserList) ) );
+}
+
+ScUserListItem::~ScUserListItem()
+{
+}
+
+bool ScUserListItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScUserListItem& r = static_cast<const ScUserListItem&>(rItem);
+ bool bEqual = false;
+
+ if ( !pUserList || !r.pUserList )
+ bEqual = ( !pUserList && !r.pUserList );
+ else
+ bEqual = ( *pUserList == *(r.pUserList) );
+
+ return bEqual;
+}
+
+ScUserListItem* ScUserListItem::Clone( SfxItemPool * ) const
+{
+ return new ScUserListItem( *this );
+}
+
+void ScUserListItem::SetUserList( const ScUserList& rUserList )
+{
+ pUserList.reset( new ScUserList( rUserList ) );
+}
+
+/**
+ * Data for the Consolidate dialog
+ */
+ScConsolidateItem::ScConsolidateItem(
+ sal_uInt16 nWhichP,
+ const ScConsolidateParam* pConsolidateData ) :
+ SfxPoolItem ( nWhichP )
+{
+ if ( pConsolidateData ) theConsData = *pConsolidateData;
+}
+
+bool ScConsolidateItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScConsolidateItem& rCItem = static_cast<const ScConsolidateItem&>(rItem);
+
+ return ( theConsData == rCItem.theConsData);
+}
+
+ScConsolidateItem* ScConsolidateItem::Clone( SfxItemPool * ) const
+{
+ return new ScConsolidateItem( *this );
+}
+
+/**
+ * Data for the Pivot dialog
+ */
+ScPivotItem::ScPivotItem( sal_uInt16 nWhichP, const ScDPSaveData* pData,
+ const ScRange* pRange, bool bNew ) :
+ SfxPoolItem ( nWhichP )
+{
+ // pSaveData must always exist
+ if ( pData )
+ pSaveData.reset( new ScDPSaveData(*pData) );
+ else
+ pSaveData.reset( new ScDPSaveData );
+ if ( pRange ) aDestRange = *pRange;
+ bNewSheet = bNew;
+}
+
+ScPivotItem::ScPivotItem( const ScPivotItem& rItem ) :
+ SfxPoolItem ( rItem ),
+ aDestRange ( rItem.aDestRange ),
+ bNewSheet ( rItem.bNewSheet )
+{
+ assert(rItem.pSaveData && "pSaveData");
+ pSaveData.reset( new ScDPSaveData(*rItem.pSaveData) );
+}
+
+ScPivotItem::~ScPivotItem()
+{
+}
+
+bool ScPivotItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScPivotItem& rPItem = static_cast<const ScPivotItem&>(rItem);
+ OSL_ENSURE( pSaveData && rPItem.pSaveData, "pSaveData" );
+ return ( *pSaveData == *rPItem.pSaveData &&
+ aDestRange == rPItem.aDestRange &&
+ bNewSheet == rPItem.bNewSheet );
+}
+
+ScPivotItem* ScPivotItem::Clone( SfxItemPool * ) const
+{
+ return new ScPivotItem( *this );
+}
+
+/**
+ * Data for the Solver dialog
+ */
+ScSolveItem::ScSolveItem( sal_uInt16 nWhichP,
+ const ScSolveParam* pSolveData )
+ : SfxPoolItem ( nWhichP )
+{
+ if ( pSolveData ) theSolveData = *pSolveData;
+}
+
+bool ScSolveItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScSolveItem& rPItem = static_cast<const ScSolveItem&>(rItem);
+
+ return ( theSolveData == rPItem.theSolveData );
+}
+
+ScSolveItem* ScSolveItem::Clone( SfxItemPool * ) const
+{
+ return new ScSolveItem( *this );
+}
+
+/**
+ * Data for the TabOp dialog
+ */
+ScTabOpItem::ScTabOpItem( sal_uInt16 nWhichP,
+ const ScTabOpParam* pTabOpData )
+ : SfxPoolItem ( nWhichP )
+{
+ if ( pTabOpData ) theTabOpData = *pTabOpData;
+}
+
+bool ScTabOpItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScTabOpItem& rPItem = static_cast<const ScTabOpItem&>(rItem);
+
+ return ( theTabOpData == rPItem.theTabOpData );
+}
+
+ScTabOpItem* ScTabOpItem::Clone( SfxItemPool * ) const
+{
+ return new ScTabOpItem( *this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */