update dev300-m58
[ooovba.git] / framework / source / recording / dispatchrecorder.cxx
blob9ad3f696d69bad711949321af520cf75b2f8f222
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dispatchrecorder.cxx,v $
10 * $Revision: 1.22 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_framework.hxx"
34 #include <recording/dispatchrecorder.hxx>
35 #include <com/sun/star/frame/DispatchStatement.hpp>
36 #include <threadhelp/writeguard.hxx>
37 #include <threadhelp/readguard.hxx>
38 #include <services.h>
39 #include <vcl/svapp.hxx>
41 using namespace ::com::sun::star::uno;
43 namespace framework{
45 // used to mark a dispatch as comment (mostly it indicates an error) Changing of this wdefine will impact all using of such comments ...
46 #define REM_AS_COMMENT "rem "
48 //*****************************************************************************************************************
49 // XInterface, XTypeProvider, XServiceInfo
50 //*****************************************************************************************************************
51 DEFINE_XINTERFACE_6(
52 DispatchRecorder,
53 OWeakObject,
54 DIRECT_INTERFACE(css::lang::XTypeProvider),
55 DIRECT_INTERFACE(css::lang::XServiceInfo),
56 DIRECT_INTERFACE(css::frame::XDispatchRecorder),
57 DIRECT_INTERFACE(css::container::XIndexReplace),
58 DIRECT_INTERFACE(css::container::XIndexAccess),
59 DIRECT_INTERFACE(css::container::XElementAccess))
61 DEFINE_XTYPEPROVIDER_6(
62 DispatchRecorder,
63 css::lang::XTypeProvider,
64 css::lang::XServiceInfo,
65 css::frame::XDispatchRecorder,
66 css::container::XIndexReplace,
67 css::container::XIndexAccess,
68 css::container::XElementAccess)
70 DEFINE_XSERVICEINFO_MULTISERVICE(
71 DispatchRecorder,
72 ::cppu::OWeakObject,
73 SERVICENAME_DISPATCHRECORDER,
74 IMPLEMENTATIONNAME_DISPATCHRECORDER)
76 DEFINE_INIT_SERVICE(
77 DispatchRecorder,
82 #include <typelib/typedescription.h>
84 //--------------------------------------------------------------------------------------------------
85 void flatten_struct_members(
86 ::std::vector< Any > * vec, void const * data,
87 typelib_CompoundTypeDescription * pTD )
88 SAL_THROW( () )
90 if (pTD->pBaseTypeDescription)
92 flatten_struct_members( vec, data, pTD->pBaseTypeDescription );
94 for ( sal_Int32 nPos = 0; nPos < pTD->nMembers; ++nPos )
96 vec->push_back(
97 Any( (char const *)data + pTD->pMemberOffsets[ nPos ], pTD->ppTypeRefs[ nPos ] ) );
100 //==================================================================================================
101 Sequence< Any > make_seq_out_of_struct(
102 Any const & val )
103 SAL_THROW( (RuntimeException) )
105 Type const & type = val.getValueType();
106 TypeClass eTypeClass = type.getTypeClass();
107 if (TypeClass_STRUCT != eTypeClass && TypeClass_EXCEPTION != eTypeClass)
109 throw RuntimeException(
110 type.getTypeName() +
111 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("is no struct or exception!") ),
112 Reference< XInterface >() );
114 typelib_TypeDescription * pTD = 0;
115 TYPELIB_DANGER_GET( &pTD, type.getTypeLibType() );
116 OSL_ASSERT( pTD );
117 if (! pTD)
119 throw RuntimeException(
120 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get type descr of type ") ) +
121 type.getTypeName(),
122 Reference< XInterface >() );
125 ::std::vector< Any > vec;
126 vec.reserve( ((typelib_CompoundTypeDescription *)pTD)->nMembers ); // good guess
127 flatten_struct_members( &vec, val.getValue(), (typelib_CompoundTypeDescription *)pTD );
128 TYPELIB_DANGER_RELEASE( pTD );
129 return Sequence< Any >( &vec[ 0 ], vec.size() );
132 //***********************************************************************
133 DispatchRecorder::DispatchRecorder( const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
134 : ThreadHelpBase ( &Application::GetSolarMutex() )
135 , ::cppu::OWeakObject( )
136 , m_xSMGR ( xSMGR )
137 , m_xConverter( m_xSMGR->createInstance(::rtl::OUString::createFromAscii("com.sun.star.script.Converter")), css::uno::UNO_QUERY )
141 //************************************************************************
142 DispatchRecorder::~DispatchRecorder()
146 //*************************************************************************
147 // generate header
148 void SAL_CALL DispatchRecorder::startRecording( const css::uno::Reference< css::frame::XFrame >& ) throw( css::uno::RuntimeException )
150 /* SAFE{ */
151 /* } */
154 //*************************************************************************
155 void SAL_CALL DispatchRecorder::recordDispatch( const css::util::URL& aURL,
156 const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException )
158 ::rtl::OUString aTarget;
160 com::sun::star::frame::DispatchStatement aStatement( aURL.Complete, aTarget, lArguments, 0, sal_False );
161 m_aStatements.push_back( aStatement );
164 //*************************************************************************
165 void SAL_CALL DispatchRecorder::recordDispatchAsComment( const css::util::URL& aURL,
166 const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException )
168 ::rtl::OUString aTarget;
170 // last parameter must be set to true -> it's a comment
171 com::sun::star::frame::DispatchStatement aStatement( aURL.Complete, aTarget, lArguments, 0, sal_True );
172 m_aStatements.push_back( aStatement );
175 //*************************************************************************
176 void SAL_CALL DispatchRecorder::endRecording() throw( css::uno::RuntimeException )
178 /* SAFE{ */
179 WriteGuard aWriteLock(m_aLock);
180 m_aStatements.clear();
181 /* } */
184 //*************************************************************************
185 ::rtl::OUString SAL_CALL DispatchRecorder::getRecordedMacro() throw( css::uno::RuntimeException )
187 /* SAFE{ */
188 WriteGuard aWriteLock(m_aLock);
190 if ( m_aStatements.empty() )
191 return ::rtl::OUString();
193 ::rtl::OUStringBuffer aScriptBuffer;
194 aScriptBuffer.ensureCapacity(10000);
195 m_nRecordingID = 1;
197 aScriptBuffer.appendAscii("rem ----------------------------------------------------------------------\n");
198 aScriptBuffer.appendAscii("rem define variables\n");
199 aScriptBuffer.appendAscii("dim document as object\n");
200 aScriptBuffer.appendAscii("dim dispatcher as object\n");
201 aScriptBuffer.appendAscii("rem ----------------------------------------------------------------------\n");
202 aScriptBuffer.appendAscii("rem get access to the document\n");
203 aScriptBuffer.appendAscii("document = ThisComponent.CurrentController.Frame\n");
204 aScriptBuffer.appendAscii("dispatcher = createUnoService(\"com.sun.star.frame.DispatchHelper\")\n\n");
206 std::vector< com::sun::star::frame::DispatchStatement>::iterator p;
207 for ( p = m_aStatements.begin(); p != m_aStatements.end(); p++ )
208 implts_recordMacro( p->aCommand, p->aArgs, p->bIsComment, aScriptBuffer );
209 ::rtl::OUString sScript = aScriptBuffer.makeStringAndClear();
210 return sScript;
211 /* } */
214 //*************************************************************************
215 void SAL_CALL DispatchRecorder::AppendToBuffer( css::uno::Any aValue, ::rtl::OUStringBuffer& aArgumentBuffer )
217 // if value == bool
218 if (aValue.getValueTypeClass() == css::uno::TypeClass_STRUCT )
220 // structs are recorded as arrays, convert to "Sequence of any"
221 Sequence< Any > aSeq = make_seq_out_of_struct( aValue );
222 aArgumentBuffer.appendAscii("Array(");
223 for ( sal_Int32 nAny=0; nAny<aSeq.getLength(); nAny++ )
225 AppendToBuffer( aSeq[nAny], aArgumentBuffer );
226 if ( nAny+1 < aSeq.getLength() )
227 // not last argument
228 aArgumentBuffer.appendAscii(",");
231 aArgumentBuffer.appendAscii(")");
233 else if (aValue.getValueTypeClass() == css::uno::TypeClass_SEQUENCE )
235 // convert to "Sequence of any"
236 css::uno::Sequence < css::uno::Any > aSeq;
237 css::uno::Any aNew;
238 try { aNew = m_xConverter->convertTo( aValue, ::getCppuType((const css::uno::Sequence < css::uno::Any >*)0) ); }
239 catch (css::uno::Exception&) {}
241 aNew >>= aSeq;
242 aArgumentBuffer.appendAscii("Array(");
243 for ( sal_Int32 nAny=0; nAny<aSeq.getLength(); nAny++ )
245 AppendToBuffer( aSeq[nAny], aArgumentBuffer );
246 if ( nAny+1 < aSeq.getLength() )
247 // not last argument
248 aArgumentBuffer.appendAscii(",");
251 aArgumentBuffer.appendAscii(")");
253 else if (aValue.getValueTypeClass() == css::uno::TypeClass_STRING )
255 // strings need \"
256 ::rtl::OUString sVal;
257 aValue >>= sVal;
259 // encode non printable characters or '"' by using the CHR$ function
260 if ( sVal.getLength() )
262 const sal_Unicode* pChars = sVal.getStr();
263 sal_Bool bInString = sal_False;
264 for ( sal_Int32 nChar=0; nChar<sVal.getLength(); nChar ++ )
266 if ( pChars[nChar] < 32 || pChars[nChar] == '"' )
268 // problematic character detected
269 if ( bInString )
271 // close current string
272 aArgumentBuffer.appendAscii("\"");
273 bInString = sal_False;
276 if ( nChar>0 )
277 // if this is not the first character, parts of the string have already been added
278 aArgumentBuffer.appendAscii("+");
280 // add the character constant
281 aArgumentBuffer.appendAscii("CHR$(");
282 aArgumentBuffer.append( (sal_Int32) pChars[nChar] );
283 aArgumentBuffer.appendAscii(")");
285 else
287 if ( !bInString )
289 if ( nChar>0 )
290 // if this is not the first character, parts of the string have already been added
291 aArgumentBuffer.appendAscii("+");
293 // start a new string
294 aArgumentBuffer.appendAscii("\"");
295 bInString = sal_True;
298 aArgumentBuffer.append( pChars[nChar] );
302 // close string
303 if ( bInString )
304 aArgumentBuffer.appendAscii("\"");
306 else
307 aArgumentBuffer.appendAscii("\"\"");
309 else if (aValue.getValueType() == getCppuCharType())
311 // character variables are recorded as strings, back conversion must be handled in client code
312 sal_Unicode nVal = *((sal_Unicode*)aValue.getValue());
313 aArgumentBuffer.appendAscii("\"");
314 if ( (sal_Unicode(nVal) == '\"') )
315 // encode \" to \"\"
316 aArgumentBuffer.append((sal_Unicode)nVal);
317 aArgumentBuffer.append((sal_Unicode)nVal);
318 aArgumentBuffer.appendAscii("\"");
320 else
322 css::uno::Any aNew;
325 aNew = m_xConverter->convertToSimpleType( aValue, css::uno::TypeClass_STRING );
327 catch (css::script::CannotConvertException&) {}
328 catch (css::uno::Exception&) {}
329 ::rtl::OUString sVal;
330 aNew >>= sVal;
332 if (aValue.getValueTypeClass() == css::uno::TypeClass_ENUM )
334 ::rtl::OUString aName = aValue.getValueType().getTypeName();
335 aArgumentBuffer.append( aName );
336 aArgumentBuffer.appendAscii(".");
339 aArgumentBuffer.append(sVal);
343 void SAL_CALL DispatchRecorder::implts_recordMacro( const ::rtl::OUString& aURL,
344 const css::uno::Sequence< css::beans::PropertyValue >& lArguments,
345 sal_Bool bAsComment, ::rtl::OUStringBuffer& aScriptBuffer )
347 ::rtl::OUStringBuffer aArgumentBuffer(1000);
348 ::rtl::OUString sArrayName;
349 // this value is used to name the arrays of aArgumentBuffer
350 sArrayName = ::rtl::OUString::createFromAscii("args");
351 sArrayName += ::rtl::OUString::valueOf((sal_Int32)m_nRecordingID);
353 aScriptBuffer.appendAscii("rem ----------------------------------------------------------------------\n");
355 sal_Int32 nLength = lArguments.getLength();
356 sal_Int32 nValidArgs = 0;
357 for( sal_Int32 i=0; i<nLength; ++i )
359 if(!lArguments[i].Value.hasValue())
360 continue;
362 ::rtl::OUStringBuffer sValBuffer(100);
365 AppendToBuffer(lArguments[i].Value, sValBuffer);
367 catch(const css::uno::Exception&)
369 sValBuffer.setLength(0);
371 if (!sValBuffer.getLength())
372 continue;
375 // add arg().Name
376 if(bAsComment)
377 aArgumentBuffer.appendAscii(REM_AS_COMMENT);
378 aArgumentBuffer.append (sArrayName);
379 aArgumentBuffer.appendAscii("(");
380 aArgumentBuffer.append (nValidArgs);
381 aArgumentBuffer.appendAscii(").Name = \"");
382 aArgumentBuffer.append (lArguments[i].Name);
383 aArgumentBuffer.appendAscii("\"\n");
385 // add arg().Value
386 if(bAsComment)
387 aArgumentBuffer.appendAscii(REM_AS_COMMENT);
388 aArgumentBuffer.append (sArrayName);
389 aArgumentBuffer.appendAscii("(");
390 aArgumentBuffer.append (nValidArgs);
391 aArgumentBuffer.appendAscii(").Value = ");
392 aArgumentBuffer.append (sValBuffer.makeStringAndClear());
393 aArgumentBuffer.appendAscii("\n");
395 ++nValidArgs;
399 // if aArgumentBuffer exist - pack it into the aScriptBuffer
400 if(nValidArgs>0)
402 if(bAsComment)
403 aScriptBuffer.appendAscii(REM_AS_COMMENT);
404 aScriptBuffer.appendAscii("dim ");
405 aScriptBuffer.append (sArrayName);
406 aScriptBuffer.appendAscii("(");
407 aScriptBuffer.append ((sal_Int32)(nValidArgs-1)); // 0 based!
408 aScriptBuffer.appendAscii(") as new com.sun.star.beans.PropertyValue\n");
409 aScriptBuffer.append (aArgumentBuffer.makeStringAndClear());
410 aScriptBuffer.appendAscii("\n");
413 // add code for dispatches
414 if(bAsComment)
415 aScriptBuffer.appendAscii(REM_AS_COMMENT);
416 aScriptBuffer.appendAscii("dispatcher.executeDispatch(document, \"");
417 aScriptBuffer.append (aURL);
418 aScriptBuffer.appendAscii("\", \"\", 0, ");
419 if(nValidArgs<1)
420 aScriptBuffer.appendAscii("Array()");
421 else
423 aScriptBuffer.append( sArrayName.getStr() );
424 aScriptBuffer.appendAscii("()");
426 aScriptBuffer.appendAscii(")\n\n");
428 /* SAFE { */
429 m_nRecordingID++;
430 /* } */
433 com::sun::star::uno::Type SAL_CALL DispatchRecorder::getElementType() throw (::com::sun::star::uno::RuntimeException)
435 return ::getCppuType((const com::sun::star::frame::DispatchStatement *)NULL);
438 sal_Bool SAL_CALL DispatchRecorder::hasElements() throw (::com::sun::star::uno::RuntimeException)
440 return (! m_aStatements.empty());
443 sal_Int32 SAL_CALL DispatchRecorder::getCount() throw (::com::sun::star::uno::RuntimeException)
445 return m_aStatements.size();
448 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)
450 if (idx >= (sal_Int32)m_aStatements.size()) {
451 throw com::sun::star::lang::IndexOutOfBoundsException(
452 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
453 "Dispatch recorder out of bounds") ),
454 Reference< XInterface >() );
458 Any element(&m_aStatements[idx],
459 ::getCppuType((const com::sun::star::frame::DispatchStatement *)NULL));
461 return element;
464 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)
466 if (element.getValueType() !=
467 ::getCppuType((const com::sun::star::frame::DispatchStatement *)NULL)) {
468 throw com::sun::star::lang::IllegalArgumentException(
469 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
470 "Illegal argument in dispatch recorder") ),
471 Reference< XInterface >(), 2 );
474 if (idx >= (sal_Int32)m_aStatements.size()) {
475 throw com::sun::star::lang::IndexOutOfBoundsException(
476 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
477 "Dispatch recorder out of bounds") ),
478 Reference< XInterface >() );
482 com::sun::star::frame::DispatchStatement *pStatement;
484 pStatement = (com::sun::star::frame::DispatchStatement *)element.getValue();
486 com::sun::star::frame::DispatchStatement aStatement(
487 pStatement->aCommand,
488 pStatement->aTarget,
489 pStatement->aArgs,
490 pStatement->nFlags,
491 pStatement->bIsComment);
493 m_aStatements[idx] = aStatement;
496 } // namespace framework