/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column:100 -*- */
/*
* 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/util/URLTransformer.hpp>
#include <com/sun/star/util/XURLTransformer.hpp>
#include <com/sun/star/frame/XDispatchProvider.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/frame/XFrame.hpp>
#include <com/sun/star/frame/XController.hpp>
#include <com/sun/star/frame/XModel2.hpp>
#include <com/sun/star/script/BasicErrorException.hpp>
#include <com/sun/star/script/XDefaultProperty.hpp>
#include <com/sun/star/script/XInvocation.hpp>
#include <com/sun/star/script/Converter.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/lang/XUnoTunnel.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/theIntrospection.hpp>
#include <com/sun/star/util/MeasureUnit.hpp>
#include <com/sun/star/awt/XControl.hpp>
#include <com/sun/star/awt/XWindow.hpp>
#include <com/sun/star/awt/XDialog.hpp>
#include <com/sun/star/awt/XUnitConversion.hpp>
#include <com/sun/star/drawing/XShape.hpp>
#include <ooo/vba/XHelperInterface.hpp>
#include <comphelper/automationinvokedzone.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/sequence.hxx>
#include <comphelper/servicehelper.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/app.hxx>
#include <sfx2/sfxsids.hrc>
#include <svl/stritem.hxx>
#include <svl/eitem.hxx>
#include <svl/intitem.hxx>
#include <svl/itemset.hxx>
#include <sfx2/docfac.hxx>
#include <sfx2/viewfac.hxx>
#include <basic/sbstar.hxx>
#include <basic/basmgr.hxx>
#include <basic/sbxmeth.hxx>
#include <basic/sbmod.hxx>
#include <basic/sbuno.hxx>
#include <basic/sberrors.hxx>
#include <o3tl/unit_conversion.hxx>
#include <rtl/ustrbuf.hxx>
#include <sfx2/viewsh.hxx>
#include <sal/log.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <utility>
#include <vcl/svapp.hxx>
#include <vcl/window.hxx>
#include <vcl/syswin.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <tools/UnitConversion.hxx>
#include <vbahelper/vbahelper.hxx>
using namespace ::com::sun::star;
using namespace ::ooo::vba;
namespace ooo::vba
{
// helper method to determine if the view ( calc ) is in print-preview mode
static bool isInPrintPreview( SfxViewFrame* pView )
{
sal_uInt16 nViewNo = SID_VIEWSHELL1 - SID_VIEWSHELL0;
if ( pView->GetObjectShell()->GetFactory().GetViewFactoryCount() >
nViewNo && !pView->GetObjectShell()->IsInPlaceActive() )
{
SfxViewFactory &rViewFactory =
pView->GetObjectShell()->GetFactory().GetViewFactory(nViewNo);
if ( pView->GetCurViewId() == rViewFactory.GetOrdinal() )
return true;
}
return false;
}
uno::Reference< beans::XIntrospectionAccess >
getIntrospectionAccess( const uno::Any& aObject )
{
static uno::Reference< beans::XIntrospection > xIntrospection( beans::theIntrospection::get( comphelper::getProcessComponentContext() ) );
return xIntrospection->inspect( aObject );
}
uno::Reference< script::XTypeConverter > const &
getTypeConverter( const uno::Reference< uno::XComponentContext >& xContext )
{
static uno::Reference< script::XTypeConverter > xTypeConv( script::Converter::create(xContext) );
return xTypeConv;
}
const uno::Any&
aNULL()
{
static uno::Any aNULLL{ uno::Reference< uno::XInterface >() };
return aNULLL;
}
void dispatchExecute(SfxViewShell const * pViewShell, sal_uInt16 nSlot)
{
SfxViewFrame* pViewFrame = nullptr;
if ( pViewShell )
pViewFrame = &pViewShell->GetViewFrame();
if ( pViewFrame )
{
SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher();
if( pDispatcher )
{
pDispatcher->Execute( nSlot , SfxCallMode::SYNCHRON );
}
}
}
void
dispatchRequests (const uno::Reference< frame::XModel>& xModel, const OUString & aUrl, const uno::Sequence< beans::PropertyValue >& sProps )
{
util::URL url;
url.Complete = aUrl;
uno::Reference<frame::XController> xController = xModel->getCurrentController();
uno::Reference<frame::XFrame> xFrame = xController->getFrame();
uno::Reference<frame::XDispatchProvider> xDispatchProvider (xFrame,uno::UNO_QUERY_THROW);
try
{
const uno::Reference<uno::XComponentContext >& xContext(
comphelper::getProcessComponentContext() );
uno::Reference<util::XURLTransformer> xParser( util::URLTransformer::create(xContext) );
xParser->parseStrict (url);
}
catch (const uno::Exception&)
{
return;
}
uno::Reference<frame::XDispatch> xDispatcher = xDispatchProvider->queryDispatch(url,u""_ustr,0);
sal_Int32 nProps = sProps.getLength();
uno::Sequence<beans::PropertyValue> dispatchProps(nProps + 1);
if ( nProps )
{
std::copy(sProps.begin(), sProps.end(), dispatchProps.getArray());
}
if ( xDispatcher.is() )
{
xDispatcher->dispatch( url, dispatchProps );
}
}
void
dispatchRequests( const uno::Reference< frame::XModel>& xModel, const OUString& aUrl )
{
uno::Sequence<beans::PropertyValue> dispatchProps;
dispatchRequests( xModel, aUrl, dispatchProps );
}
uno::Reference< frame::XModel >
getCurrentDoc( const OUString& sKey )
{
uno::Reference< frame::XModel > xModel;
StarBASIC* pBasic = SfxApplication::GetBasic();
if (pBasic == nullptr)
{
SAL_INFO("vbahelper", "getModelFromBasic() StarBASIC* is NULL" );
return xModel;
}
SbxObject* basicChosen = pBasic;
SbxObject* pParent = pBasic->GetParent();
SbxObject* pParentParent = pParent ? pParent->GetParent() : nullptr;
if( pParentParent )
{
basicChosen = pParentParent;
}
else if( pParent )
{
basicChosen = pParent;
}
uno::Any aModel;
SbxVariable *pCompVar = basicChosen->Find( sKey, SbxClassType::Object );
if ( pCompVar )
{
aModel = sbxToUnoValue( pCompVar );
if ( !( aModel >>= xModel ) || !xModel.is() )
{
throw uno::RuntimeException(
u"Can't extract model from basic ( it's obviously not set yet therefore don't know the current document context)"_ustr );
}
SAL_INFO("vbahelper", "Have model points to url " << xModel->getURL());
}
else
{
SAL_INFO("vbahelper", "Failed to get " << sKey);
throw uno::RuntimeException( u"Can't determine the currently selected document"_ustr );
}
return xModel;
}
/// @throws uno::RuntimeException
static uno::Reference< frame::XModel >
getCurrentDocCtx( const OUString& ctxName, const uno::Reference< uno::XComponentContext >& xContext )
{
uno::Reference< frame::XModel > xModel;
// try fallback to calling doc
css::uno::Reference< css::container::XNameAccess > xNameAccess( xContext, css::uno::UNO_QUERY_THROW );
xModel.set( xNameAccess->getByName( ctxName ), uno::UNO_QUERY_THROW );
return xModel;
}
uno::Reference< frame::XModel >
getThisExcelDoc( const uno::Reference< uno::XComponentContext >& xContext )
{
return getCurrentDocCtx( u"ExcelDocumentContext"_ustr , xContext );
}
uno::Reference< frame::XModel >
getThisWordDoc( const uno::Reference< uno::XComponentContext >& xContext )
{
return getCurrentDocCtx( u"WordDocumentContext"_ustr , xContext );
}
uno::Reference< frame::XModel >
getCurrentExcelDoc( const uno::Reference< uno::XComponentContext >& xContext )
{
uno::Reference< frame::XModel > xModel;
try
{
xModel = getCurrentDoc( u"ThisExcelDoc"_ustr );
}
catch (const uno::Exception&)
{
try
{
xModel = getThisExcelDoc( xContext );
}
catch (const uno::Exception&)
{
}
}
return xModel;
}
uno::Reference< frame::XModel >
getCurrentWordDoc( const uno::Reference< uno::XComponentContext >& xContext )
{
uno::Reference< frame::XModel > xModel;
try
{
xModel = getCurrentDoc( u"ThisWordDoc"_ustr );
}
catch (const uno::Exception&)
{
try
{
xModel = getThisWordDoc( xContext );
}
catch (const uno::Exception&)
{
}
}
return xModel;
}
sal_Int32
OORGBToXLRGB( sal_Int32 nCol )
{
sal_Int32 nAutoBits = nCol;
nAutoBits &= 0xFF000000;
sal_Int32 nRed = nCol;
nRed &= 0x00FF0000;
nRed >>= 16;
sal_Int32 nGreen = nCol;
nGreen &= 0x0000FF00;
nGreen >>= 8;
sal_Int32 nBlue = nCol;
nBlue &= 0x000000FF;
sal_Int32 nRGB = ( nAutoBits | (nBlue << 16) | (nGreen << 8) | nRed );
return nRGB;
}
sal_Int32
XLRGBToOORGB( sal_Int32 nCol )
{
sal_Int32 nAutoBits = nCol;
nAutoBits &= 0xFF000000;
sal_Int32 nBlue = nCol;
nBlue &= 0x00FF0000;
nBlue >>= 16;
sal_Int32 nGreen = nCol;
nGreen &= 0x0000FF00;
nGreen >>= 8;
sal_Int32 nRed = nCol;
nRed &= 0x000000FF;
sal_Int32 nRGB = ( nAutoBits | (nRed << 16) | (nGreen << 8) | nBlue );
return nRGB;
}
uno::Any
OORGBToXLRGB( const uno::Any& aCol )
{
sal_Int32 nCol(0);
aCol >>= nCol;
nCol = OORGBToXLRGB( nCol );
return uno::Any( nCol );
}
uno::Any
XLRGBToOORGB( const uno::Any& aCol )
{
sal_Int32 nCol(0);
aCol >>= nCol;
nCol = XLRGBToOORGB( nCol );
return uno::Any( nCol );
}
void PrintOutHelper( SfxViewShell const * pViewShell, const uno::Any& From, const uno::Any& To, const uno::Any& Copies, const uno::Any& Preview, const uno::Any& /*ActivePrinter*/, const uno::Any& /*PrintToFile*/, const uno::Any& Collate, const uno::Any& PrToFileName, bool bUseSelection )
{
sal_Int32 nTo = 0;
sal_Int32 nFrom = 0;
sal_Int16 nCopies = 1;
bool bPreview = false;
bool bCollate = false;
bool bSelection = bUseSelection;
From >>= nFrom;
To >>= nTo;
Copies >>= nCopies;
Preview >>= bPreview;
if ( nCopies > 1 ) // Collate only useful when more that 1 copy
Collate >>= bCollate;
OUString sRange( u"-"_ustr );
OUString sFileName;
if ( nFrom || nTo )
{
if ( nFrom )
sRange = OUString::number( nFrom ) + sRange;
if ( nTo )
sRange += OUString::number( nTo );
}
PrToFileName >>= sFileName;
SfxViewFrame* pViewFrame = nullptr;
if ( pViewShell )
pViewFrame = &pViewShell->GetViewFrame();
if ( !pViewFrame )
return;
SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
SfxBoolItem sfxCollate( SID_PRINT_COLLATE, bCollate );
aArgs.Put( sfxCollate );
SfxInt16Item sfxCopies( SID_PRINT_COPIES, nCopies );
aArgs.Put( sfxCopies );
if ( !sFileName.isEmpty() )
{
SfxStringItem sfxFileName( SID_FILE_NAME, sFileName);
aArgs.Put( sfxFileName );
}
if ( !sRange.isEmpty() )
{
SfxStringItem sfxRange( SID_PRINT_PAGES, sRange );
aArgs.Put( sfxRange );
}
SfxBoolItem sfxSelection( SID_SELECTION, bSelection );
aArgs.Put( sfxSelection );
SfxBoolItem sfxAsync( SID_ASYNCHRON, false );
aArgs.Put( sfxAsync );
SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher();
if ( !pDispatcher )
return;
if ( bPreview )
{
if ( !pViewFrame->GetFrame().IsInPlace() )
{
// #TODO is this necessary ( calc specific )
// SC_MOD()->InputEnterHandler();
pViewFrame->GetDispatcher()->Execute( SID_VIEWSHELL1, SfxCallMode::SYNCHRON );
WaitUntilPreviewIsClosed( pViewFrame );
}
}
else
pDispatcher->Execute( sal_uInt16(SID_PRINTDOC), SfxCallMode::SYNCHRON, aArgs );
// #FIXME #TODO
// 1 ActivePrinter ( how/can we switch a printer via API? )
// 2 PrintToFile ( ms behaviour if this option is specified but no
// filename supplied 'PrToFileName' then the user will be prompted )
// 3 Need to check behaviour of Selected sheets with range ( e.g. From & To
// values ) in oOO these options are mutually exclusive
// 4 There is a pop up to do with transparent objects in the print source
// should be able to disable that via configuration for the duration
// of this method
}
void PrintPreviewHelper( const css::uno::Any& /*EnableChanges*/, SfxViewShell const * pViewShell )
{
SfxViewFrame* pViewFrame = nullptr;
if ( pViewShell )
pViewFrame = &pViewShell->GetViewFrame();
if ( pViewFrame )
{
if ( !pViewFrame->GetFrame().IsInPlace() )
{
dispatchExecute( pViewShell, SID_VIEWSHELL1 );
WaitUntilPreviewIsClosed( pViewFrame );
}
}
}
void WaitUntilPreviewIsClosed( SfxViewFrame* pViewFrame )
{
while ( pViewFrame && isInPrintPreview( pViewFrame ) && !Application::IsQuit())
Application::Yield();
}
bool extractBoolFromAny( const uno::Any& rAny )
{
switch( rAny.getValueTypeClass() )
{
case uno::TypeClass_BOOLEAN:
return rAny.get< bool >();
case uno::TypeClass_FLOAT:
return rAny.get< float >() != 0.0;
case uno::TypeClass_DOUBLE:
return rAny.get< double >() != 0.0;
case uno::TypeClass_BYTE:
case uno::TypeClass_SHORT:
case uno::TypeClass_LONG:
return rAny.get< sal_Int32 >() != 0;
case uno::TypeClass_HYPER:
return rAny.get< sal_Int64 >() != 0;
default:;
}
throw uno::RuntimeException( u"Invalid type, cannot convert to boolean."_ustr , nullptr );
}
OUString extractStringFromAny( const uno::Any& rAny, bool bUppercaseBool )
{
switch( rAny.getValueTypeClass() )
{
case uno::TypeClass_STRING:
return rAny.get< OUString >();
case uno::TypeClass_BOOLEAN:
return bUppercaseBool ?
(rAny.get< bool >() ? u"TRUE"_ustr : u"FALSE"_ustr) :
OUString::boolean( rAny.get< bool >() );
case uno::TypeClass_FLOAT:
return OUString::number( rAny.get< float >() );
case uno::TypeClass_DOUBLE:
return OUString::number( rAny.get< double >() );
case uno::TypeClass_BYTE:
case uno::TypeClass_SHORT:
case uno::TypeClass_LONG:
return OUString::number( rAny.get< sal_Int32 >() );
case uno::TypeClass_HYPER:
return OUString::number( rAny.get< sal_Int64 >() );
default:;
}
throw uno::RuntimeException( u"Invalid type, cannot convert to string."_ustr , nullptr );
}
OUString extractStringFromAny( const uno::Any& rAny, const OUString& rDefault, bool bUppercaseBool )
{
return rAny.hasValue() ? extractStringFromAny( rAny, bUppercaseBool ) : rDefault;
}
OUString getAnyAsString( const uno::Any& pvargItem )
{
return extractStringFromAny( pvargItem );
}
OUString
ContainerUtilities::getUniqueName( const uno::Sequence< OUString >& _slist, const OUString& _sElementName, std::u16string_view _sSuffixSeparator)
{
return getUniqueName(_slist, _sElementName, _sSuffixSeparator, sal_Int32(2));
}
OUString
ContainerUtilities::getUniqueName( const uno::Sequence< OUString >& _slist, const OUString& _sElementName, std::u16string_view _sSuffixSeparator, sal_Int32 _nStartSuffix)
{
if ( !_slist.hasElements() )
return _sElementName;
OUString scompname = _sElementName;
sal_Int32 a = _nStartSuffix;
for (;;)
{
if (FieldInList(_slist, scompname) == -1)
return scompname;
scompname = _sElementName + _sSuffixSeparator + OUString::number( a++ );
}
}
sal_Int32
ContainerUtilities::FieldInList( const uno::Sequence< OUString >& SearchList, const OUString& SearchString )
{
// I wonder why comparing lexicographically is done
// when it's a match, is it interesting?
return comphelper::findValue(SearchList, SearchString);
}
static bool NeedEsc(sal_Unicode cCode)
{
return u".^$+\\|{}()"_ustr.indexOf(cCode) != -1;
}
OUString VBAToRegexp(const OUString &rIn)
{
OUStringBuffer sResult;
const sal_Unicode *start = rIn.getStr();
const sal_Unicode *end = start + rIn.getLength();
int seenright = 0;
while (start < end)
{
switch (*start)
{
case '?':
sResult.append('.');
start++;
break;
case '*':
sResult.append(".*");
start++;
break;
case '#':
sResult.append("[0-9]");
start++;
break;
case '~':
sResult.append('\\');
sResult.append(*(++start));
start++;
break;
// dump the ~ and escape the next character
case ']':
sResult.append('\\');
sResult.append(*start++);
break;
case '[':
sResult.append(*start++);
seenright = 0;
while (start < end && !seenright)
{
switch (*start)
{
case '[':
case '?':
case '*':
sResult.append('\\');
sResult.append(*start);
break;
case ']':
sResult.append(*start);
seenright = 1;
break;
case '!':
sResult.append('^');
break;
default:
if (NeedEsc(*start))
sResult.append('\\');
sResult.append(*start);
break;
}
start++;
}
break;
default:
if (NeedEsc(*start))
sResult.append('\\');
sResult.append(*start++);
}
}
return sResult.makeStringAndClear( );
}
static double getPixelToMeterConversionFactor( const css::uno::Reference< css::awt::XDevice >& xDevice, bool bVertical)
{
return bVertical ? xDevice->getInfo().PixelPerMeterY : xDevice->getInfo().PixelPerMeterX;
}
double PointsToPixels( const css::uno::Reference< css::awt::XDevice >& xDevice, double fPoints, bool bVertical)
{
double fConvertFactor = getPixelToMeterConversionFactor( xDevice, bVertical );
return o3tl::convert(fPoints, o3tl::Length::pt, o3tl::Length::m) * fConvertFactor;
}
double PixelsToPoints( const css::uno::Reference< css::awt::XDevice >& xDevice, double fPixels, bool bVertical)
{
double fConvertFactor = getPixelToMeterConversionFactor( xDevice, bVertical );
return o3tl::convert(fPixels / fConvertFactor, o3tl::Length::m, o3tl::Length::pt);
}
ConcreteXShapeGeometryAttributes::ConcreteXShapeGeometryAttributes( const css::uno::Reference< css::drawing::XShape >& xShape )
: m_aShapeHelper( xShape )
{
}
ConcreteXShapeGeometryAttributes::~ConcreteXShapeGeometryAttributes()
{
}
PointerStyle getPointerStyle( const uno::Reference< frame::XModel >& xModel )
{
PointerStyle nPointerStyle( PointerStyle::Arrow );
try
{
const uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW );
const uno::Reference< frame::XFrame > xFrame ( xController->getFrame(), uno::UNO_SET_THROW );
const uno::Reference< awt::XWindow > xWindow ( xFrame->getContainerWindow(), uno::UNO_SET_THROW );
// why the heck isn't there an XWindowPeer::getPointer, but a setPointer only?
const vcl::Window* pWindow = VCLUnoHelper::GetWindow( xWindow );
if ( pWindow )
nPointerStyle = pWindow->GetSystemWindow()->GetPointer();
}
catch (const uno::Exception&)
{
DBG_UNHANDLED_EXCEPTION("vbahelper");
}
return nPointerStyle;
}
// #FIXME this method looks wrong, shouldn't it just affect calc *or* writer
// document/frame/window(s) but not both ( and depending on what api called
// this )
void setCursorHelper( const uno::Reference< frame::XModel >& xModel, PointerStyle nPointer, bool bOverWrite )
{
::std::vector< uno::Reference< frame::XController > > aControllers;
uno::Reference< frame::XModel2 > xModel2( xModel, uno::UNO_QUERY );
if ( xModel2.is() )
{
const uno::Reference< container::XEnumeration > xEnumControllers( xModel2->getControllers(), uno::UNO_SET_THROW );
while ( xEnumControllers->hasMoreElements() )
{
const uno::Reference< frame::XController > xController( xEnumControllers->nextElement(), uno::UNO_QUERY_THROW );
aControllers.push_back( xController );
}
}
else
{
if ( xModel.is() )
{
const uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW );
aControllers.push_back( xController );
}
}
for ( const auto& rController : aControllers )
{
const uno::Reference< frame::XFrame > xFrame ( rController->getFrame(), uno::UNO_SET_THROW );
const uno::Reference< awt::XWindow > xWindow ( xFrame->getContainerWindow(), uno::UNO_SET_THROW );
VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
SAL_WARN_IF( !pWindow, "vbahelper", "ScVbaApplication::setCursor: no window!" );
if ( !pWindow )
continue;
pWindow->GetSystemWindow()->SetPointer( nPointer );
pWindow->GetSystemWindow()->EnableChildPointerOverwrite( bOverWrite );
}
}
void setDefaultPropByIntrospection( const uno::Any& aObj, const uno::Any& aValue )
{
uno::Reference< beans::XIntrospectionAccess > xUnoAccess( getIntrospectionAccess( aObj ) );
// #MAYBE #FIXME sort of a bit of a hack,
uno::Reference< script::XDefaultProperty > xDflt( aObj, uno::UNO_QUERY_THROW );
uno::Reference< beans::XPropertySet > xPropSet;
if ( xUnoAccess.is() )
xPropSet.set( xUnoAccess->queryAdapter( cppu::UnoType<beans::XPropertySet>::get()), uno::UNO_QUERY);
if ( !xPropSet.is() )
throw uno::RuntimeException();
xPropSet->setPropertyValue( xDflt->getDefaultPropertyName(), aValue );
}
uno::Any getPropertyValue( const uno::Sequence< beans::PropertyValue >& aProp, const OUString& aName )
{
auto pProp = std::find_if(aProp.begin(), aProp.end(),
[&aName](const beans::PropertyValue& rProp) { return rProp.Name == aName; });
if (pProp != aProp.end())
return pProp->Value;
return uno::Any();
}
bool setPropertyValue( uno::Sequence< beans::PropertyValue >& aProp, const OUString& aName, const uno::Any& aValue )
{
auto [begin, end] = asNonConstRange(aProp);
auto pProp = std::find_if(begin, end,
[&aName](const beans::PropertyValue& rProp) { return rProp.Name == aName; });
if (pProp != end)
{
pProp->Value = aValue;
return true;
}
return false;
}
void setOrAppendPropertyValue( uno::Sequence< beans::PropertyValue >& aProp, const OUString& aName, const uno::Any& aValue )
{
if( setPropertyValue( aProp, aName, aValue ) )
return;
// append the property
sal_Int32 nLength = aProp.getLength();
aProp.realloc( nLength + 1 );
auto pProp = aProp.getArray();
pProp[ nLength ].Name = aName;
pProp[ nLength ].Value = aValue;
}
bool executeRunTimeLibrary(const std::u16string_view& rSbRtl_command, SbxArray* pParameters)
{
StarBASIC* pBasic = dynamic_cast< StarBASIC* >(StarBASIC::GetActiveModule()->GetParent());
if (!pBasic)
return false;
SbxObject* pRunTimeLibrary = pBasic->GetRtl();
if (!pRunTimeLibrary)
return false;
SbxVariable* pFound = pRunTimeLibrary->Find(OUString(rSbRtl_command), SbxClassType::Method);
SbxMethod* pMethod = dynamic_cast<SbxMethod*>(pFound);
if (!pMethod)
return false;
pMethod->SetParameters(pParameters);
// Believe it or not, this actually runs the command
pMethod->Broadcast(SfxHintId::BasicDataWanted);
return true;
}
// ====UserFormGeomentryHelper====
UserFormGeometryHelper::UserFormGeometryHelper(
const uno::Reference< awt::XControl >& xControl,
double fOffsetX, double fOffsetY ) :
mfOffsetX( fOffsetX ),
mfOffsetY( fOffsetY ),
mbDialog( uno::Reference< awt::XDialog >( xControl, uno::UNO_QUERY ).is() )
{
if ( !xControl.is() )
throw uno::RuntimeException( u"No control is provided!"_ustr );
mxWindow.set( xControl->getPeer(), uno::UNO_QUERY_THROW );
mxModelProps.set( xControl->getModel(), uno::UNO_QUERY_THROW );
mxUnitConv.set( mxWindow, uno::UNO_QUERY_THROW );
}
double UserFormGeometryHelper::getLeft() const
{
return implGetPos( false );
}
void UserFormGeometryHelper::setLeft( double fLeft )
{
implSetPos( fLeft, false );
}
double UserFormGeometryHelper::getTop() const
{
return implGetPos( true );
}
void UserFormGeometryHelper::setTop( double fTop )
{
implSetPos( fTop, true );
}
double UserFormGeometryHelper::getWidth() const
{
return implGetSize( false, true );
}
void UserFormGeometryHelper::setWidth( double fWidth )
{
implSetSize( fWidth, false, true );
}
double UserFormGeometryHelper::getHeight() const
{
return implGetSize( true, true );
}
void UserFormGeometryHelper::setHeight( double fHeight )
{
implSetSize( fHeight, true, true );
}
double UserFormGeometryHelper::getInnerWidth() const
{
return implGetSize( false, false );
}
void UserFormGeometryHelper::setInnerWidth( double fWidth )
{
implSetSize( fWidth, false, false );
}
double UserFormGeometryHelper::getInnerHeight() const
{
return implGetSize( true, false );
}
void UserFormGeometryHelper::setInnerHeight( double fHeight )
{
implSetSize( fHeight, true, false );
}
double UserFormGeometryHelper::getOffsetX() const
{
return mfOffsetX;
}
double UserFormGeometryHelper::getOffsetY() const
{
return mfOffsetY;
}
constexpr OUString saPosXName = u"PositionX"_ustr;
constexpr OUString saPosYName = u"PositionY"_ustr;
constexpr OUString saWidthName = u"Width"_ustr;
constexpr OUString saHeightName = u"Height"_ustr;
double UserFormGeometryHelper::implGetPos( bool bPosY ) const
{
sal_Int32 nPosAppFont = mxModelProps->getPropertyValue( bPosY ? saPosYName : saPosXName ).get< sal_Int32 >();
// appfont to pixel
awt::Point aPosPixel = mxUnitConv->convertPointToPixel( awt::Point( nPosAppFont, nPosAppFont ), util::MeasureUnit::APPFONT );
// pixel to VBA points
awt::Point aPosPoint = mxUnitConv->convertPointToLogic( aPosPixel, util::MeasureUnit::POINT );
return bPosY ? (aPosPoint.Y - mfOffsetY) : (aPosPoint.X - mfOffsetX);
}
void UserFormGeometryHelper::implSetPos( double fPos, bool bPosY )
{
// convert passed VBA points to pixels
sal_Int32 nPosPixel = static_cast< sal_Int32 >( fPos + (bPosY ? mfOffsetY : mfOffsetX) );
awt::Point aPosPixel = mxUnitConv->convertPointToPixel( awt::Point( nPosPixel, nPosPixel ), util::MeasureUnit::POINT );
// pixel to appfont
awt::Point aPosAppFont = mxUnitConv->convertPointToLogic( aPosPixel, util::MeasureUnit::APPFONT );
mxModelProps->setPropertyValue( bPosY ? saPosYName : saPosXName, uno::Any( bPosY ? aPosAppFont.Y : aPosAppFont.X ) );
}
double UserFormGeometryHelper::implGetSize( bool bHeight, bool bOuter ) const
{
sal_Int32 nSizeAppFont = mxModelProps->getPropertyValue( bHeight ? saHeightName : saWidthName ).get< sal_Int32 >();
// appfont to pixel
awt::Size aSizePixel = mxUnitConv->convertSizeToPixel( awt::Size( nSizeAppFont, nSizeAppFont ), util::MeasureUnit::APPFONT );
/* The VBA symbols 'Width' and 'Height' return the outer size including
window decoration (in difference to the symbols 'InnerWidth' and
'InnerHeight'), but the window API returns the inner size. */
if( mbDialog && bOuter )
{
if( const vcl::Window* pWindow = VCLUnoHelper::GetWindow( mxWindow ) )
{
AbsoluteScreenPixelRectangle aOuterRect = pWindow->GetWindowExtentsAbsolute();
aSizePixel = awt::Size( aOuterRect.getOpenWidth(), aOuterRect.getOpenHeight() );
}
}
// pixel to VBA points
awt::Size aSizePoint = mxUnitConv->convertSizeToLogic( aSizePixel, util::MeasureUnit::POINT );
return bHeight ? aSizePoint.Height : aSizePoint.Width;
}
void UserFormGeometryHelper::implSetSize( double fSize, bool bHeight, bool bOuter )
{
// convert passed VBA points to pixels
sal_Int32 nSize = static_cast< sal_Int32 >( fSize );
awt::Size aSizePixel = mxUnitConv->convertSizeToPixel( awt::Size( nSize, nSize ), util::MeasureUnit::POINT );
/* The VBA symbols 'Width' and 'Height' set the outer size (in difference
to the symbols 'InnerWidth' and 'InnerHeight'), but the dialog model
expects the inner size. We have to remove the window extents from the
pixel height to get the same result. */
if ( mbDialog && bOuter )
{
if( const vcl::Window* pWindow = VCLUnoHelper::GetWindow( mxWindow ) )
{
AbsoluteScreenPixelRectangle aOuterRect = pWindow->GetWindowExtentsAbsolute();
if( !aOuterRect.IsEmpty() )
{
awt::Rectangle aInnerRect = mxWindow->getPosSize();
sal_Int32 nDecorWidth = aOuterRect.getOpenWidth() - aInnerRect.Width;
sal_Int32 nDecorHeight = aOuterRect.getOpenHeight() - aInnerRect.Height;
aSizePixel.Width = ::std::max< sal_Int32 >( aSizePixel.Width - nDecorWidth, 1 );
aSizePixel.Height = ::std::max< sal_Int32 >( aSizePixel.Height - nDecorHeight, 1 );
}
}
}
awt::Size aSizeAppFont = mxUnitConv->convertSizeToLogic( aSizePixel, util::MeasureUnit::APPFONT );
mxModelProps->setPropertyValue( bHeight ? saHeightName : saWidthName, uno::Any( bHeight ? aSizeAppFont.Height : aSizeAppFont.Width ) );
}
double ConcreteXShapeGeometryAttributes::getLeft() const
{
return m_aShapeHelper.getLeft();
}
void ConcreteXShapeGeometryAttributes::setLeft( double nLeft )
{
m_aShapeHelper.setLeft( nLeft );
}
double ConcreteXShapeGeometryAttributes::getTop() const
{
return m_aShapeHelper.getTop();
}
void ConcreteXShapeGeometryAttributes::setTop( double nTop )
{
m_aShapeHelper.setTop( nTop );
}
double ConcreteXShapeGeometryAttributes::getHeight() const
{
return m_aShapeHelper.getHeight();
}
void ConcreteXShapeGeometryAttributes::setHeight( double nHeight )
{
m_aShapeHelper.setHeight( nHeight );
}
double ConcreteXShapeGeometryAttributes::getWidth() const
{
return m_aShapeHelper.getWidth();
}
void ConcreteXShapeGeometryAttributes::setWidth( double nWidth)
{
m_aShapeHelper.setWidth( nWidth );
}
ShapeHelper::ShapeHelper( css::uno::Reference< css::drawing::XShape > _xShape)
: xShape(std::move( _xShape ))
{
if( !xShape.is() )
throw css::uno::RuntimeException( u"No valid shape for helper"_ustr );
}
double ShapeHelper::getHeight() const
{
return Millimeter::getInPoints(xShape->getSize().Height);
}
void ShapeHelper::setHeight(double _fheight)
{
css::awt::Size aSize = xShape->getSize();
aSize.Height = Millimeter::getInHundredthsOfOneMillimeter(_fheight);
xShape->setSize(aSize);
}
double ShapeHelper::getWidth() const
{
return Millimeter::getInPoints(xShape->getSize().Width);
}
void ShapeHelper::setWidth(double _fWidth)
{
css::awt::Size aSize = xShape->getSize();
aSize.Width = Millimeter::getInHundredthsOfOneMillimeter(_fWidth);
xShape->setSize(aSize);
}
double ShapeHelper::getLeft() const
{
return Millimeter::getInPoints(xShape->getPosition().X);
}
void ShapeHelper::setLeft(double _fLeft)
{
css::awt::Point aPoint = xShape->getPosition();
aPoint.X = Millimeter::getInHundredthsOfOneMillimeter(_fLeft);
xShape->setPosition(aPoint);
}
double ShapeHelper::getTop() const
{
return Millimeter::getInPoints(xShape->getPosition().Y);
}
void ShapeHelper::setTop(double _fTop)
{
css::awt::Point aPoint = xShape->getPosition();
aPoint.Y = Millimeter::getInHundredthsOfOneMillimeter(_fTop);
xShape->setPosition(aPoint);
}
void DebugHelper::basicexception( const css::uno::Exception& ex, ErrCode err, std::u16string_view /*additionalArgument*/ )
{
// #TODO #FIXME ( do we want to support additionalArg here )
throw css::script::BasicErrorException( ex.Message, css::uno::Reference< css::uno::XInterface >(), sal_uInt32(err), OUString() );
}
void DebugHelper::basicexception( ErrCode err, std::u16string_view additionalArgument )
{
basicexception( css::uno::Exception(), err, additionalArgument );
}
void DebugHelper::basicexception( const css::uno::Exception& ex )
{
basicexception( ex, ERRCODE_BASIC_INTERNAL_ERROR, {} );
}
void DebugHelper::runtimeexception( ErrCode err )
{
// #TODO #FIXME ( do we want to support additionalArg here )
throw css::uno::RuntimeException( css::uno::Exception().Message + " " + OUString::number(sal_uInt32(err)),
css::uno::Reference< css::uno::XInterface >() );
}
Millimeter::Millimeter():m_nMillimeter(0) {}
Millimeter::Millimeter(double mm):m_nMillimeter(mm) {}
void Millimeter::setInPoints(double points)
{
m_nMillimeter = convertPointToMm100(points) / 100.0;
}
double Millimeter::getInHundredthsOfOneMillimeter() const
{
return m_nMillimeter * 100;
}
sal_Int32 Millimeter::getInHundredthsOfOneMillimeter(double points)
{
sal_Int32 mm = std::round(convertPointToMm100(points));
return mm;
}
double Millimeter::getInPoints(int _hmm)
{
double points = convertMm100ToPoint<double>(_hmm);
return points;
}
uno::Reference< XHelperInterface > getVBADocument( const uno::Reference< frame::XModel >& xModel )
{
uno::Reference< XHelperInterface > xIf;
try
{
uno::Reference< beans::XPropertySet > xDocProps( xModel, uno::UNO_QUERY );
if (!xDocProps)
return xIf;
OUString aCodeName;
xDocProps->getPropertyValue( u"CodeName"_ustr ) >>= aCodeName;
xIf = getUnoDocModule( aCodeName, getSfxObjShell( xModel ) );
}
catch (const uno::Exception&)
{
}
return xIf;
}
uno::Reference< XHelperInterface > getUnoDocModule( std::u16string_view aModName, SfxObjectShell const * pShell )
{
uno::Reference< XHelperInterface > xIf;
if ( pShell )
{
OUString sProj( u"Standard"_ustr );
// GetBasicManager() causes a SolarMutex assertion failure in some use cases from
// Automation, at least when opening a Calc Document through ooo::vba::excel::
// XWorkbooks::Open(). Let's see if this check is a good way around that. It does seem that
// callers are prepared for this to return null?
if (comphelper::Automation::AutomationInvokedZone::isActive())
return xIf;
BasicManager* pBasMgr = pShell->GetBasicManager();
if ( pBasMgr && !pBasMgr->GetName().isEmpty() )
sProj = pBasMgr->GetName();
if( StarBASIC* pBasic = pShell->GetBasicManager()->GetLib( sProj ) )
if( SbModule* pMod = pBasic->FindModule( aModName ) )
xIf.set( pMod->GetUnoModule(), uno::UNO_QUERY );
}
return xIf;
}
SfxObjectShell* getSfxObjShell( const uno::Reference< frame::XModel >& xModel )
{
SfxObjectShell* pFoundShell = comphelper::getFromUnoTunnel<SfxObjectShell>(xModel);
if ( !pFoundShell )
throw uno::RuntimeException();
return pFoundShell;
}
} //org
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.