Quelle dispatchrecorder.cxx
Sprache: C
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project .
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2 . 0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice :
*
* Licensed to the Apache Software Foundation ( ASF ) under one or more
* contributor license agreements . See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership . The ASF licenses this file to you under the Apache
* License , Version 2 . 0 ( the " License " ) ; you may not use this file
* except in compliance with the License . You may obtain a copy of
* the License at http : //www.apache.org/licenses/LICENSE-2.0 .
*/
#include <recording/dispatchrecorder.hxx>
#include <com/sun/star/frame/DispatchStatement.hpp>
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
#include <com/sun/star/script/CannotConvertException.hpp>
#include <com/sun/star/script/Converter.hpp>
#include <o3tl/any.hxx>
#include <osl/diagnose.h>
#include <vcl/svapp.hxx>
#include <typelib/typedescription.h>
#include <cppuhelper/supportsservice.hxx>
using namespace ::com::sun::star::uno;
namespace framework{
// used to mark a dispatch as comment (mostly it indicates an error) Changing of this define will impact all using of such comments...
constexpr OUString REM_AS_COMMENT = u"rem " _ustr;
// XInterface, XTypeProvider, XServiceInfo
OUString SAL_CALL DispatchRecorder::getImplementationName()
{
return u"com.sun.star.comp.framework.DispatchRecorder" _ustr;
}
sal_Bool SAL_CALL DispatchRecorder::supportsService( const OUString& sServiceName )
{
return cppu::supportsService(this , sServiceName);
}
css::uno::Sequence< OUString > SAL_CALL DispatchRecorder::getSupportedServiceNames()
{
return { u"com.sun.star.frame.DispatchRecorder" _ustr };
}
static void flatten_struct_members(
::std::vector< Any > * vec, void const * data,
typelib_CompoundTypeDescription * pTD )
{
if (pTD->pBaseTypeDescription)
{
flatten_struct_members( vec, data, pTD->pBaseTypeDescription );
}
for ( sal_Int32 nPos = 0 ; nPos < pTD->nMembers; ++nPos )
{
vec->push_back(
Any( static_cast <char const *>(data) + pTD->pMemberOffsets[ nPos ], pTD->ppTypeRefs[ nPos ] ) );
}
}
static Sequence< Any > make_seq_out_of_struct(
Any const & val )
{
Type const & type = val.getValueType();
TypeClass eTypeClass = type.getTypeClass();
if (TypeClass_STRUCT != eTypeClass && TypeClass_EXCEPTION != eTypeClass)
{
throw RuntimeException(
type.getTypeName() + "is no struct or exception!" );
}
typelib_TypeDescription * pTD = nullptr;
TYPELIB_DANGER_GET( &pTD, type.getTypeLibType() );
OSL_ASSERT( pTD );
if (! pTD)
{
throw RuntimeException(
"cannot get type descr of type " + type.getTypeName() );
}
::std::vector< Any > vec;
vec.reserve( reinterpret_cast <typelib_CompoundTypeDescription *>(pTD)->nMembers ); // good guess
flatten_struct_members( &vec, val.getValue(), reinterpret_cast <typelib_CompoundTypeDescription *>(pTD) );
TYPELIB_DANGER_RELEASE( pTD );
return Sequence< Any >( vec.data(), vec.size() );
}
DispatchRecorder::DispatchRecorder( const css::uno::Reference< css::uno::XComponentContext >& xContext )
: m_nRecordingID(0 )
, m_xConverter(css::script::Converter::create(xContext))
{
}
DispatchRecorder::~DispatchRecorder()
{
}
// generate header
void SAL_CALL DispatchRecorder::startRecording( const css::uno::Reference< css::frame::XFrame >& )
{
/* SAFE{ */
/* } */
}
void SAL_CALL DispatchRecorder::recordDispatch( const css::util::URL& aURL,
const css::uno::Sequence< css::beans::PropertyValue >& lArguments )
{
css::frame::DispatchStatement aStatement( aURL.Complete, OUString(), lArguments, 0 , false );
m_aStatements.push_back( aStatement );
}
void SAL_CALL DispatchRecorder::recordDispatchAsComment( const css::util::URL& aURL,
const css::uno::Sequence< css::beans::PropertyValue >& lArguments )
{
// last parameter must be set to true -> it's a comment
css::frame::DispatchStatement aStatement( aURL.Complete, OUString(), lArguments, 0 , true );
m_aStatements.push_back( aStatement );
}
void SAL_CALL DispatchRecorder::endRecording()
{
SolarMutexGuard g;
m_aStatements.clear();
}
OUString SAL_CALL DispatchRecorder::getRecordedMacro()
{
SolarMutexGuard g;
if ( m_aStatements.empty() )
return OUString();
OUStringBuffer aScriptBuffer;
aScriptBuffer.ensureCapacity(10000 );
m_nRecordingID = 1 ;
aScriptBuffer.append(
"rem ----------------------------------------------------------------------\n"
"rem define variables\n"
"dim document as object\n"
"dim dispatcher as object\n"
"rem ----------------------------------------------------------------------\n"
"rem get access to the document\n"
"document = ThisComponent.CurrentController.Frame\n"
"dispatcher = createUnoService(\" com.sun.star.frame.DispatchHelper\")\n\n" );
for (auto const & statement : m_aStatements)
implts_recordMacro( statement.aCommand, statement.aArgs, statement.bIsComment, aScriptBuffer );
OUString sScript = aScriptBuffer.makeStringAndClear();
return sScript;
}
void DispatchRecorder::AppendToBuffer( const css::uno::Any& aValue, OUStringBuffer& aArgumentBuffer )
{
// if value == bool
if (aValue.getValueTypeClass() == css::uno::TypeClass_STRUCT )
{
// structs are recorded as arrays, convert to "Sequence of any"
Sequence< Any > aSeq = make_seq_out_of_struct( aValue );
aArgumentBuffer.append("Array(" );
for ( sal_Int32 nAny=0 ; nAny<aSeq.getLength(); nAny++ )
{
AppendToBuffer( aSeq[nAny], aArgumentBuffer );
if ( nAny+1 < aSeq.getLength() )
// not last argument
aArgumentBuffer.append("," );
}
aArgumentBuffer.append(")" );
}
else if (aValue.getValueTypeClass() == css::uno::TypeClass_SEQUENCE )
{
// convert to "Sequence of any"
css::uno::Sequence < css::uno::Any > aSeq;
css::uno::Any aNew;
try { aNew = m_xConverter->convertTo( aValue, cppu::UnoType<css::uno::Sequence < css::uno::Any >>::get() ); }
catch (const css::uno::Exception&) {}
aNew >>= aSeq;
aArgumentBuffer.append("Array(" );
for ( sal_Int32 nAny=0 ; nAny<aSeq.getLength(); nAny++ )
{
AppendToBuffer( aSeq[nAny], aArgumentBuffer );
if ( nAny+1 < aSeq.getLength() )
// not last argument
aArgumentBuffer.append("," );
}
aArgumentBuffer.append(")" );
}
else if (aValue.getValueTypeClass() == css::uno::TypeClass_STRING )
{
// strings need \"
OUString sVal;
aValue >>= sVal;
// encode non printable characters or '"' by using the CHR$ function
if ( !sVal.isEmpty() )
{
const sal_Unicode* pChars = sVal.getStr();
bool bInString = false ;
for ( sal_Int32 nChar=0 ; nChar<sVal.getLength(); nChar ++ )
{
if ( pChars[nChar] < 32 || pChars[nChar] == '"' )
{
// problematic character detected
if ( bInString )
{
// close current string
aArgumentBuffer.append("\" ");
bInString = false ;
}
if ( nChar>0 )
// if this is not the first character, parts of the string have already been added
aArgumentBuffer.append("+" );
// add the character constant
aArgumentBuffer.append("CHR$(" );
aArgumentBuffer.append( static_cast <sal_Int32>(pChars[nChar]) );
aArgumentBuffer.append(")" );
}
else
{
if ( !bInString )
{
if ( nChar>0 )
// if this is not the first character, parts of the string have already been added
aArgumentBuffer.append("+" );
// start a new string
aArgumentBuffer.append("\" ");
bInString = true ;
}
aArgumentBuffer.append( pChars[nChar] );
}
}
// close string
if ( bInString )
aArgumentBuffer.append("\" ");
}
else
aArgumentBuffer.append("\" \"" );
}
else if (auto nVal = o3tl::tryAccess<sal_Unicode>(aValue))
{
// character variables are recorded as strings, back conversion must be handled in client code
aArgumentBuffer.append("\" ");
if ( *nVal == '\"' )
// encode \" to \"\"
aArgumentBuffer.append(*nVal);
aArgumentBuffer.append(*nVal);
aArgumentBuffer.append("\" ");
}
else
{
css::uno::Any aNew;
try
{
aNew = m_xConverter->convertToSimpleType( aValue, css::uno::TypeClass_STRING );
}
catch (const css::script::CannotConvertException&) {}
catch (const css::uno::Exception&) {}
OUString sVal;
aNew >>= sVal;
if (aValue.getValueTypeClass() == css::uno::TypeClass_ENUM )
{
OUString aName = aValue.getValueTypeName();
aArgumentBuffer.append( aName );
aArgumentBuffer.append("." );
}
aArgumentBuffer.append(sVal);
}
}
void DispatchRecorder::implts_recordMacro( std::u16string_view aURL,
const css::uno::Sequence< css::beans::PropertyValue >& lArguments,
bool bAsComment, OUStringBuffer& aScriptBuffer )
{
OUStringBuffer aArgumentBuffer(1000 );
// this value is used to name the arrays of aArgumentBuffer
OUString sArrayName = "args" + OUString::number(m_nRecordingID);
aScriptBuffer.append("rem ----------------------------------------------------------------------\n" );
sal_Int32 nLength = lArguments.getLength();
sal_Int32 nValidArgs = 0 ;
for ( sal_Int32 i=0 ; i<nLength; ++i )
{
if (!lArguments[i].Value.hasValue())
continue ;
OUStringBuffer sValBuffer(100 );
try
{
AppendToBuffer(lArguments[i].Value, sValBuffer);
}
catch (const css::uno::Exception&)
{
sValBuffer.setLength(0 );
}
if (sValBuffer.isEmpty())
continue ;
{
// add arg().Name
if (bAsComment)
aArgumentBuffer.append(REM_AS_COMMENT);
aArgumentBuffer.append(sArrayName
+ "(" + OUString::number(nValidArgs)
+ ").Name = \" " + lArguments[i].Name
+ "\" \n");
// add arg().Value
if (bAsComment)
aArgumentBuffer.append(REM_AS_COMMENT);
aArgumentBuffer.append(sArrayName
+ "(" + OUString::number(nValidArgs)
+ ").Value = " + sValBuffer + "\n" );
++nValidArgs;
}
}
// if aArgumentBuffer exist - pack it into the aScriptBuffer
if (nValidArgs>0 )
{
if (bAsComment)
aScriptBuffer.append(REM_AS_COMMENT);
aScriptBuffer.append("dim " );
aScriptBuffer.append (sArrayName);
aScriptBuffer.append("(" );
aScriptBuffer.append (static_cast <sal_Int32>(nValidArgs-1 )); // 0 based!
aScriptBuffer.append(") as new com.sun.star.beans.PropertyValue\n" );
aScriptBuffer.append (aArgumentBuffer);
aScriptBuffer.append("\n" );
}
// add code for dispatches
if (bAsComment)
aScriptBuffer.append(REM_AS_COMMENT);
aScriptBuffer.append("dispatcher.executeDispatch(document, \" ");
aScriptBuffer.append(aURL);
aScriptBuffer.append("\" , \"\" , 0 , ");
if (nValidArgs<1 )
aScriptBuffer.append("Array()" );
else
{
aScriptBuffer.append( sArrayName );
aScriptBuffer.append("()" );
}
aScriptBuffer.append(")\n\n" );
/* SAFE { */
m_nRecordingID++;
/* } */
}
css::uno::Type SAL_CALL DispatchRecorder::getElementType()
{
return cppu::UnoType<css::frame::DispatchStatement>::get();
}
sal_Bool SAL_CALL DispatchRecorder::hasElements()
{
return (! m_aStatements.empty());
}
sal_Int32 SAL_CALL DispatchRecorder::getCount()
{
return m_aStatements.size();
}
css::uno::Any SAL_CALL DispatchRecorder::getByIndex(sal_Int32 idx)
{
if (idx >= static_cast <sal_Int32>(m_aStatements.size()))
throw css::lang::IndexOutOfBoundsException( u"Dispatch recorder out of bounds" _ustr );
Any element(&m_aStatements[idx],
cppu::UnoType<css::frame::DispatchStatement>::get());
return element;
}
void SAL_CALL DispatchRecorder::replaceByIndex(sal_Int32 idx, const css::uno::Any& element)
{
if (element.getValueType() !=
cppu::UnoType<css::frame::DispatchStatement>::get()) {
throw css::lang::IllegalArgumentException(
u"Illegal argument in dispatch recorder" _ustr,
Reference< XInterface >(), 2 );
}
if (idx >= static_cast <sal_Int32>(m_aStatements.size()))
throw css::lang::IndexOutOfBoundsException(
u"Dispatch recorder out of bounds" _ustr );
auto pStatement = o3tl::doAccess<css::frame::DispatchStatement>(element);
m_aStatements[idx] = css::frame::DispatchStatement(
pStatement->aCommand,
pStatement->aTarget,
pStatement->aArgs,
pStatement->nFlags,
pStatement->bIsComment);
}
} // namespace framework
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
framework_DispatchRecorder_get_implementation(
css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const & )
{
return cppu::acquire(new framework::DispatchRecorder(context));
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent C=92 H=91 G=91
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-10-01)
¤
*© Formatika GbR, Deutschland
2026-10-10
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=1126438
#Domains=1897691