xref: /trunk/main/sfx2/source/control/macro.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
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.
14  *
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).
20  *
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.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sfx2.hxx"
30 
31 #if OSL_DEBUG_LEVEL > 1
32 #include <tools/stream.hxx>
33 #endif
34 
35 #include "macro.hxx"
36 #include <sfx2/request.hxx>
37 #include <sfx2/msg.hxx>
38 
39 //====================================================================
40 
41 SV_DECL_PTRARR_DEL( SfxStatements_Impl, SfxMacroStatement*, 16, 8 )
42 SV_IMPL_PTRARR( SfxStatements_Impl, SfxMacroStatement* );
43 
44 //--------------------------------------------------------------------
45 
46 struct SfxMacro_Impl
47 
48 /*  [Beschreibung]
49 
50     Implementations-Struktur der Klasse <SfxMacro>.
51 */
52 
53 {
54     SfxMacroMode        eMode;  /*  Zweck der <SfxMacro>-Instanz,
55                                     Bedeutung siehe enum <SfxMacroMode> */
56     SfxStatements_Impl  aList;  /*  Liste von aufgezeichneten Statements */
57 };
58 
59 //====================================================================
60 
61 SfxMacroStatement::SfxMacroStatement
62 (
63     const SfxShell& /*rShell*/,     // <SfxShell>, die den Request ausf"uhrte
64     const String&   /*rTarget*/,    // Name des Zielobjektes vor der Ausf"urhung
65     sal_Bool            /*bAbsolute*/,  // obsolet
66     const SfxSlot&  rSlot,          // der <SfxSlot>, der das Statement abspielen kann
67     sal_Bool            bRequestDone,   // wurde der Request tats"achlich ausgef"uhrt
68     ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& rArgs
69 )
70 
71 /*  [Beschreibung]
72 
73     Dieser Konstruktor der Klasse SfxMacroStatement erzeugt ein Statement,
74     bei dem ein Objekt angesprochen wird, welches durch 'rShell' angegeben
75     ist. Dabei erfolgt die Addressierung je nach 'bAbsolute' absolut,
76     also z.B. als '[mydoc.sdc]' oder relativ, also z.B. 'ActiveDocument'.
77 
78     Je nach Art der Subklasse von 'rShell' ergeben sich folgende
79     Ausdr"ucke:
80 
81                           | absolut                  relativ
82     -----------------------------------------------------------------------
83     SfxApplication'       | 'StarCalc'              'Application'
84     SfxViewFrame'         | '[mydoc.sdc:1]'         'ActiveWindow'
85     SfxViewShell'         | '[mydoc.sdc:1]'         'AvtiveWindow'
86     SfxObjectShell'       | '[mydoc.sdc]'           'ActiveDocument'
87     sonstige (Sub-Shells) | '[mydoc.sdc:1]'         'ActiveWindow'
88 
89     Dabei sind 'StarCalc' stellvertretend fuer den Namen der Applikation
90     (Application::GetAppName()const). In der absoluten Fassung k"onnte
91     die Selektion auch deskriptiv z.B. als 'CellSelection("A5-D8")')
92     angesprochen werden, dazu mu\ jedoch vom Anwendungsprogrammierer der
93     Konstruktor <SfxMacroStatement::SfxMacroStatement(const String&,
94     const SfxSlot&,sal_Bool,SfxArguments*)> verwendet werden.
95 
96     F"ur das so bezeichnete Objekt wird dann je nach Typ des Slots
97     eine Zuweisung an eines seiner Properties oder der Aufruf einer seiner
98     Methoden ausgedr"uckt.
99 
100 
101     [Beispiele]
102 
103     absolut:
104     SCalc3.OpenDocument( "\docs\mydoc.sdd", "StarDraw Presentation", 0, 0 )
105     [mydoc.sdd].Activate()
106     [mydoc.sdd:1].SwitchToView( 2 )
107     [mydoc.sdc:1:1].CellSelection( "A5-D8" ).LineColor = 192357
108 
109     relativ:
110     ActiveWindow.LineColor = 192357
111 
112 
113     [Querverweise]
114 
115     <SfxMacroStatement::SfxMacroStatement(const String&,const SfxSlot&,sal_Bool,SfxArguments*)>
116     <SfxMacroStatement::SfxMacroStatement(const String&)>
117 */
118 
119 :   nSlotId( rSlot.GetSlotId() ),
120     aArgs( rArgs ),
121     bDone( bRequestDone ),
122     pDummy( 0 )
123 {
124     // Workaround Recording nicht exportierter Slots (#25386#)
125     if ( !rSlot.pName )
126         return;
127 /*
128     // Objekt-Typ bestimmen
129     bool bIsApp = rShell.ISA(SfxApplication);
130     bool bIsDoc = rShell.ISA(SfxObjectShell);
131     bool bIsWin = !bIsApp && !bIsDoc &&
132                       ( rShell.ISA(SfxViewShell) || rShell.ISA(SfxViewFrame) );
133     bool bIsSel = !bIsApp && !bIsDoc && !bIsWin;
134 
135     // Objekt nicht schon im Slot-Namen enthalten?
136     if ( bIsSel || rSlot.pName[0] == '.' )
137     {
138         // absolutes Aufzeichnen?
139         if ( rSlot.IsMode( SFX_SLOT_RECORDABSOLUTE ) )
140         {
141             // an der Applikation oder am Modul
142             if ( rShell.ISA(SfxApplication) || rShell.ISA(SfxModule) )
143                 aStatement = rTarget;
144 
145             // am Dokument?
146             // '[' = 5Bh
147             // ']' = 5Dh
148             else if ( rShell.ISA(SfxObjectShell) )
149             {
150                 aStatement = 0x005B;
151                 aStatement += rTarget;
152                 aStatement += 0x005D;
153             }
154 
155             else if ( rShell.ISA(SfxViewFrame) )
156             {
157                 aStatement = 0x005B;
158                 aStatement += String::CreateFromAscii("ViewFrame");//rShell.GetSbxObject()->GetName();
159                 aStatement += 0x005D;
160             }
161 
162             else
163             {
164                 // an der View oder Sub-Shell
165                 SfxViewShell *pViewShell = rShell.GetViewShell();
166                 aStatement = 0x005B;
167                 aStatement += String::CreateFromAscii("ViewShell");//pViewShell->GetViewFrame()->GetSbxObject()->GetName();
168                 aStatement += 0x005D;
169                 if ( !rShell.ISA(SfxViewFrame) )
170                     // an einer Sub-Shell zus"atlich ".Selection" anh"angen
171                     aStatement += DEFINE_CONST_UNICODE(".Selection");
172             }
173         }
174         else // relatives Aufzeichnen
175         {
176             // an der Application?
177             if ( rShell.ISA(SfxApplication) )
178                 aStatement = DEFINE_CONST_UNICODE("Application");
179 
180             // am Modul?
181             else if ( rShell.ISA(SfxModule) )
182                 aStatement = DEFINE_CONST_UNICODE("ActiveModule");
183 
184             // am Dokument
185             else if ( rShell.ISA(SfxObjectShell) )
186                 aStatement = DEFINE_CONST_UNICODE("ActiveDocument");
187 
188             // am Window
189             else if ( rShell.ISA(SfxViewShell) || rShell.ISA(SfxViewFrame) )
190                 aStatement = DEFINE_CONST_UNICODE("ActiveWindow");
191 
192             else
193                 // an einer Sub-Shell
194                 aStatement = DEFINE_CONST_UNICODE("Selection");
195         }
196     }
197 
198     if ( bIsSel )
199     {
200         // bei Selection ggf. noch den Namen der SubShell anh"angen
201         const SfxShellObject *pShObj =
202                     (const SfxShellObject*) rShell.GetSbxObject();
203         if ( pShObj )
204         {
205             const SfxShellObject *pParentObj =
206                         (const SfxShellObject*) pShObj->GetParent();
207             SfxShell *pParentSh = pParentObj->GetShell();
208             DBG_ASSERT( pParentSh->ISA(SfxViewFrame),
209                         "parent of SubShell must be a Frame" );
210             if ( rSlot.pName[0] == '.' )
211             {
212                 aStatement += '.';
213                 aStatement += rShell.GetSbxObject()->GetName();
214             }
215         }
216         else
217             DBG_ASSERT( rSlot.pName[0] != '0', "recording unnamed object" );
218     }
219 */
220     aStatement = DEFINE_CONST_UNICODE("Selection");
221 
222     // an diesen Objekt-Ausdruck den Methoden-/Property-Namen und Parameter
223     GenerateNameAndArgs_Impl( SfxRequest::GetRecordingMacro(), rSlot, bRequestDone, aArgs);
224 }
225 
226 //--------------------------------------------------------------------
227 
228 SfxMacroStatement::SfxMacroStatement
229 (
230     const String&   rTarget,        // Objekt, was beim Playing angesprochen wird
231     const SfxSlot&  rSlot,          // der <SfxSlot>, der das Statement abspielen kann
232     sal_Bool            bRequestDone,   // wurde der Request tats"achlich ausgef"uhrt
233     ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& rArgs
234 )
235 
236 /*  [Beschreibung]
237 
238 
239     [Querverweise]
240 
241     <SfxMacroStatement::SfxMacroStatement(const String&)>
242     <SfxMacroStatement::SfxMacroStatement(const SfxShell&,sal_Bool,const SfxSlot&,sal_Bool,SfxArguments*)>
243 */
244 
245 :   nSlotId( rSlot.GetSlotId() ),
246     aArgs( rArgs ),
247     bDone( bRequestDone ),
248     pDummy( 0 )
249 {
250     aStatement = rTarget;
251     aStatement += '.';
252     GenerateNameAndArgs_Impl( SfxRequest::GetRecordingMacro(), rSlot, bRequestDone, aArgs);
253 }
254 
255 //--------------------------------------------------------------------
256 
257 SfxMacroStatement::SfxMacroStatement
258 (
259     const String&   rStatement      // manuell erzeugte(s) Statement(s)
260 )
261 
262 /*  [Beschreibung]
263 
264     Dieser Konstruktor erzeugt eine SfxMacroStatement-Instanz, deren
265     Aufbau vollst"andig vom Applikationsentwickler bestimmt wird. Da der
266     angegebene String auch mehrere mit CR/LF getrennte Statements
267     enthalten darf, ist damit ein weitgehender Eingriff in das Aufzeichnen
268     von BASIC-Makros m"oglich, um Spezialf"alle zu behandeln.
269 
270 
271     [Querverweise]
272 
273     <SfxMacroStatement::SfxMacroStatement(const String&,const SfxSlot&,sal_Bool,SfxArguments*)>
274     <SfxMacroStatement::SfxMacroStatement(const SfxShell&,sal_Bool,const SfxSlot&,sal_Bool,SfxArguments*)>
275 */
276 
277 :   nSlotId( 0 ),
278        aStatement( rStatement ),
279     bDone( sal_True ),
280     pDummy( 0 )
281 {
282 }
283 
284 //--------------------------------------------------------------------
285 
286 SfxMacroStatement::SfxMacroStatement
287 (
288     const SfxMacroStatement&    rOrig // Original, von dem kopiert wird
289 )
290 
291 /*  [Beschreibung]
292 
293     Copy-Konstruktor der SfxMacroStatement-Klasse.
294 */
295 
296 :   nSlotId( rOrig.nSlotId ),
297     aStatement( rOrig.aStatement ),
298        bDone( rOrig.bDone ),
299     pDummy( 0 )
300 {
301     aArgs = rOrig.aArgs;
302 }
303 
304 //--------------------------------------------------------------------
305 
306 SfxMacroStatement::~SfxMacroStatement()
307 
308 /*  [Beschreibung]
309 
310     Destruktor der Klasse SfxMacroStatement. Gibt die Liste der
311     aktuellen Parameter frei.
312 */
313 
314 {
315 }
316 
317 //--------------------------------------------------------------------
318 
319 void SfxMacroStatement::GenerateNameAndArgs_Impl
320 (
321     SfxMacro*       /*pMacro*/,         // darin wird aufgezeichnet
322     const SfxSlot&  rSlot,          // der Slot, der das Statement abspielen kann
323     sal_Bool            bRequestDone,   // sal_True=wurde ausgef"uhrt, sal_False=abgebrochen
324     ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& /*rArgs*/
325 )
326 
327 /*  [Beschreibung]
328 
329     Interne Hilfsmethode zum generieren des Funktions-/Property-Names
330     sowie der Parameter. Diese Methode wird nur verwendet, wenn der
331     Anwendungsprogrammierer keinen eigenen Source an den <SfxRequest>
332     geh"angt hat.
333 */
334 
335 {
336     if ( aStatement.Len() && aStatement.GetChar( aStatement.Len() - 1 ) != '.'
337          && rSlot.pName[0] != '.' )
338         aStatement += '.';
339 
340     // der Name des Slots ist der Name der Methode / des Properties
341     aStatement += String::CreateFromAscii(rSlot.pName);
342     if ( rSlot.IsMode(SFX_SLOT_METHOD) )
343         aStatement += DEFINE_CONST_UNICODE("( ");
344     else
345         aStatement += DEFINE_CONST_UNICODE(" = ");
346 
347     // alle zusammengesuchten Parameter rausschreiben
348     if ( aArgs.getLength() )
349         for ( sal_uInt16 nArg = 0; nArg < aArgs.getLength(); ++nArg )
350         {
351             // den Parameter textuell darstellen
352             String aArg;
353             ::com::sun::star::uno::Any& rValue = aArgs[nArg].Value;
354             ::com::sun::star::uno::Type pType = rValue.getValueType();
355             if ( pType == ::getBooleanCppuType() )
356             {
357                 sal_Bool bTemp = false;
358                 rValue >>= bTemp;
359                 aArg = bTemp ? DEFINE_CONST_UNICODE("TRUE") : DEFINE_CONST_UNICODE("FALSE");
360             }
361             else if ( pType == ::getCppuType((const sal_Int16*)0) )
362             {
363                 sal_uInt16 nTemp = 0;
364                 rValue >>= nTemp;
365                 aArg = String::CreateFromInt32( (sal_Int32) nTemp );
366             }
367             else if ( pType == ::getCppuType((const sal_Int32*)0) )
368             {
369                 sal_uInt32 nTemp = 0;
370                 rValue >>= nTemp;
371                 aArg = String::CreateFromInt32( nTemp );
372             }
373             else if ( pType == ::getCppuType((const ::rtl::OUString*)0) )
374             {
375                 ::rtl::OUString sTemp;
376                 rValue >>= sTemp;
377 
378                 // Anf"uhrungszeichen werden verdoppelt
379                 XubString aRecordable( sTemp );
380                 sal_uInt16 nPos = 0;
381                 while ( sal_True )
382                 {
383                     nPos = aRecordable.SearchAndReplace( DEFINE_CONST_UNICODE('"'), DEFINE_CONST_UNICODE("\"\""), nPos );
384                     if ( STRING_NOTFOUND == nPos )
385                         break;
386                     nPos += 2;
387                 }
388 
389                 // nicht druckbare Zeichen werden als chr$(...) geschrieben
390                 bool bPrevReplaced = sal_False;
391                 for ( sal_uInt16 n = 0; n < aRecordable.Len(); ++n )
392                 {
393                     sal_Unicode cChar = aRecordable.GetChar(n);
394                     if ( !( cChar>=32 && cChar!=127 ) ) // ALS ERSATZ FUER String::IsPrintable()!
395                     {
396                         XubString aReplacement( DEFINE_CONST_UNICODE("+chr$(") );
397                         aReplacement += cChar;
398 
399                         if ( bPrevReplaced )
400                         {
401                             aRecordable.Insert( aReplacement, n - 2 );
402                             n = n + aReplacement.Len();
403                             aRecordable.SetChar((unsigned short) (n-2), 0x0029);// ')' = 29h
404                             aRecordable.Replace( n-1, 2, DEFINE_CONST_UNICODE("+\"") );
405                             // ++n;
406                         }
407                         else
408                         {
409                             aReplacement += DEFINE_CONST_UNICODE(")+\"");
410                             aRecordable.SetChar(n, 0x0022 );// '"' = 22h
411                             aRecordable.Insert( aReplacement, n + 1 );
412                             n = n + aReplacement.Len();
413                         }
414                         bPrevReplaced = sal_True;
415                     }
416                     else
417                         bPrevReplaced = sal_False;
418 
419                     // Argument in Anf"uhrungszeichen
420                     aArg = '"';
421                     aArg += aRecordable;
422                     aArg += '"';
423                 }
424 /*
425                 case SbxBYTE:
426                 {
427                     // als Zahl darstellen
428                     aArg = (sal_uInt16) rVar.GetByte();
429                     break;
430                 }
431 */
432             }
433             else
434             {
435                 OSL_ENSURE(
436                     pType == ::getVoidCppuType(), "Unknown Type in recorder!" );
437             }
438 
439             // den Parameter anh"angen
440             aStatement += aArg;
441             aStatement += DEFINE_CONST_UNICODE(", ");
442         }
443 
444     // Statement beeden
445     if ( aArgs.getLength() )
446         aStatement.Erase( aStatement.Len() - 2, 1 );
447     else
448         aStatement.Erase( aStatement.Len() - 1, 1 );
449     if ( rSlot.IsMode(SFX_SLOT_METHOD) )
450         aStatement += ')';
451 
452     if ( !bRequestDone )
453         // nicht als "Done()" gekennzeichnete Statements auskommentieren
454         aStatement.InsertAscii( "rem ", 0 );
455 }
456 
457 //--------------------------------------------------------------------
458 
459 SfxMacro::SfxMacro
460 (
461     SfxMacroMode    eMode       // Zweck der Instanz, siehe <SfxMacroMode>
462 )
463 
464 /*  [Beschreibung]
465 
466     Konstruktor der Klasse SfxMacro. Instanzen dieser Klasse werden im
467     SFx zu zwei Zwecken ben"otigt:
468 
469     1. zum Aufzeichnen von Makros
470     In diesem Fall wird der Konstruktor mit SFX_MACRO_RECORDINGABSOLUTE
471     oder SFX_MACRO_RECORDINGRELATIVE aufgerufen. Es sollte sich um eine
472     Instanz einer abgeleiteten Klasse handeln, um in der Ableitung
473     die Information dar"uber unterzubringen, wo das Makro gespeichert
474     werden soll. Ein solches Makro solle sich dann in seinem Destruktor
475     an der vom Benutzer gew"ahlten Stelle speichern.
476 
477     2. zum Zuordnen von exisitierenden Makros
478     In diesem Fall wird der Konstruktor mit SFX_MACRO_EXISTING aufgerufen.
479     Eine solche Instanz wird z.B. ben"otigt, wenn Makros auf Events
480     oder <SfxControllerItem>s konfiguriert werden sollen.
481 */
482 
483 :   pImp( new SfxMacro_Impl )
484 
485 {
486     pImp->eMode = eMode;
487 }
488 
489 //--------------------------------------------------------------------
490 
491 SfxMacro::~SfxMacro()
492 
493 /*  [Beschreibung]
494 
495     Virtueller Destruktor der Klasse SfxMacro. Dieser sollte in den
496     abgeleiteten Klassen "uberladen werden, um in den Modi
497     SFX_MACRO_RECORDINGABSOLUTE und SFX_MACRO_RECORDINGRELATIVE den
498     aufgezeichneten Source abzuspeichern.
499 
500 
501     [Querverweise]
502 
503     <SfxMacro::GenerateSource()const>
504 */
505 
506 {
507 #if OSL_DEBUG_LEVEL > 1
508     SvFileStream aStream( String::CreateFromAscii("file:///f:/testmacro.bas" ), STREAM_STD_READWRITE | STREAM_TRUNC );
509     aStream << ByteString( GenerateSource(), RTL_TEXTENCODING_UTF8 ).GetBuffer();
510 #endif
511     delete pImp;
512 }
513 
514 //--------------------------------------------------------------------
515 
516 SfxMacroMode SfxMacro::GetMode() const
517 
518 /*  [Beschreibung]
519 
520     Liefert den Modus, der besagt zu welchem Zweck das SfxMacro konstruiert
521     wurde.
522 
523 
524     [Querverweise]
525 
526     enum <SfxMacroMode>
527 */
528 
529 {
530     return pImp->eMode;
531 }
532 
533 //--------------------------------------------------------------------
534 
535 void SfxMacro::Record
536 (
537     SfxMacroStatement*  pStatement  // aufzuzeichnendes <SfxMacroStatement>
538 )
539 
540 /*  [Beschreibung]
541 
542     Diese Methode zeichnet das als Parameter "ubergeben Statement auf.
543     Die Instanz auf die der "ubergebe Pointer zeigt, geht in das Eigentum
544     des SfxMacro "uber.
545 
546     Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt,
547     welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE
548     konstruiert wirde.
549 
550 
551     [Querverweise]
552 
553     <SfxMacro::Replace(SfxMacroStatement*)>
554     <SfxMacro::Remove()>
555     <SfxMacro::GetLastStatement()const>
556 */
557 
558 {
559     DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, "invalid call to non-recording SfxMacro" );
560     pImp->aList.C40_INSERT( SfxMacroStatement, pStatement, pImp->aList.Count() );
561 }
562 
563 //--------------------------------------------------------------------
564 
565 void SfxMacro::Replace
566 (
567     SfxMacroStatement*  pStatement  // aufzuzeichnendes <SfxMacroStatement>
568 )
569 
570 /*  [Beschreibung]
571 
572     Diese Methode zeichnet das als Parameter "ubergeben Statement auf.
573     Dabei wird das jeweils zuletzt aufgezeichnete Statement "uberschrieben.
574     Die Instanz auf die der "ubergebe Pointer zeigt, geht in das Eigentum
575     des SfxMacro "uber.
576 
577     Mit dieser Methode ist es m"oglich, Statements zusammenzufassen. Z.B.
578     anstelle f"unfmal hintereinander 'CursorLeft()' aufzurufen, k"onnte
579     das zu 'CursorLeft(5)' zusammengefa\st werden. Oder anstelle ein Wort
580     Buchstabe f"ur Buchstabe aufzubauen, k"onnte dies durch ein einziges
581     Statement 'InsertString("Hallo")' ersetzt werden.
582 
583     Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt,
584     welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE
585     konstruiert wurde und bereits ein aufgezeichnetes Statement vorhanden
586     ist.
587 
588 
589     [Anmerkung]
590 
591     Diese Methode wird typischerweise aus den Execute-Methoden der
592     <SfxSlot>s von den Applikationsentwicklern gerufen.
593 
594 
595     [Querverweise]
596 
597     <SfxMacro::Record(SfxMacroStatement*)>
598     <SfxMacro::Remove()>
599     <SfxMacro::GetLastStatement()const>
600 */
601 
602 {
603     DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, "invalid call to non-recording SfxMacro" );
604     DBG_ASSERT( pImp->aList.Count(), "no replaceable statement available" );
605     pImp->aList.Remove( pImp->aList.Count() - 1 );
606     pImp->aList.C40_INSERT( SfxMacroStatement,pStatement, pImp->aList.Count() );
607 }
608 
609 //--------------------------------------------------------------------
610 
611 void SfxMacro::Remove()
612 
613 /*  [Beschreibung]
614 
615     Diese Methode l"oscht das zuletzt aufgezeichnete <SfxMacroStatement>
616     und entfernt es aus dem Macro.
617 
618     Mit dieser Methode ist es m"oglich, Statements zusammenzufassen. Z.B.
619     anstelle f"unfmal hintereinander 'CursorLeft()' aufzurufen, k"onnte
620     das zu 'CursorLeft(5)' zusammengefa\st werden. Oder anstelle ein Wort
621     Buchstabe f"ur Buchstabe aufzubauen, k"onnte dies durch ein einziges
622     Statement 'InsertString("Hallo")' ersetzt werden.
623 
624     Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt,
625     welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE
626     konstruiert wurde und bereits ein aufgezeichnetes Statement vorhanden
627     ist.
628 
629 
630     [Anmerkung]
631 
632     Diese Methode wird typischerweise aus den Execute-Methoden der
633     <SfxSlot>s von den Applikationsentwicklern gerufen.
634 
635 
636     [Querverweise]
637 
638     <SfxMacro::Replace(SfxMacroStatement*)>
639     <SfxMacro::Record(SfxMacroStatement*)>
640     <SfxMacro::GetLastStatement()const>
641 */
642 
643 {
644     DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, "invalid call to non-recording SfxMacro" );
645     DBG_ASSERT( pImp->aList.Count(), "no replaceable statement available" );
646     pImp->aList.Remove( pImp->aList.Count() - 1 );
647 }
648 
649 //--------------------------------------------------------------------
650 
651 const SfxMacroStatement* SfxMacro::GetLastStatement() const
652 
653 /*  [Beschreibung]
654 
655     Mit dieser Methode kann auf das jeweils zuletzt aufgezeichnete Statement
656     lesend zugegriffen werden. Zusammen mit der Methode
657     <SfxMacro::Replace(SfxMacroStatement*)> ergibt sich dadurch die
658     M"oglichkeit, Statements zusammenzufassen.
659 
660     Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt,
661     welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE
662     konstruiert wurde.
663 
664 
665     [Querverweise]
666 
667     <SfxMacro::Record(SfxMacroStatement*)>
668     <SfxMacro::Replace(SfxMacroStatement*)>
669 */
670 
671 {
672     DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, "invalid call to non-recording SfxMacro" );
673     if ( pImp->aList.Count() )
674         return pImp->aList.GetObject( pImp->aList.Count() - 1 );
675     return 0;
676 }
677 
678 //--------------------------------------------------------------------
679 
680 String SfxMacro::GenerateSource() const
681 
682 /*  [Beschreibung]
683 
684     Diese Funktion generiert aus den, seit dem Konstruieren der Instanz
685     bis zum Zeitpunkt des Aufrufs dieser Methode aufgezeichneten
686     <SfxMacroStatement>s einen BASIC-Sourcecode, der die Statements,
687     jedoch nicht den Header ('Sub X') und den Footer ('End Sub') enth"alt.
688 
689 
690     [Querverweise]
691 
692     <SfxMacro::Record(SfxMacroStatement*)>
693     <SfxMacro::Repeat(SfxMacroStatement*)>
694 */
695 
696 {
697     DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, "invalid call to non-recording SfxMacro" );
698     String aSource;
699     for ( sal_uInt16 n = 0; n < pImp->aList.Count(); ++n )
700     {
701         aSource += pImp->aList.GetObject(n)->GetStatement();
702         if ( (n+1) < pImp->aList.Count() )
703             aSource += DEFINE_CONST_UNICODE("\n");
704     }
705 
706     return aSource;
707 }
708 
709