1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: macro.cxx,v $
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 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sfx2.hxx"
34 #if OSL_DEBUG_LEVEL > 1
35 #include <tools/stream.hxx>
39 #include <sfx2/request.hxx>
40 #include <sfx2/msg.hxx>
42 //====================================================================
44 SV_DECL_PTRARR_DEL( SfxStatements_Impl
, SfxMacroStatement
*, 16, 8 )
45 SV_IMPL_PTRARR( SfxStatements_Impl
, SfxMacroStatement
* );
47 //--------------------------------------------------------------------
53 Implementations-Struktur der Klasse <SfxMacro>.
57 SfxMacroMode eMode
; /* Zweck der <SfxMacro>-Instanz,
58 Bedeutung siehe enum <SfxMacroMode> */
59 SfxStatements_Impl aList
; /* Liste von aufgezeichneten Statements */
62 //====================================================================
64 SfxMacroStatement::SfxMacroStatement
66 const SfxShell
& /*rShell*/, // <SfxShell>, die den Request ausf"uhrte
67 const String
& /*rTarget*/, // Name des Zielobjektes vor der Ausf"urhung
68 BOOL
/*bAbsolute*/, // obsolet
69 const SfxSlot
& rSlot
, // der <SfxSlot>, der das Statement abspielen kann
70 BOOL bRequestDone
, // wurde der Request tats"achlich ausgef"uhrt
71 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& rArgs
76 Dieser Konstruktor der Klasse SfxMacroStatement erzeugt ein Statement,
77 bei dem ein Objekt angesprochen wird, welches durch 'rShell' angegeben
78 ist. Dabei erfolgt die Addressierung je nach 'bAbsolute' absolut,
79 also z.B. als '[mydoc.sdc]' oder relativ, also z.B. 'ActiveDocument'.
81 Je nach Art der Subklasse von 'rShell' ergeben sich folgende
85 -----------------------------------------------------------------------
86 SfxApplication' | 'StarCalc' 'Application'
87 SfxViewFrame' | '[mydoc.sdc:1]' 'ActiveWindow'
88 SfxViewShell' | '[mydoc.sdc:1]' 'AvtiveWindow'
89 SfxObjectShell' | '[mydoc.sdc]' 'ActiveDocument'
90 sonstige (Sub-Shells) | '[mydoc.sdc:1]' 'ActiveWindow'
92 Dabei sind 'StarCalc' stellvertretend fuer den Namen der Applikation
93 (Application::GetAppName()const). In der absoluten Fassung k"onnte
94 die Selektion auch deskriptiv z.B. als 'CellSelection("A5-D8")')
95 angesprochen werden, dazu mu\ jedoch vom Anwendungsprogrammierer der
96 Konstruktor <SfxMacroStatement::SfxMacroStatement(const String&,
97 const SfxSlot&,BOOL,SfxArguments*)> verwendet werden.
99 F"ur das so bezeichnete Objekt wird dann je nach Typ des Slots
100 eine Zuweisung an eines seiner Properties oder der Aufruf einer seiner
101 Methoden ausgedr"uckt.
107 SCalc3.OpenDocument( "\docs\mydoc.sdd", "StarDraw Presentation", 0, 0 )
108 [mydoc.sdd].Activate()
109 [mydoc.sdd:1].SwitchToView( 2 )
110 [mydoc.sdc:1:1].CellSelection( "A5-D8" ).LineColor = 192357
113 ActiveWindow.LineColor = 192357
118 <SfxMacroStatement::SfxMacroStatement(const String&,const SfxSlot&,BOOL,SfxArguments*)>
119 <SfxMacroStatement::SfxMacroStatement(const String&)>
122 : nSlotId( rSlot
.GetSlotId() ),
124 bDone( bRequestDone
),
127 // Workaround Recording nicht exportierter Slots (#25386#)
131 // Objekt-Typ bestimmen
132 FASTBOOL bIsApp = rShell.ISA(SfxApplication);
133 FASTBOOL bIsDoc = rShell.ISA(SfxObjectShell);
134 FASTBOOL bIsWin = !bIsApp && !bIsDoc &&
135 ( rShell.ISA(SfxViewShell) || rShell.ISA(SfxViewFrame) );
136 FASTBOOL bIsSel = !bIsApp && !bIsDoc && !bIsWin;
138 // Objekt nicht schon im Slot-Namen enthalten?
139 if ( bIsSel || rSlot.pName[0] == '.' )
141 // absolutes Aufzeichnen?
142 if ( rSlot.IsMode( SFX_SLOT_RECORDABSOLUTE ) )
144 // an der Applikation oder am Modul
145 if ( rShell.ISA(SfxApplication) || rShell.ISA(SfxModule) )
146 aStatement = rTarget;
151 else if ( rShell.ISA(SfxObjectShell) )
154 aStatement += rTarget;
155 aStatement += 0x005D;
158 else if ( rShell.ISA(SfxViewFrame) )
161 aStatement += String::CreateFromAscii("ViewFrame");//rShell.GetSbxObject()->GetName();
162 aStatement += 0x005D;
167 // an der View oder Sub-Shell
168 SfxViewShell *pViewShell = rShell.GetViewShell();
170 aStatement += String::CreateFromAscii("ViewShell");//pViewShell->GetViewFrame()->GetSbxObject()->GetName();
171 aStatement += 0x005D;
172 if ( !rShell.ISA(SfxViewFrame) )
173 // an einer Sub-Shell zus"atlich ".Selection" anh"angen
174 aStatement += DEFINE_CONST_UNICODE(".Selection");
177 else // relatives Aufzeichnen
179 // an der Application?
180 if ( rShell.ISA(SfxApplication) )
181 aStatement = DEFINE_CONST_UNICODE("Application");
184 else if ( rShell.ISA(SfxModule) )
185 aStatement = DEFINE_CONST_UNICODE("ActiveModule");
188 else if ( rShell.ISA(SfxObjectShell) )
189 aStatement = DEFINE_CONST_UNICODE("ActiveDocument");
192 else if ( rShell.ISA(SfxViewShell) || rShell.ISA(SfxViewFrame) )
193 aStatement = DEFINE_CONST_UNICODE("ActiveWindow");
196 // an einer Sub-Shell
197 aStatement = DEFINE_CONST_UNICODE("Selection");
203 // bei Selection ggf. noch den Namen der SubShell anh"angen
204 const SfxShellObject *pShObj =
205 (const SfxShellObject*) rShell.GetSbxObject();
208 const SfxShellObject *pParentObj =
209 (const SfxShellObject*) pShObj->GetParent();
210 SfxShell *pParentSh = pParentObj->GetShell();
211 DBG_ASSERT( pParentSh->ISA(SfxViewFrame),
212 "parent of SubShell must be a Frame" );
213 if ( rSlot.pName[0] == '.' )
216 aStatement += rShell.GetSbxObject()->GetName();
220 DBG_ASSERT( rSlot.pName[0] != '0', "recording unnamed object" );
223 aStatement
= DEFINE_CONST_UNICODE("Selection");
225 // an diesen Objekt-Ausdruck den Methoden-/Property-Namen und Parameter
226 GenerateNameAndArgs_Impl( SfxRequest::GetRecordingMacro(), rSlot
, bRequestDone
, aArgs
);
229 //--------------------------------------------------------------------
231 SfxMacroStatement::SfxMacroStatement
233 const String
& rTarget
, // Objekt, was beim Playing angesprochen wird
234 const SfxSlot
& rSlot
, // der <SfxSlot>, der das Statement abspielen kann
235 BOOL bRequestDone
, // wurde der Request tats"achlich ausgef"uhrt
236 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& rArgs
244 <SfxMacroStatement::SfxMacroStatement(const String&)>
245 <SfxMacroStatement::SfxMacroStatement(const SfxShell&,BOOL,const SfxSlot&,BOOL,SfxArguments*)>
248 : nSlotId( rSlot
.GetSlotId() ),
250 bDone( bRequestDone
),
253 aStatement
= rTarget
;
255 GenerateNameAndArgs_Impl( SfxRequest::GetRecordingMacro(), rSlot
, bRequestDone
, aArgs
);
258 //--------------------------------------------------------------------
260 SfxMacroStatement::SfxMacroStatement
262 const String
& rStatement
// manuell erzeugte(s) Statement(s)
267 Dieser Konstruktor erzeugt eine SfxMacroStatement-Instanz, deren
268 Aufbau vollst"andig vom Applikationsentwickler bestimmt wird. Da der
269 angegebene String auch mehrere mit CR/LF getrennte Statements
270 enthalten darf, ist damit ein weitgehender Eingriff in das Aufzeichnen
271 von BASIC-Makros m"oglich, um Spezialf"alle zu behandeln.
276 <SfxMacroStatement::SfxMacroStatement(const String&,const SfxSlot&,BOOL,SfxArguments*)>
277 <SfxMacroStatement::SfxMacroStatement(const SfxShell&,BOOL,const SfxSlot&,BOOL,SfxArguments*)>
281 aStatement( rStatement
),
287 //--------------------------------------------------------------------
289 SfxMacroStatement::SfxMacroStatement
291 const SfxMacroStatement
& rOrig
// Original, von dem kopiert wird
296 Copy-Konstruktor der SfxMacroStatement-Klasse.
299 : nSlotId( rOrig
.nSlotId
),
300 aStatement( rOrig
.aStatement
),
301 bDone( rOrig
.bDone
),
307 //--------------------------------------------------------------------
309 SfxMacroStatement::~SfxMacroStatement()
313 Destruktor der Klasse SfxMacroStatement. Gibt die Liste der
314 aktuellen Parameter frei.
320 //--------------------------------------------------------------------
322 void SfxMacroStatement::GenerateNameAndArgs_Impl
324 SfxMacro
* /*pMacro*/, // darin wird aufgezeichnet
325 const SfxSlot
& rSlot
, // der Slot, der das Statement abspielen kann
326 BOOL bRequestDone
, // TRUE=wurde ausgef"uhrt, FALSE=abgebrochen
327 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& /*rArgs*/
332 Interne Hilfsmethode zum generieren des Funktions-/Property-Names
333 sowie der Parameter. Diese Methode wird nur verwendet, wenn der
334 Anwendungsprogrammierer keinen eigenen Source an den <SfxRequest>
339 if ( aStatement
.Len() && aStatement
.GetChar( aStatement
.Len() - 1 ) != '.'
340 && rSlot
.pName
[0] != '.' )
343 // der Name des Slots ist der Name der Methode / des Properties
344 aStatement
+= String::CreateFromAscii(rSlot
.pName
);
345 if ( rSlot
.IsMode(SFX_SLOT_METHOD
) )
346 aStatement
+= DEFINE_CONST_UNICODE("( ");
348 aStatement
+= DEFINE_CONST_UNICODE(" = ");
350 // alle zusammengesuchten Parameter rausschreiben
351 if ( aArgs
.getLength() )
352 for ( USHORT nArg
= 0; nArg
< aArgs
.getLength(); ++nArg
)
354 // den Parameter textuell darstellen
356 ::com::sun::star::uno::Any
& rValue
= aArgs
[nArg
].Value
;
357 ::com::sun::star::uno::Type pType
= rValue
.getValueType();
358 if ( pType
== ::getBooleanCppuType() )
360 sal_Bool bTemp
= false;
362 aArg
= bTemp
? DEFINE_CONST_UNICODE("TRUE") : DEFINE_CONST_UNICODE("FALSE");
364 else if ( pType
== ::getCppuType((const sal_Int16
*)0) )
366 sal_uInt16 nTemp
= 0;
368 aArg
= String::CreateFromInt32( (sal_Int32
) nTemp
);
370 else if ( pType
== ::getCppuType((const sal_Int32
*)0) )
372 sal_uInt32 nTemp
= 0;
374 aArg
= String::CreateFromInt32( nTemp
);
376 else if ( pType
== ::getCppuType((const ::rtl::OUString
*)0) )
378 ::rtl::OUString sTemp
;
381 // Anf"uhrungszeichen werden verdoppelt
382 XubString
aRecordable( sTemp
);
386 nPos
= aRecordable
.SearchAndReplace( DEFINE_CONST_UNICODE('"'), DEFINE_CONST_UNICODE("\"\""), nPos
);
387 if ( STRING_NOTFOUND
== nPos
)
392 // nicht druckbare Zeichen werden als chr$(...) geschrieben
393 FASTBOOL bPrevReplaced
= FALSE
;
394 for ( USHORT n
= 0; n
< aRecordable
.Len(); ++n
)
396 sal_Unicode cChar
= aRecordable
.GetChar(n
);
397 if ( !( cChar
>=32 && cChar
!=127 ) ) // ALS ERSATZ FUER String::IsPrintable()!
399 XubString
aReplacement( DEFINE_CONST_UNICODE("+chr$(") );
400 aReplacement
+= cChar
;
404 aRecordable
.Insert( aReplacement
, n
- 2 );
405 n
= n
+ aReplacement
.Len();
406 aRecordable
.SetChar((unsigned short) (n
-2), 0x0029);// ')' = 29h
407 aRecordable
.Replace( n
-1, 2, DEFINE_CONST_UNICODE("+\"") );
412 aReplacement
+= DEFINE_CONST_UNICODE(")+\"");
413 aRecordable
.SetChar(n
, 0x0022 );// '"' = 22h
414 aRecordable
.Insert( aReplacement
, n
+ 1 );
415 n
= n
+ aReplacement
.Len();
417 bPrevReplaced
= TRUE
;
420 bPrevReplaced
= FALSE
;
422 // Argument in Anf"uhrungszeichen
430 // als Zahl darstellen
431 aArg = (USHORT) rVar.GetByte();
439 pType
== ::getVoidCppuType(), "Unknown Type in recorder!" );
442 // den Parameter anh"angen
444 aStatement
+= DEFINE_CONST_UNICODE(", ");
448 if ( aArgs
.getLength() )
449 aStatement
.Erase( aStatement
.Len() - 2, 1 );
451 aStatement
.Erase( aStatement
.Len() - 1, 1 );
452 if ( rSlot
.IsMode(SFX_SLOT_METHOD
) )
456 // nicht als "Done()" gekennzeichnete Statements auskommentieren
457 aStatement
.InsertAscii( "rem ", 0 );
460 //--------------------------------------------------------------------
464 SfxMacroMode eMode
// Zweck der Instanz, siehe <SfxMacroMode>
469 Konstruktor der Klasse SfxMacro. Instanzen dieser Klasse werden im
470 SFx zu zwei Zwecken ben"otigt:
472 1. zum Aufzeichnen von Makros
473 In diesem Fall wird der Konstruktor mit SFX_MACRO_RECORDINGABSOLUTE
474 oder SFX_MACRO_RECORDINGRELATIVE aufgerufen. Es sollte sich um eine
475 Instanz einer abgeleiteten Klasse handeln, um in der Ableitung
476 die Information dar"uber unterzubringen, wo das Makro gespeichert
477 werden soll. Ein solches Makro solle sich dann in seinem Destruktor
478 an der vom Benutzer gew"ahlten Stelle speichern.
480 2. zum Zuordnen von exisitierenden Makros
481 In diesem Fall wird der Konstruktor mit SFX_MACRO_EXISTING aufgerufen.
482 Eine solche Instanz wird z.B. ben"otigt, wenn Makros auf Events
483 oder <SfxControllerItem>s konfiguriert werden sollen.
486 : pImp( new SfxMacro_Impl
)
492 //--------------------------------------------------------------------
494 SfxMacro::~SfxMacro()
498 Virtueller Destruktor der Klasse SfxMacro. Dieser sollte in den
499 abgeleiteten Klassen "uberladen werden, um in den Modi
500 SFX_MACRO_RECORDINGABSOLUTE und SFX_MACRO_RECORDINGRELATIVE den
501 aufgezeichneten Source abzuspeichern.
506 <SfxMacro::GenerateSource()const>
510 #if OSL_DEBUG_LEVEL > 1
511 SvFileStream
aStream( String::CreateFromAscii("file:///f:/testmacro.bas" ), STREAM_STD_READWRITE
| STREAM_TRUNC
);
512 aStream
<< ByteString( GenerateSource(), RTL_TEXTENCODING_UTF8
).GetBuffer();
517 //--------------------------------------------------------------------
519 SfxMacroMode
SfxMacro::GetMode() const
523 Liefert den Modus, der besagt zu welchem Zweck das SfxMacro konstruiert
536 //--------------------------------------------------------------------
538 void SfxMacro::Record
540 SfxMacroStatement
* pStatement
// aufzuzeichnendes <SfxMacroStatement>
545 Diese Methode zeichnet das als Parameter "ubergeben Statement auf.
546 Die Instanz auf die der "ubergebe Pointer zeigt, geht in das Eigentum
549 Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt,
550 welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE
556 <SfxMacro::Replace(SfxMacroStatement*)>
558 <SfxMacro::GetLastStatement()const>
562 DBG_ASSERT( pImp
->eMode
!= SFX_MACRO_EXISTING
, "invalid call to non-recording SfxMacro" );
563 pImp
->aList
.C40_INSERT( SfxMacroStatement
, pStatement
, pImp
->aList
.Count() );
566 //--------------------------------------------------------------------
568 void SfxMacro::Replace
570 SfxMacroStatement
* pStatement
// aufzuzeichnendes <SfxMacroStatement>
575 Diese Methode zeichnet das als Parameter "ubergeben Statement auf.
576 Dabei wird das jeweils zuletzt aufgezeichnete Statement "uberschrieben.
577 Die Instanz auf die der "ubergebe Pointer zeigt, geht in das Eigentum
580 Mit dieser Methode ist es m"oglich, Statements zusammenzufassen. Z.B.
581 anstelle f"unfmal hintereinander 'CursorLeft()' aufzurufen, k"onnte
582 das zu 'CursorLeft(5)' zusammengefa\st werden. Oder anstelle ein Wort
583 Buchstabe f"ur Buchstabe aufzubauen, k"onnte dies durch ein einziges
584 Statement 'InsertString("Hallo")' ersetzt werden.
586 Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt,
587 welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE
588 konstruiert wurde und bereits ein aufgezeichnetes Statement vorhanden
594 Diese Methode wird typischerweise aus den Execute-Methoden der
595 <SfxSlot>s von den Applikationsentwicklern gerufen.
600 <SfxMacro::Record(SfxMacroStatement*)>
602 <SfxMacro::GetLastStatement()const>
606 DBG_ASSERT( pImp
->eMode
!= SFX_MACRO_EXISTING
, "invalid call to non-recording SfxMacro" );
607 DBG_ASSERT( pImp
->aList
.Count(), "no replaceable statement available" );
608 pImp
->aList
.Remove( pImp
->aList
.Count() - 1 );
609 pImp
->aList
.C40_INSERT( SfxMacroStatement
,pStatement
, pImp
->aList
.Count() );
612 //--------------------------------------------------------------------
614 void SfxMacro::Remove()
618 Diese Methode l"oscht das zuletzt aufgezeichnete <SfxMacroStatement>
619 und entfernt es aus dem Macro.
621 Mit dieser Methode ist es m"oglich, Statements zusammenzufassen. Z.B.
622 anstelle f"unfmal hintereinander 'CursorLeft()' aufzurufen, k"onnte
623 das zu 'CursorLeft(5)' zusammengefa\st werden. Oder anstelle ein Wort
624 Buchstabe f"ur Buchstabe aufzubauen, k"onnte dies durch ein einziges
625 Statement 'InsertString("Hallo")' ersetzt werden.
627 Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt,
628 welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE
629 konstruiert wurde und bereits ein aufgezeichnetes Statement vorhanden
635 Diese Methode wird typischerweise aus den Execute-Methoden der
636 <SfxSlot>s von den Applikationsentwicklern gerufen.
641 <SfxMacro::Replace(SfxMacroStatement*)>
642 <SfxMacro::Record(SfxMacroStatement*)>
643 <SfxMacro::GetLastStatement()const>
647 DBG_ASSERT( pImp
->eMode
!= SFX_MACRO_EXISTING
, "invalid call to non-recording SfxMacro" );
648 DBG_ASSERT( pImp
->aList
.Count(), "no replaceable statement available" );
649 pImp
->aList
.Remove( pImp
->aList
.Count() - 1 );
652 //--------------------------------------------------------------------
654 const SfxMacroStatement
* SfxMacro::GetLastStatement() const
658 Mit dieser Methode kann auf das jeweils zuletzt aufgezeichnete Statement
659 lesend zugegriffen werden. Zusammen mit der Methode
660 <SfxMacro::Replace(SfxMacroStatement*)> ergibt sich dadurch die
661 M"oglichkeit, Statements zusammenzufassen.
663 Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt,
664 welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE
670 <SfxMacro::Record(SfxMacroStatement*)>
671 <SfxMacro::Replace(SfxMacroStatement*)>
675 DBG_ASSERT( pImp
->eMode
!= SFX_MACRO_EXISTING
, "invalid call to non-recording SfxMacro" );
676 if ( pImp
->aList
.Count() )
677 return pImp
->aList
.GetObject( pImp
->aList
.Count() - 1 );
681 //--------------------------------------------------------------------
683 String
SfxMacro::GenerateSource() const
687 Diese Funktion generiert aus den, seit dem Konstruieren der Instanz
688 bis zum Zeitpunkt des Aufrufs dieser Methode aufgezeichneten
689 <SfxMacroStatement>s einen BASIC-Sourcecode, der die Statements,
690 jedoch nicht den Header ('Sub X') und den Footer ('End Sub') enth"alt.
695 <SfxMacro::Record(SfxMacroStatement*)>
696 <SfxMacro::Repeat(SfxMacroStatement*)>
700 DBG_ASSERT( pImp
->eMode
!= SFX_MACRO_EXISTING
, "invalid call to non-recording SfxMacro" );
702 for ( USHORT n
= 0; n
< pImp
->aList
.Count(); ++n
)
704 aSource
+= pImp
->aList
.GetObject(n
)->GetStatement();
705 if ( (n
+1) < pImp
->aList
.Count() )
706 aSource
+= DEFINE_CONST_UNICODE("\n");