fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / framework / source / recording / dispatchrecorder.cxx
blobe49d43f3d61b521adb7582d7072ad8cb4b0667f5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <recording/dispatchrecorder.hxx>
21 #include <com/sun/star/frame/DispatchStatement.hpp>
22 #include <com/sun/star/script/Converter.hpp>
23 #include <services.h>
24 #include <vcl/svapp.hxx>
25 #include <comphelper/processfactory.hxx>
27 using namespace ::com::sun::star::uno;
29 namespace framework{
31 // used to mark a dispatch as comment (mostly it indicates an error) Changing of this wdefine will impact all using of such comments ...
32 #define REM_AS_COMMENT "rem "
34 // XInterface, XTypeProvider, XServiceInfo
36 DEFINE_XSERVICEINFO_MULTISERVICE_2(
37 DispatchRecorder,
38 ::cppu::OWeakObject,
39 "com.sun.star.frame.DispatchRecorder",
40 OUString("com.sun.star.comp.framework.DispatchRecorder"))
42 DEFINE_INIT_SERVICE(
43 DispatchRecorder,
48 #include <typelib/typedescription.h>
50 void flatten_struct_members(
51 ::std::vector< Any > * vec, void const * data,
52 typelib_CompoundTypeDescription * pTD )
54 if (pTD->pBaseTypeDescription)
56 flatten_struct_members( vec, data, pTD->pBaseTypeDescription );
58 for ( sal_Int32 nPos = 0; nPos < pTD->nMembers; ++nPos )
60 vec->push_back(
61 Any( static_cast<char const *>(data) + pTD->pMemberOffsets[ nPos ], pTD->ppTypeRefs[ nPos ] ) );
65 Sequence< Any > make_seq_out_of_struct(
66 Any const & val )
68 Type const & type = val.getValueType();
69 TypeClass eTypeClass = type.getTypeClass();
70 if (TypeClass_STRUCT != eTypeClass && TypeClass_EXCEPTION != eTypeClass)
72 throw RuntimeException(
73 type.getTypeName() + "is no struct or exception!" );
75 typelib_TypeDescription * pTD = 0;
76 TYPELIB_DANGER_GET( &pTD, type.getTypeLibType() );
77 OSL_ASSERT( pTD );
78 if (! pTD)
80 throw RuntimeException(
81 "cannot get type descr of type " + type.getTypeName() );
84 ::std::vector< Any > vec;
85 vec.reserve( reinterpret_cast<typelib_CompoundTypeDescription *>(pTD)->nMembers ); // good guess
86 flatten_struct_members( &vec, val.getValue(), reinterpret_cast<typelib_CompoundTypeDescription *>(pTD) );
87 TYPELIB_DANGER_RELEASE( pTD );
88 return Sequence< Any >( &vec[ 0 ], vec.size() );
91 DispatchRecorder::DispatchRecorder( const css::uno::Reference< css::uno::XComponentContext >& xContext )
92 : m_nRecordingID(0)
93 , m_xConverter(css::script::Converter::create(xContext))
97 DispatchRecorder::~DispatchRecorder()
101 // generate header
102 void SAL_CALL DispatchRecorder::startRecording( const css::uno::Reference< css::frame::XFrame >& ) throw( css::uno::RuntimeException, std::exception )
104 /* SAFE{ */
105 /* } */
108 void SAL_CALL DispatchRecorder::recordDispatch( const css::util::URL& aURL,
109 const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException, std::exception )
111 OUString aTarget;
113 com::sun::star::frame::DispatchStatement aStatement( aURL.Complete, aTarget, lArguments, 0, sal_False );
114 m_aStatements.push_back( aStatement );
117 void SAL_CALL DispatchRecorder::recordDispatchAsComment( const css::util::URL& aURL,
118 const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException, std::exception )
120 OUString aTarget;
122 // last parameter must be set to true -> it's a comment
123 com::sun::star::frame::DispatchStatement aStatement( aURL.Complete, aTarget, lArguments, 0, sal_True );
124 m_aStatements.push_back( aStatement );
127 void SAL_CALL DispatchRecorder::endRecording() throw( css::uno::RuntimeException, std::exception )
129 SolarMutexGuard g;
130 m_aStatements.clear();
133 OUString SAL_CALL DispatchRecorder::getRecordedMacro() throw( css::uno::RuntimeException, std::exception )
135 SolarMutexGuard g;
137 if ( m_aStatements.empty() )
138 return OUString();
140 OUStringBuffer aScriptBuffer;
141 aScriptBuffer.ensureCapacity(10000);
142 m_nRecordingID = 1;
144 aScriptBuffer.appendAscii("rem ----------------------------------------------------------------------\n");
145 aScriptBuffer.appendAscii("rem define variables\n");
146 aScriptBuffer.appendAscii("dim document as object\n");
147 aScriptBuffer.appendAscii("dim dispatcher as object\n");
148 aScriptBuffer.appendAscii("rem ----------------------------------------------------------------------\n");
149 aScriptBuffer.appendAscii("rem get access to the document\n");
150 aScriptBuffer.appendAscii("document = ThisComponent.CurrentController.Frame\n");
151 aScriptBuffer.appendAscii("dispatcher = createUnoService(\"com.sun.star.frame.DispatchHelper\")\n\n");
153 std::vector< com::sun::star::frame::DispatchStatement>::iterator p;
154 for ( p = m_aStatements.begin(); p != m_aStatements.end(); ++p )
155 implts_recordMacro( p->aCommand, p->aArgs, p->bIsComment, aScriptBuffer );
156 OUString sScript = aScriptBuffer.makeStringAndClear();
157 return sScript;
160 void SAL_CALL DispatchRecorder::AppendToBuffer( css::uno::Any aValue, OUStringBuffer& aArgumentBuffer )
162 // if value == bool
163 if (aValue.getValueTypeClass() == css::uno::TypeClass_STRUCT )
165 // structs are recorded as arrays, convert to "Sequence of any"
166 Sequence< Any > aSeq = make_seq_out_of_struct( aValue );
167 aArgumentBuffer.appendAscii("Array(");
168 for ( sal_Int32 nAny=0; nAny<aSeq.getLength(); nAny++ )
170 AppendToBuffer( aSeq[nAny], aArgumentBuffer );
171 if ( nAny+1 < aSeq.getLength() )
172 // not last argument
173 aArgumentBuffer.appendAscii(",");
176 aArgumentBuffer.appendAscii(")");
178 else if (aValue.getValueTypeClass() == css::uno::TypeClass_SEQUENCE )
180 // convert to "Sequence of any"
181 css::uno::Sequence < css::uno::Any > aSeq;
182 css::uno::Any aNew;
183 try { aNew = m_xConverter->convertTo( aValue, cppu::UnoType<css::uno::Sequence < css::uno::Any >>::get() ); }
184 catch (const css::uno::Exception&) {}
186 aNew >>= aSeq;
187 aArgumentBuffer.appendAscii("Array(");
188 for ( sal_Int32 nAny=0; nAny<aSeq.getLength(); nAny++ )
190 AppendToBuffer( aSeq[nAny], aArgumentBuffer );
191 if ( nAny+1 < aSeq.getLength() )
192 // not last argument
193 aArgumentBuffer.appendAscii(",");
196 aArgumentBuffer.appendAscii(")");
198 else if (aValue.getValueTypeClass() == css::uno::TypeClass_STRING )
200 // strings need \"
201 OUString sVal;
202 aValue >>= sVal;
204 // encode non printable characters or '"' by using the CHR$ function
205 if ( !sVal.isEmpty() )
207 const sal_Unicode* pChars = sVal.getStr();
208 bool bInString = false;
209 for ( sal_Int32 nChar=0; nChar<sVal.getLength(); nChar ++ )
211 if ( pChars[nChar] < 32 || pChars[nChar] == '"' )
213 // problematic character detected
214 if ( bInString )
216 // close current string
217 aArgumentBuffer.appendAscii("\"");
218 bInString = false;
221 if ( nChar>0 )
222 // if this is not the first character, parts of the string have already been added
223 aArgumentBuffer.appendAscii("+");
225 // add the character constant
226 aArgumentBuffer.appendAscii("CHR$(");
227 aArgumentBuffer.append( (sal_Int32) pChars[nChar] );
228 aArgumentBuffer.appendAscii(")");
230 else
232 if ( !bInString )
234 if ( nChar>0 )
235 // if this is not the first character, parts of the string have already been added
236 aArgumentBuffer.appendAscii("+");
238 // start a new string
239 aArgumentBuffer.appendAscii("\"");
240 bInString = true;
243 aArgumentBuffer.append( pChars[nChar] );
247 // close string
248 if ( bInString )
249 aArgumentBuffer.appendAscii("\"");
251 else
252 aArgumentBuffer.appendAscii("\"\"");
254 else if (aValue.getValueType() == cppu::UnoType<cppu::UnoCharType>::get())
256 // character variables are recorded as strings, back conversion must be handled in client code
257 sal_Unicode nVal = *static_cast<sal_Unicode const *>(aValue.getValue());
258 aArgumentBuffer.appendAscii("\"");
259 if ( (sal_Unicode(nVal) == '\"') )
260 // encode \" to \"\"
261 aArgumentBuffer.append((sal_Unicode)nVal);
262 aArgumentBuffer.append((sal_Unicode)nVal);
263 aArgumentBuffer.appendAscii("\"");
265 else
267 css::uno::Any aNew;
270 aNew = m_xConverter->convertToSimpleType( aValue, css::uno::TypeClass_STRING );
272 catch (const css::script::CannotConvertException&) {}
273 catch (const css::uno::Exception&) {}
274 OUString sVal;
275 aNew >>= sVal;
277 if (aValue.getValueTypeClass() == css::uno::TypeClass_ENUM )
279 OUString aName = aValue.getValueType().getTypeName();
280 aArgumentBuffer.append( aName );
281 aArgumentBuffer.appendAscii(".");
284 aArgumentBuffer.append(sVal);
288 void SAL_CALL DispatchRecorder::implts_recordMacro( const OUString& aURL,
289 const css::uno::Sequence< css::beans::PropertyValue >& lArguments,
290 bool bAsComment, OUStringBuffer& aScriptBuffer )
292 OUStringBuffer aArgumentBuffer(1000);
293 OUString sArrayName;
294 // this value is used to name the arrays of aArgumentBuffer
295 sArrayName = "args" + OUString::number(m_nRecordingID);
297 aScriptBuffer.appendAscii("rem ----------------------------------------------------------------------\n");
299 sal_Int32 nLength = lArguments.getLength();
300 sal_Int32 nValidArgs = 0;
301 for( sal_Int32 i=0; i<nLength; ++i )
303 if(!lArguments[i].Value.hasValue())
304 continue;
306 OUStringBuffer sValBuffer(100);
309 AppendToBuffer(lArguments[i].Value, sValBuffer);
311 catch(const css::uno::Exception&)
313 sValBuffer.setLength(0);
315 if (sValBuffer.isEmpty())
316 continue;
319 // add arg().Name
320 if(bAsComment)
321 aArgumentBuffer.appendAscii(REM_AS_COMMENT);
322 aArgumentBuffer.append (sArrayName);
323 aArgumentBuffer.appendAscii("(");
324 aArgumentBuffer.append (nValidArgs);
325 aArgumentBuffer.appendAscii(").Name = \"");
326 aArgumentBuffer.append (lArguments[i].Name);
327 aArgumentBuffer.appendAscii("\"\n");
329 // add arg().Value
330 if(bAsComment)
331 aArgumentBuffer.appendAscii(REM_AS_COMMENT);
332 aArgumentBuffer.append (sArrayName);
333 aArgumentBuffer.appendAscii("(");
334 aArgumentBuffer.append (nValidArgs);
335 aArgumentBuffer.appendAscii(").Value = ");
336 aArgumentBuffer.append (sValBuffer.makeStringAndClear());
337 aArgumentBuffer.appendAscii("\n");
339 ++nValidArgs;
343 // if aArgumentBuffer exist - pack it into the aScriptBuffer
344 if(nValidArgs>0)
346 if(bAsComment)
347 aScriptBuffer.appendAscii(REM_AS_COMMENT);
348 aScriptBuffer.appendAscii("dim ");
349 aScriptBuffer.append (sArrayName);
350 aScriptBuffer.appendAscii("(");
351 aScriptBuffer.append ((sal_Int32)(nValidArgs-1)); // 0 based!
352 aScriptBuffer.appendAscii(") as new com.sun.star.beans.PropertyValue\n");
353 aScriptBuffer.append (aArgumentBuffer.makeStringAndClear());
354 aScriptBuffer.appendAscii("\n");
357 // add code for dispatches
358 if(bAsComment)
359 aScriptBuffer.appendAscii(REM_AS_COMMENT);
360 aScriptBuffer.appendAscii("dispatcher.executeDispatch(document, \"");
361 aScriptBuffer.append (aURL);
362 aScriptBuffer.appendAscii("\", \"\", 0, ");
363 if(nValidArgs<1)
364 aScriptBuffer.appendAscii("Array()");
365 else
367 aScriptBuffer.append( sArrayName.getStr() );
368 aScriptBuffer.appendAscii("()");
370 aScriptBuffer.appendAscii(")\n\n");
372 /* SAFE { */
373 m_nRecordingID++;
374 /* } */
377 com::sun::star::uno::Type SAL_CALL DispatchRecorder::getElementType() throw (::com::sun::star::uno::RuntimeException, std::exception)
379 return cppu::UnoType<com::sun::star::frame::DispatchStatement>::get();
382 sal_Bool SAL_CALL DispatchRecorder::hasElements() throw (::com::sun::star::uno::RuntimeException, std::exception)
384 return (! m_aStatements.empty());
387 sal_Int32 SAL_CALL DispatchRecorder::getCount() throw (::com::sun::star::uno::RuntimeException, std::exception)
389 return m_aStatements.size();
392 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, std::exception)
394 if (idx >= (sal_Int32)m_aStatements.size()) {
395 throw com::sun::star::lang::IndexOutOfBoundsException( "Dispatch recorder out of bounds" );
398 Any element(&m_aStatements[idx],
399 cppu::UnoType<com::sun::star::frame::DispatchStatement>::get());
401 return element;
404 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, std::exception)
406 if (element.getValueType() !=
407 cppu::UnoType<com::sun::star::frame::DispatchStatement>::get()) {
408 throw com::sun::star::lang::IllegalArgumentException(
409 "Illegal argument in dispatch recorder",
410 Reference< XInterface >(), 2 );
413 if (idx >= (sal_Int32)m_aStatements.size()) {
414 throw com::sun::star::lang::IndexOutOfBoundsException(
415 "Dispatch recorder out of bounds" );
419 com::sun::star::frame::DispatchStatement const *pStatement;
421 pStatement = static_cast<com::sun::star::frame::DispatchStatement const *>(element.getValue());
423 com::sun::star::frame::DispatchStatement aStatement(
424 pStatement->aCommand,
425 pStatement->aTarget,
426 pStatement->aArgs,
427 pStatement->nFlags,
428 pStatement->bIsComment);
430 m_aStatements[idx] = aStatement;
433 } // namespace framework
435 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */