summaryrefslogtreecommitdiff
path: root/framework/source/recording/dispatchrecorder.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'framework/source/recording/dispatchrecorder.cxx')
-rw-r--r--framework/source/recording/dispatchrecorder.cxx493
1 files changed, 493 insertions, 0 deletions
diff --git a/framework/source/recording/dispatchrecorder.cxx b/framework/source/recording/dispatchrecorder.cxx
new file mode 100644
index 000000000000..7716fb45e791
--- /dev/null
+++ b/framework/source/recording/dispatchrecorder.cxx
@@ -0,0 +1,493 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_framework.hxx"
+#include <recording/dispatchrecorder.hxx>
+#include <com/sun/star/frame/DispatchStatement.hpp>
+#include <threadhelp/writeguard.hxx>
+#include <threadhelp/readguard.hxx>
+#include <services.h>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star::uno;
+
+namespace framework{
+
+// used to mark a dispatch as comment (mostly it indicates an error) Changing of this wdefine will impact all using of such comments ...
+#define REM_AS_COMMENT "rem "
+
+//*****************************************************************************************************************
+// XInterface, XTypeProvider, XServiceInfo
+//*****************************************************************************************************************
+DEFINE_XINTERFACE_6(
+ DispatchRecorder,
+ OWeakObject,
+ DIRECT_INTERFACE(css::lang::XTypeProvider),
+ DIRECT_INTERFACE(css::lang::XServiceInfo),
+ DIRECT_INTERFACE(css::frame::XDispatchRecorder),
+ DIRECT_INTERFACE(css::container::XIndexReplace),
+ DIRECT_INTERFACE(css::container::XIndexAccess),
+ DIRECT_INTERFACE(css::container::XElementAccess))
+
+DEFINE_XTYPEPROVIDER_6(
+ DispatchRecorder,
+ css::lang::XTypeProvider,
+ css::lang::XServiceInfo,
+ css::frame::XDispatchRecorder,
+ css::container::XIndexReplace,
+ css::container::XIndexAccess,
+ css::container::XElementAccess)
+
+DEFINE_XSERVICEINFO_MULTISERVICE(
+ DispatchRecorder,
+ ::cppu::OWeakObject,
+ SERVICENAME_DISPATCHRECORDER,
+ IMPLEMENTATIONNAME_DISPATCHRECORDER)
+
+DEFINE_INIT_SERVICE(
+ DispatchRecorder,
+ {
+ }
+)
+
+#include <typelib/typedescription.h>
+
+//--------------------------------------------------------------------------------------------------
+void flatten_struct_members(
+ ::std::vector< Any > * vec, void const * data,
+ typelib_CompoundTypeDescription * pTD )
+ SAL_THROW( () )
+{
+ if (pTD->pBaseTypeDescription)
+ {
+ flatten_struct_members( vec, data, pTD->pBaseTypeDescription );
+ }
+ for ( sal_Int32 nPos = 0; nPos < pTD->nMembers; ++nPos )
+ {
+ vec->push_back(
+ Any( (char const *)data + pTD->pMemberOffsets[ nPos ], pTD->ppTypeRefs[ nPos ] ) );
+ }
+}
+//==================================================================================================
+Sequence< Any > make_seq_out_of_struct(
+ Any const & val )
+ SAL_THROW( (RuntimeException) )
+{
+ Type const & type = val.getValueType();
+ TypeClass eTypeClass = type.getTypeClass();
+ if (TypeClass_STRUCT != eTypeClass && TypeClass_EXCEPTION != eTypeClass)
+ {
+ throw RuntimeException(
+ type.getTypeName() +
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("is no struct or exception!") ),
+ Reference< XInterface >() );
+ }
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, type.getTypeLibType() );
+ OSL_ASSERT( pTD );
+ if (! pTD)
+ {
+ throw RuntimeException(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get type descr of type ") ) +
+ type.getTypeName(),
+ Reference< XInterface >() );
+ }
+
+ ::std::vector< Any > vec;
+ vec.reserve( ((typelib_CompoundTypeDescription *)pTD)->nMembers ); // good guess
+ flatten_struct_members( &vec, val.getValue(), (typelib_CompoundTypeDescription *)pTD );
+ TYPELIB_DANGER_RELEASE( pTD );
+ return Sequence< Any >( &vec[ 0 ], vec.size() );
+}
+
+//***********************************************************************
+DispatchRecorder::DispatchRecorder( const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
+ : ThreadHelpBase ( &Application::GetSolarMutex() )
+ , ::cppu::OWeakObject( )
+ , m_xSMGR ( xSMGR )
+ , m_xConverter( m_xSMGR->createInstance(::rtl::OUString::createFromAscii("com.sun.star.script.Converter")), css::uno::UNO_QUERY )
+{
+}
+
+//************************************************************************
+DispatchRecorder::~DispatchRecorder()
+{
+}
+
+//*************************************************************************
+// generate header
+void SAL_CALL DispatchRecorder::startRecording( const css::uno::Reference< css::frame::XFrame >& ) throw( css::uno::RuntimeException )
+{
+ /* SAFE{ */
+ /* } */
+}
+
+//*************************************************************************
+void SAL_CALL DispatchRecorder::recordDispatch( const css::util::URL& aURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException )
+{
+ ::rtl::OUString aTarget;
+
+ com::sun::star::frame::DispatchStatement aStatement( aURL.Complete, aTarget, lArguments, 0, sal_False );
+ m_aStatements.push_back( aStatement );
+}
+
+//*************************************************************************
+void SAL_CALL DispatchRecorder::recordDispatchAsComment( const css::util::URL& aURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException )
+{
+ ::rtl::OUString aTarget;
+
+ // last parameter must be set to true -> it's a comment
+ com::sun::star::frame::DispatchStatement aStatement( aURL.Complete, aTarget, lArguments, 0, sal_True );
+ m_aStatements.push_back( aStatement );
+}
+
+//*************************************************************************
+void SAL_CALL DispatchRecorder::endRecording() throw( css::uno::RuntimeException )
+{
+ /* SAFE{ */
+ WriteGuard aWriteLock(m_aLock);
+ m_aStatements.clear();
+ /* } */
+}
+
+//*************************************************************************
+::rtl::OUString SAL_CALL DispatchRecorder::getRecordedMacro() throw( css::uno::RuntimeException )
+{
+ /* SAFE{ */
+ WriteGuard aWriteLock(m_aLock);
+
+ if ( m_aStatements.empty() )
+ return ::rtl::OUString();
+
+ ::rtl::OUStringBuffer aScriptBuffer;
+ aScriptBuffer.ensureCapacity(10000);
+ m_nRecordingID = 1;
+
+ aScriptBuffer.appendAscii("rem ----------------------------------------------------------------------\n");
+ aScriptBuffer.appendAscii("rem define variables\n");
+ aScriptBuffer.appendAscii("dim document as object\n");
+ aScriptBuffer.appendAscii("dim dispatcher as object\n");
+ aScriptBuffer.appendAscii("rem ----------------------------------------------------------------------\n");
+ aScriptBuffer.appendAscii("rem get access to the document\n");
+ aScriptBuffer.appendAscii("document = ThisComponent.CurrentController.Frame\n");
+ aScriptBuffer.appendAscii("dispatcher = createUnoService(\"com.sun.star.frame.DispatchHelper\")\n\n");
+
+ std::vector< com::sun::star::frame::DispatchStatement>::iterator p;
+ for ( p = m_aStatements.begin(); p != m_aStatements.end(); p++ )
+ implts_recordMacro( p->aCommand, p->aArgs, p->bIsComment, aScriptBuffer );
+ ::rtl::OUString sScript = aScriptBuffer.makeStringAndClear();
+ return sScript;
+ /* } */
+}
+
+//*************************************************************************
+void SAL_CALL DispatchRecorder::AppendToBuffer( css::uno::Any aValue, ::rtl::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.appendAscii("Array(");
+ for ( sal_Int32 nAny=0; nAny<aSeq.getLength(); nAny++ )
+ {
+ AppendToBuffer( aSeq[nAny], aArgumentBuffer );
+ if ( nAny+1 < aSeq.getLength() )
+ // not last argument
+ aArgumentBuffer.appendAscii(",");
+ }
+
+ aArgumentBuffer.appendAscii(")");
+ }
+ 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, ::getCppuType((const css::uno::Sequence < css::uno::Any >*)0) ); }
+ catch (css::uno::Exception&) {}
+
+ aNew >>= aSeq;
+ aArgumentBuffer.appendAscii("Array(");
+ for ( sal_Int32 nAny=0; nAny<aSeq.getLength(); nAny++ )
+ {
+ AppendToBuffer( aSeq[nAny], aArgumentBuffer );
+ if ( nAny+1 < aSeq.getLength() )
+ // not last argument
+ aArgumentBuffer.appendAscii(",");
+ }
+
+ aArgumentBuffer.appendAscii(")");
+ }
+ else if (aValue.getValueTypeClass() == css::uno::TypeClass_STRING )
+ {
+ // strings need \"
+ ::rtl::OUString sVal;
+ aValue >>= sVal;
+
+ // encode non printable characters or '"' by using the CHR$ function
+ if ( sVal.getLength() )
+ {
+ const sal_Unicode* pChars = sVal.getStr();
+ sal_Bool bInString = sal_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.appendAscii("\"");
+ bInString = sal_False;
+ }
+
+ if ( nChar>0 )
+ // if this is not the first character, parts of the string have already been added
+ aArgumentBuffer.appendAscii("+");
+
+ // add the character constant
+ aArgumentBuffer.appendAscii("CHR$(");
+ aArgumentBuffer.append( (sal_Int32) pChars[nChar] );
+ aArgumentBuffer.appendAscii(")");
+ }
+ else
+ {
+ if ( !bInString )
+ {
+ if ( nChar>0 )
+ // if this is not the first character, parts of the string have already been added
+ aArgumentBuffer.appendAscii("+");
+
+ // start a new string
+ aArgumentBuffer.appendAscii("\"");
+ bInString = sal_True;
+ }
+
+ aArgumentBuffer.append( pChars[nChar] );
+ }
+ }
+
+ // close string
+ if ( bInString )
+ aArgumentBuffer.appendAscii("\"");
+ }
+ else
+ aArgumentBuffer.appendAscii("\"\"");
+ }
+ else if (aValue.getValueType() == getCppuCharType())
+ {
+ // character variables are recorded as strings, back conversion must be handled in client code
+ sal_Unicode nVal = *((sal_Unicode*)aValue.getValue());
+ aArgumentBuffer.appendAscii("\"");
+ if ( (sal_Unicode(nVal) == '\"') )
+ // encode \" to \"\"
+ aArgumentBuffer.append((sal_Unicode)nVal);
+ aArgumentBuffer.append((sal_Unicode)nVal);
+ aArgumentBuffer.appendAscii("\"");
+ }
+ else
+ {
+ css::uno::Any aNew;
+ try
+ {
+ aNew = m_xConverter->convertToSimpleType( aValue, css::uno::TypeClass_STRING );
+ }
+ catch (css::script::CannotConvertException&) {}
+ catch (css::uno::Exception&) {}
+ ::rtl::OUString sVal;
+ aNew >>= sVal;
+
+ if (aValue.getValueTypeClass() == css::uno::TypeClass_ENUM )
+ {
+ ::rtl::OUString aName = aValue.getValueType().getTypeName();
+ aArgumentBuffer.append( aName );
+ aArgumentBuffer.appendAscii(".");
+ }
+
+ aArgumentBuffer.append(sVal);
+ }
+}
+
+void SAL_CALL DispatchRecorder::implts_recordMacro( const ::rtl::OUString& aURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArguments,
+ sal_Bool bAsComment, ::rtl::OUStringBuffer& aScriptBuffer )
+{
+ ::rtl::OUStringBuffer aArgumentBuffer(1000);
+ ::rtl::OUString sArrayName;
+ // this value is used to name the arrays of aArgumentBuffer
+ sArrayName = ::rtl::OUString::createFromAscii("args");
+ sArrayName += ::rtl::OUString::valueOf((sal_Int32)m_nRecordingID);
+
+ aScriptBuffer.appendAscii("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;
+
+ ::rtl::OUStringBuffer sValBuffer(100);
+ try
+ {
+ AppendToBuffer(lArguments[i].Value, sValBuffer);
+ }
+ catch(const css::uno::Exception&)
+ {
+ sValBuffer.setLength(0);
+ }
+ if (!sValBuffer.getLength())
+ continue;
+
+ {
+ // add arg().Name
+ if(bAsComment)
+ aArgumentBuffer.appendAscii(REM_AS_COMMENT);
+ aArgumentBuffer.append (sArrayName);
+ aArgumentBuffer.appendAscii("(");
+ aArgumentBuffer.append (nValidArgs);
+ aArgumentBuffer.appendAscii(").Name = \"");
+ aArgumentBuffer.append (lArguments[i].Name);
+ aArgumentBuffer.appendAscii("\"\n");
+
+ // add arg().Value
+ if(bAsComment)
+ aArgumentBuffer.appendAscii(REM_AS_COMMENT);
+ aArgumentBuffer.append (sArrayName);
+ aArgumentBuffer.appendAscii("(");
+ aArgumentBuffer.append (nValidArgs);
+ aArgumentBuffer.appendAscii(").Value = ");
+ aArgumentBuffer.append (sValBuffer.makeStringAndClear());
+ aArgumentBuffer.appendAscii("\n");
+
+ ++nValidArgs;
+ }
+ }
+
+ // if aArgumentBuffer exist - pack it into the aScriptBuffer
+ if(nValidArgs>0)
+ {
+ if(bAsComment)
+ aScriptBuffer.appendAscii(REM_AS_COMMENT);
+ aScriptBuffer.appendAscii("dim ");
+ aScriptBuffer.append (sArrayName);
+ aScriptBuffer.appendAscii("(");
+ aScriptBuffer.append ((sal_Int32)(nValidArgs-1)); // 0 based!
+ aScriptBuffer.appendAscii(") as new com.sun.star.beans.PropertyValue\n");
+ aScriptBuffer.append (aArgumentBuffer.makeStringAndClear());
+ aScriptBuffer.appendAscii("\n");
+ }
+
+ // add code for dispatches
+ if(bAsComment)
+ aScriptBuffer.appendAscii(REM_AS_COMMENT);
+ aScriptBuffer.appendAscii("dispatcher.executeDispatch(document, \"");
+ aScriptBuffer.append (aURL);
+ aScriptBuffer.appendAscii("\", \"\", 0, ");
+ if(nValidArgs<1)
+ aScriptBuffer.appendAscii("Array()");
+ else
+ {
+ aScriptBuffer.append( sArrayName.getStr() );
+ aScriptBuffer.appendAscii("()");
+ }
+ aScriptBuffer.appendAscii(")\n\n");
+
+ /* SAFE { */
+ m_nRecordingID++;
+ /* } */
+}
+
+com::sun::star::uno::Type SAL_CALL DispatchRecorder::getElementType() throw (::com::sun::star::uno::RuntimeException)
+{
+ return ::getCppuType((const com::sun::star::frame::DispatchStatement *)NULL);
+}
+
+sal_Bool SAL_CALL DispatchRecorder::hasElements() throw (::com::sun::star::uno::RuntimeException)
+{
+ return (! m_aStatements.empty());
+}
+
+sal_Int32 SAL_CALL DispatchRecorder::getCount() throw (::com::sun::star::uno::RuntimeException)
+{
+ return m_aStatements.size();
+}
+
+com::sun::star::uno::Any SAL_CALL DispatchRecorder::getByIndex(sal_Int32 idx) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
+{
+ if (idx >= (sal_Int32)m_aStatements.size()) {
+ throw com::sun::star::lang::IndexOutOfBoundsException(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "Dispatch recorder out of bounds") ),
+ Reference< XInterface >() );
+
+ }
+
+ Any element(&m_aStatements[idx],
+ ::getCppuType((const com::sun::star::frame::DispatchStatement *)NULL));
+
+ return element;
+}
+
+void SAL_CALL DispatchRecorder::replaceByIndex(sal_Int32 idx, const com::sun::star::uno::Any& element) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
+{
+ if (element.getValueType() !=
+ ::getCppuType((const com::sun::star::frame::DispatchStatement *)NULL)) {
+ throw com::sun::star::lang::IllegalArgumentException(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "Illegal argument in dispatch recorder") ),
+ Reference< XInterface >(), 2 );
+ }
+
+ if (idx >= (sal_Int32)m_aStatements.size()) {
+ throw com::sun::star::lang::IndexOutOfBoundsException(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "Dispatch recorder out of bounds") ),
+ Reference< XInterface >() );
+
+ }
+
+ com::sun::star::frame::DispatchStatement *pStatement;
+
+ pStatement = (com::sun::star::frame::DispatchStatement *)element.getValue();
+
+ com::sun::star::frame::DispatchStatement aStatement(
+ pStatement->aCommand,
+ pStatement->aTarget,
+ pStatement->aArgs,
+ pStatement->nFlags,
+ pStatement->bIsComment);
+
+ m_aStatements[idx] = aStatement;
+}
+
+} // namespace framework