merged tag ooo/OOO330_m14
[LibreOffice.git] / framework / source / recording / dispatchrecorder.cxx
blob7716fb45e79129c67bbc877185a9e38026b34ebf
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
29 // MARKER(update_precomp.py): autogen include statement, do not remove
30 #include "precompiled_framework.hxx"
31 #include <recording/dispatchrecorder.hxx>
32 #include <com/sun/star/frame/DispatchStatement.hpp>
33 #include <threadhelp/writeguard.hxx>
34 #include <threadhelp/readguard.hxx>
35 #include <services.h>
36 #include <vcl/svapp.hxx>
38 using namespace ::com::sun::star::uno;
40 namespace framework{
42 // used to mark a dispatch as comment (mostly it indicates an error) Changing of this wdefine will impact all using of such comments ...
43 #define REM_AS_COMMENT "rem "
45 //*****************************************************************************************************************
46 // XInterface, XTypeProvider, XServiceInfo
47 //*****************************************************************************************************************
48 DEFINE_XINTERFACE_6(
49 DispatchRecorder,
50 OWeakObject,
51 DIRECT_INTERFACE(css::lang::XTypeProvider),
52 DIRECT_INTERFACE(css::lang::XServiceInfo),
53 DIRECT_INTERFACE(css::frame::XDispatchRecorder),
54 DIRECT_INTERFACE(css::container::XIndexReplace),
55 DIRECT_INTERFACE(css::container::XIndexAccess),
56 DIRECT_INTERFACE(css::container::XElementAccess))
58 DEFINE_XTYPEPROVIDER_6(
59 DispatchRecorder,
60 css::lang::XTypeProvider,
61 css::lang::XServiceInfo,
62 css::frame::XDispatchRecorder,
63 css::container::XIndexReplace,
64 css::container::XIndexAccess,
65 css::container::XElementAccess)
67 DEFINE_XSERVICEINFO_MULTISERVICE(
68 DispatchRecorder,
69 ::cppu::OWeakObject,
70 SERVICENAME_DISPATCHRECORDER,
71 IMPLEMENTATIONNAME_DISPATCHRECORDER)
73 DEFINE_INIT_SERVICE(
74 DispatchRecorder,
79 #include <typelib/typedescription.h>
81 //--------------------------------------------------------------------------------------------------
82 void flatten_struct_members(
83 ::std::vector< Any > * vec, void const * data,
84 typelib_CompoundTypeDescription * pTD )
85 SAL_THROW( () )
87 if (pTD->pBaseTypeDescription)
89 flatten_struct_members( vec, data, pTD->pBaseTypeDescription );
91 for ( sal_Int32 nPos = 0; nPos < pTD->nMembers; ++nPos )
93 vec->push_back(
94 Any( (char const *)data + pTD->pMemberOffsets[ nPos ], pTD->ppTypeRefs[ nPos ] ) );
97 //==================================================================================================
98 Sequence< Any > make_seq_out_of_struct(
99 Any const & val )
100 SAL_THROW( (RuntimeException) )
102 Type const & type = val.getValueType();
103 TypeClass eTypeClass = type.getTypeClass();
104 if (TypeClass_STRUCT != eTypeClass && TypeClass_EXCEPTION != eTypeClass)
106 throw RuntimeException(
107 type.getTypeName() +
108 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("is no struct or exception!") ),
109 Reference< XInterface >() );
111 typelib_TypeDescription * pTD = 0;
112 TYPELIB_DANGER_GET( &pTD, type.getTypeLibType() );
113 OSL_ASSERT( pTD );
114 if (! pTD)
116 throw RuntimeException(
117 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get type descr of type ") ) +
118 type.getTypeName(),
119 Reference< XInterface >() );
122 ::std::vector< Any > vec;
123 vec.reserve( ((typelib_CompoundTypeDescription *)pTD)->nMembers ); // good guess
124 flatten_struct_members( &vec, val.getValue(), (typelib_CompoundTypeDescription *)pTD );
125 TYPELIB_DANGER_RELEASE( pTD );
126 return Sequence< Any >( &vec[ 0 ], vec.size() );
129 //***********************************************************************
130 DispatchRecorder::DispatchRecorder( const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
131 : ThreadHelpBase ( &Application::GetSolarMutex() )
132 , ::cppu::OWeakObject( )
133 , m_xSMGR ( xSMGR )
134 , m_xConverter( m_xSMGR->createInstance(::rtl::OUString::createFromAscii("com.sun.star.script.Converter")), css::uno::UNO_QUERY )
138 //************************************************************************
139 DispatchRecorder::~DispatchRecorder()
143 //*************************************************************************
144 // generate header
145 void SAL_CALL DispatchRecorder::startRecording( const css::uno::Reference< css::frame::XFrame >& ) throw( css::uno::RuntimeException )
147 /* SAFE{ */
148 /* } */
151 //*************************************************************************
152 void SAL_CALL DispatchRecorder::recordDispatch( const css::util::URL& aURL,
153 const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException )
155 ::rtl::OUString aTarget;
157 com::sun::star::frame::DispatchStatement aStatement( aURL.Complete, aTarget, lArguments, 0, sal_False );
158 m_aStatements.push_back( aStatement );
161 //*************************************************************************
162 void SAL_CALL DispatchRecorder::recordDispatchAsComment( const css::util::URL& aURL,
163 const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException )
165 ::rtl::OUString aTarget;
167 // last parameter must be set to true -> it's a comment
168 com::sun::star::frame::DispatchStatement aStatement( aURL.Complete, aTarget, lArguments, 0, sal_True );
169 m_aStatements.push_back( aStatement );
172 //*************************************************************************
173 void SAL_CALL DispatchRecorder::endRecording() throw( css::uno::RuntimeException )
175 /* SAFE{ */
176 WriteGuard aWriteLock(m_aLock);
177 m_aStatements.clear();
178 /* } */
181 //*************************************************************************
182 ::rtl::OUString SAL_CALL DispatchRecorder::getRecordedMacro() throw( css::uno::RuntimeException )
184 /* SAFE{ */
185 WriteGuard aWriteLock(m_aLock);
187 if ( m_aStatements.empty() )
188 return ::rtl::OUString();
190 ::rtl::OUStringBuffer aScriptBuffer;
191 aScriptBuffer.ensureCapacity(10000);
192 m_nRecordingID = 1;
194 aScriptBuffer.appendAscii("rem ----------------------------------------------------------------------\n");
195 aScriptBuffer.appendAscii("rem define variables\n");
196 aScriptBuffer.appendAscii("dim document as object\n");
197 aScriptBuffer.appendAscii("dim dispatcher as object\n");
198 aScriptBuffer.appendAscii("rem ----------------------------------------------------------------------\n");
199 aScriptBuffer.appendAscii("rem get access to the document\n");
200 aScriptBuffer.appendAscii("document = ThisComponent.CurrentController.Frame\n");
201 aScriptBuffer.appendAscii("dispatcher = createUnoService(\"com.sun.star.frame.DispatchHelper\")\n\n");
203 std::vector< com::sun::star::frame::DispatchStatement>::iterator p;
204 for ( p = m_aStatements.begin(); p != m_aStatements.end(); p++ )
205 implts_recordMacro( p->aCommand, p->aArgs, p->bIsComment, aScriptBuffer );
206 ::rtl::OUString sScript = aScriptBuffer.makeStringAndClear();
207 return sScript;
208 /* } */
211 //*************************************************************************
212 void SAL_CALL DispatchRecorder::AppendToBuffer( css::uno::Any aValue, ::rtl::OUStringBuffer& aArgumentBuffer )
214 // if value == bool
215 if (aValue.getValueTypeClass() == css::uno::TypeClass_STRUCT )
217 // structs are recorded as arrays, convert to "Sequence of any"
218 Sequence< Any > aSeq = make_seq_out_of_struct( aValue );
219 aArgumentBuffer.appendAscii("Array(");
220 for ( sal_Int32 nAny=0; nAny<aSeq.getLength(); nAny++ )
222 AppendToBuffer( aSeq[nAny], aArgumentBuffer );
223 if ( nAny+1 < aSeq.getLength() )
224 // not last argument
225 aArgumentBuffer.appendAscii(",");
228 aArgumentBuffer.appendAscii(")");
230 else if (aValue.getValueTypeClass() == css::uno::TypeClass_SEQUENCE )
232 // convert to "Sequence of any"
233 css::uno::Sequence < css::uno::Any > aSeq;
234 css::uno::Any aNew;
235 try { aNew = m_xConverter->convertTo( aValue, ::getCppuType((const css::uno::Sequence < css::uno::Any >*)0) ); }
236 catch (css::uno::Exception&) {}
238 aNew >>= aSeq;
239 aArgumentBuffer.appendAscii("Array(");
240 for ( sal_Int32 nAny=0; nAny<aSeq.getLength(); nAny++ )
242 AppendToBuffer( aSeq[nAny], aArgumentBuffer );
243 if ( nAny+1 < aSeq.getLength() )
244 // not last argument
245 aArgumentBuffer.appendAscii(",");
248 aArgumentBuffer.appendAscii(")");
250 else if (aValue.getValueTypeClass() == css::uno::TypeClass_STRING )
252 // strings need \"
253 ::rtl::OUString sVal;
254 aValue >>= sVal;
256 // encode non printable characters or '"' by using the CHR$ function
257 if ( sVal.getLength() )
259 const sal_Unicode* pChars = sVal.getStr();
260 sal_Bool bInString = sal_False;
261 for ( sal_Int32 nChar=0; nChar<sVal.getLength(); nChar ++ )
263 if ( pChars[nChar] < 32 || pChars[nChar] == '"' )
265 // problematic character detected
266 if ( bInString )
268 // close current string
269 aArgumentBuffer.appendAscii("\"");
270 bInString = sal_False;
273 if ( nChar>0 )
274 // if this is not the first character, parts of the string have already been added
275 aArgumentBuffer.appendAscii("+");
277 // add the character constant
278 aArgumentBuffer.appendAscii("CHR$(");
279 aArgumentBuffer.append( (sal_Int32) pChars[nChar] );
280 aArgumentBuffer.appendAscii(")");
282 else
284 if ( !bInString )
286 if ( nChar>0 )
287 // if this is not the first character, parts of the string have already been added
288 aArgumentBuffer.appendAscii("+");
290 // start a new string
291 aArgumentBuffer.appendAscii("\"");
292 bInString = sal_True;
295 aArgumentBuffer.append( pChars[nChar] );
299 // close string
300 if ( bInString )
301 aArgumentBuffer.appendAscii("\"");
303 else
304 aArgumentBuffer.appendAscii("\"\"");
306 else if (aValue.getValueType() == getCppuCharType())
308 // character variables are recorded as strings, back conversion must be handled in client code
309 sal_Unicode nVal = *((sal_Unicode*)aValue.getValue());
310 aArgumentBuffer.appendAscii("\"");
311 if ( (sal_Unicode(nVal) == '\"') )
312 // encode \" to \"\"
313 aArgumentBuffer.append((sal_Unicode)nVal);
314 aArgumentBuffer.append((sal_Unicode)nVal);
315 aArgumentBuffer.appendAscii("\"");
317 else
319 css::uno::Any aNew;
322 aNew = m_xConverter->convertToSimpleType( aValue, css::uno::TypeClass_STRING );
324 catch (css::script::CannotConvertException&) {}
325 catch (css::uno::Exception&) {}
326 ::rtl::OUString sVal;
327 aNew >>= sVal;
329 if (aValue.getValueTypeClass() == css::uno::TypeClass_ENUM )
331 ::rtl::OUString aName = aValue.getValueType().getTypeName();
332 aArgumentBuffer.append( aName );
333 aArgumentBuffer.appendAscii(".");
336 aArgumentBuffer.append(sVal);
340 void SAL_CALL DispatchRecorder::implts_recordMacro( const ::rtl::OUString& aURL,
341 const css::uno::Sequence< css::beans::PropertyValue >& lArguments,
342 sal_Bool bAsComment, ::rtl::OUStringBuffer& aScriptBuffer )
344 ::rtl::OUStringBuffer aArgumentBuffer(1000);
345 ::rtl::OUString sArrayName;
346 // this value is used to name the arrays of aArgumentBuffer
347 sArrayName = ::rtl::OUString::createFromAscii("args");
348 sArrayName += ::rtl::OUString::valueOf((sal_Int32)m_nRecordingID);
350 aScriptBuffer.appendAscii("rem ----------------------------------------------------------------------\n");
352 sal_Int32 nLength = lArguments.getLength();
353 sal_Int32 nValidArgs = 0;
354 for( sal_Int32 i=0; i<nLength; ++i )
356 if(!lArguments[i].Value.hasValue())
357 continue;
359 ::rtl::OUStringBuffer sValBuffer(100);
362 AppendToBuffer(lArguments[i].Value, sValBuffer);
364 catch(const css::uno::Exception&)
366 sValBuffer.setLength(0);
368 if (!sValBuffer.getLength())
369 continue;
372 // add arg().Name
373 if(bAsComment)
374 aArgumentBuffer.appendAscii(REM_AS_COMMENT);
375 aArgumentBuffer.append (sArrayName);
376 aArgumentBuffer.appendAscii("(");
377 aArgumentBuffer.append (nValidArgs);
378 aArgumentBuffer.appendAscii(").Name = \"");
379 aArgumentBuffer.append (lArguments[i].Name);
380 aArgumentBuffer.appendAscii("\"\n");
382 // add arg().Value
383 if(bAsComment)
384 aArgumentBuffer.appendAscii(REM_AS_COMMENT);
385 aArgumentBuffer.append (sArrayName);
386 aArgumentBuffer.appendAscii("(");
387 aArgumentBuffer.append (nValidArgs);
388 aArgumentBuffer.appendAscii(").Value = ");
389 aArgumentBuffer.append (sValBuffer.makeStringAndClear());
390 aArgumentBuffer.appendAscii("\n");
392 ++nValidArgs;
396 // if aArgumentBuffer exist - pack it into the aScriptBuffer
397 if(nValidArgs>0)
399 if(bAsComment)
400 aScriptBuffer.appendAscii(REM_AS_COMMENT);
401 aScriptBuffer.appendAscii("dim ");
402 aScriptBuffer.append (sArrayName);
403 aScriptBuffer.appendAscii("(");
404 aScriptBuffer.append ((sal_Int32)(nValidArgs-1)); // 0 based!
405 aScriptBuffer.appendAscii(") as new com.sun.star.beans.PropertyValue\n");
406 aScriptBuffer.append (aArgumentBuffer.makeStringAndClear());
407 aScriptBuffer.appendAscii("\n");
410 // add code for dispatches
411 if(bAsComment)
412 aScriptBuffer.appendAscii(REM_AS_COMMENT);
413 aScriptBuffer.appendAscii("dispatcher.executeDispatch(document, \"");
414 aScriptBuffer.append (aURL);
415 aScriptBuffer.appendAscii("\", \"\", 0, ");
416 if(nValidArgs<1)
417 aScriptBuffer.appendAscii("Array()");
418 else
420 aScriptBuffer.append( sArrayName.getStr() );
421 aScriptBuffer.appendAscii("()");
423 aScriptBuffer.appendAscii(")\n\n");
425 /* SAFE { */
426 m_nRecordingID++;
427 /* } */
430 com::sun::star::uno::Type SAL_CALL DispatchRecorder::getElementType() throw (::com::sun::star::uno::RuntimeException)
432 return ::getCppuType((const com::sun::star::frame::DispatchStatement *)NULL);
435 sal_Bool SAL_CALL DispatchRecorder::hasElements() throw (::com::sun::star::uno::RuntimeException)
437 return (! m_aStatements.empty());
440 sal_Int32 SAL_CALL DispatchRecorder::getCount() throw (::com::sun::star::uno::RuntimeException)
442 return m_aStatements.size();
445 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)
447 if (idx >= (sal_Int32)m_aStatements.size()) {
448 throw com::sun::star::lang::IndexOutOfBoundsException(
449 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
450 "Dispatch recorder out of bounds") ),
451 Reference< XInterface >() );
455 Any element(&m_aStatements[idx],
456 ::getCppuType((const com::sun::star::frame::DispatchStatement *)NULL));
458 return element;
461 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)
463 if (element.getValueType() !=
464 ::getCppuType((const com::sun::star::frame::DispatchStatement *)NULL)) {
465 throw com::sun::star::lang::IllegalArgumentException(
466 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
467 "Illegal argument in dispatch recorder") ),
468 Reference< XInterface >(), 2 );
471 if (idx >= (sal_Int32)m_aStatements.size()) {
472 throw com::sun::star::lang::IndexOutOfBoundsException(
473 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
474 "Dispatch recorder out of bounds") ),
475 Reference< XInterface >() );
479 com::sun::star::frame::DispatchStatement *pStatement;
481 pStatement = (com::sun::star::frame::DispatchStatement *)element.getValue();
483 com::sun::star::frame::DispatchStatement aStatement(
484 pStatement->aCommand,
485 pStatement->aTarget,
486 pStatement->aArgs,
487 pStatement->nFlags,
488 pStatement->bIsComment);
490 m_aStatements[idx] = aStatement;
493 } // namespace framework