xref: /AOO41X/main/basic/source/sample/object.cxx (revision e1f63238eb022c8a12b30d46a012444ff20e0951)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basic.hxx"
26 #include <tools/errcode.hxx>
27 #include <basic/sbxobj.hxx>
28 #include <basic/sbx.hxx>
29 #ifndef __SBX_SBXVARIABLE_HXX //autogen
30 #include <basic/sbxvar.hxx>
31 #endif
32 #ifndef _MSGBOX_HXX //autogen
33 #include <vcl/msgbox.hxx>
34 #endif
35 
36 #include "object.hxx"
37 #include "collelem.hxx"
38 
39 // Das Sample-Objekt hat folgende Elemente:
40 // 1) Properties:
41 //    Name      der Name
42 //    Value     ein double-Wert, beide bereits als Default drin
43 // 2) Methoden:
44 //    Create    Erzeugen eines neuen Unterelements
45 //    Display   Ausgabe eines Textes
46 //    Square    Argument * Argument
47 //    Event     Aufruf eines Basic-Eventhandlers
48 // 3) Unterobjekte:
49 //    Per Create() kann ein neues Unterelement eingerichtet werden,
50 //    das indiziert werden kann, falls mehrere Objekte gleichen Namens
51 //    existieren.
52 // Diese Implementation ist ein Beispiel fuer eine tabellengesteuerte
53 // Version, die sehr viele Elemente enthalten kann. Die Elemente werden
54 // je nach Bedarf aus der Tabelle in das Objekt uebernommen.
55 // Die Collection findet sich in COLLECTN.*, die in der Collection
56 // enthaltenen Objekte in COLLELEM.*
57 
58 // Das Sample-Objekt wird in ..\app\mybasic.cxx wie folgt in StarBASIC
59 // eingebaut:
60 
61 // MyBasic::MyBasic() : StarBASIC()
62 // {
63 //      AddFactory( new SampleObjectFac() );
64 // }
65 
66 // Das nArgs-Feld eines Tabelleneintrags ist wie folgt verschluesselt:
67 
68 #define _ARGSMASK   0x00FF  // Bis zu 255 Argumente
69 #define _RWMASK     0x0F00  // Maske fuer R/W-Bits
70 #define _TYPEMASK   0xF000  // Maske fuer den Typ des Eintrags
71 
72 #define _READ       0x0100  // kann gelesen werden
73 #define _BWRITE     0x0200  // kann as Lvalue verwendet werden
74 #define _LVALUE     _BWRITE  // kann as Lvalue verwendet werden
75 #define _READWRITE  0x0300  // beides
76 #define _OPT        0x0400  // sal_True: optionaler Parameter
77 #define _METHOD     0x1000  // Masken-Bit fuer eine Methode
78 #define _PROPERTY   0x2000  // Masken-Bit fuer eine Property
79 #define _COLL       0x4000  // Masken-Bit fuer eine Collection
80                             // Kombination von oberen Bits:
81 #define _FUNCTION   0x1100  // Maske fuer Function
82 #define _LFUNCTION  0x1300  // Maske fuer Function, die auch als Lvalue geht
83 #define _ROPROP     0x2100  // Maske Read Only-Property
84 #define _WOPROP     0x2200  // Maske Write Only-Property
85 #define _RWPROP     0x2300  // Maske Read/Write-Property
86 #define _COLLPROP   0x4100  // Maske Read-Collection-Element
87 
88 #define COLLNAME    "Elements"  // Name der Collection, hier mal hart verdrahtet
89 
90 SampleObject::Methods SampleObject::aMethods[] = {
91 // Eine Sample-Methode (der Returnwert ist SbxNULL)
92 { "Display", SbxEMPTY, &SampleObject::Display, 1 | _FUNCTION },
93     // Ein Named Parameter
94     { "message", SbxSTRING, NULL, 0 },
95 // Eine Sample-Funktion
96 { "Square", SbxDOUBLE, &SampleObject::Square, 1 | _FUNCTION },
97     // Ein Named Parameter
98     { "value", SbxDOUBLE, NULL, 0 },
99 //  Basic-Callback
100 { "Event", SbxEMPTY, &SampleObject::Event, 1 | _FUNCTION },
101     // Ein Named Parameter
102     { "event", SbxSTRING, NULL, 0 },
103 //  Element erzeugen
104 { "Create", SbxEMPTY, &SampleObject::Create, 1 | _FUNCTION },
105     // Ein Named Parameter
106     { "name", SbxSTRING, NULL, 0 },
107 
108 { NULL, SbxNULL, NULL, -1 }};  // Tabellenende
109 
SampleObject(const String & rClass)110 SampleObject::SampleObject( const String& rClass ) : SbxObject( rClass )
111 {
112     SetName( String( RTL_CONSTASCII_USTRINGPARAM("Sample") ) );
113     PutDouble( 1.0 );   // Startwert fuer Value
114 }
115 
116 // Suche nach einem Element:
117 // Hier wird linear durch die Methodentabelle gegangen, bis eine
118 // passende Methode gefunden wurde.
119 // Wenn die Methode/Property nicht gefunden wurde, nur NULL ohne
120 // Fehlercode zurueckliefern, da so auch eine ganze Chain von
121 // Objekten nach der Methode/Property befragt werden kann.
122 
Find(const String & rName,SbxClassType t)123 SbxVariable* SampleObject::Find( const String& rName, SbxClassType t )
124 {
125     // Ist das Element bereits vorhanden?
126     SbxVariable* pRes = SbxObject::Find( rName, t );
127     if( !pRes && t != SbxCLASS_OBJECT )
128     {
129         // sonst suchen
130         Methods* p = aMethods;
131         short nIndex = 0;
132         sal_Bool bFound = sal_False;
133         while( p->nArgs != -1 )
134         {
135             if( rName.EqualsIgnoreCaseAscii( p->pName ) )
136             {
137                 bFound = sal_True; break;
138             }
139             nIndex += ( p->nArgs & _ARGSMASK ) + 1;
140             p = aMethods + nIndex;
141         }
142         if( bFound )
143         {
144             // Args-Felder isolieren:
145             short nAccess = ( p->nArgs & _RWMASK ) >> 8;
146             short nType   = ( p->nArgs & _TYPEMASK );
147             String aName_ = String::CreateFromAscii( p->pName );
148             SbxClassType eCT = SbxCLASS_OBJECT;
149             if( nType & _PROPERTY )
150                 eCT = SbxCLASS_PROPERTY;
151             else if( nType & _METHOD )
152                 eCT = SbxCLASS_METHOD;
153             pRes = Make( aName_, eCT, p->eType );
154             // Wir setzen den Array-Index + 1, da ja noch andere
155             // Standard-Properties existieren, die auch aktiviert
156             // werden muessen.
157             pRes->SetUserData( nIndex + 1 );
158             pRes->SetFlags( nAccess );
159         }
160     }
161     return pRes;
162 }
163 
164 // Aktivierung eines Elements oder Anfordern eines Infoblocks
165 
SFX_NOTIFY(SfxBroadcaster & rBC,const TypeId & rBCT,const SfxHint & rHint,const TypeId & rHT)166 void SampleObject::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCT,
167                              const SfxHint& rHint, const TypeId& rHT )
168 {
169     const SbxHint* pHint = PTR_CAST(SbxHint,&rHint);
170     if( pHint )
171     {
172         SbxVariable* pVar = pHint->GetVar();
173         SbxArray* pPar_ = pVar->GetParameters();
174         sal_uInt16 nIndex = (sal_uInt16) pVar->GetUserData();
175         // kein Index: weiterreichen!
176         if( nIndex )
177         {
178             sal_uIntPtr t = pHint->GetId();
179             if( t == SBX_HINT_INFOWANTED )
180                 pVar->SetInfo( GetInfo( (short) pVar->GetUserData() ) );
181             else
182             {
183                 sal_Bool bWrite = sal_False;
184                 if( t == SBX_HINT_DATACHANGED )
185                     bWrite = sal_True;
186                 if( t == SBX_HINT_DATAWANTED || bWrite )
187                 {
188                     // Parameter-Test fuer Methoden:
189                     sal_uInt16 nPar = aMethods[ --nIndex ].nArgs & 0x00FF;
190                     // Element 0 ist der Returnwert
191                     if( ( !pPar_ && nPar )
192                      || ( pPar_->Count() != nPar+1 ) )
193                         SetError( SbxERR_WRONG_ARGS );
194                     // Alles klar, man kann den Call ausfuehren
195                     else
196                     {
197                         (this->*(aMethods[ nIndex ].pFunc))( pVar, pPar_, bWrite );
198                     }
199                 }
200             }
201         }
202         SbxObject::SFX_NOTIFY( rBC, rBCT, rHint, rHT );
203     }
204 }
205 
206 // Zusammenbau der Infostruktur fuer einzelne Elemente
207 
GetInfo(short nIdx)208 SbxInfo* SampleObject::GetInfo( short nIdx )
209 {
210     Methods* p = &aMethods[ nIdx ];
211     // Wenn mal eine Hilfedatei zur Verfuegung steht:
212     // SbxInfo* pInfo_ = new SbxInfo( Hilfedateiname, p->nHelpId );
213     SbxInfo* pInfo_ = new SbxInfo;
214     short nPar = p->nArgs & _ARGSMASK;
215     for( short i = 0; i < nPar; i++ )
216     {
217         p++;
218         String aName_ = String::CreateFromAscii( p->pName );
219         sal_uInt16 nFlags_ = ( p->nArgs >> 8 ) & 0x03;
220         if( p->nArgs & _OPT )
221             nFlags_ |= SBX_OPTIONAL;
222         pInfo_->AddParam( aName_, p->eType, nFlags_ );
223     }
224     return pInfo_;
225 }
226 
227 ////////////////////////////////////////////////////////////////////////////
228 
229 // Properties und Methoden legen beim Get (bPut = sal_False) den Returnwert
230 // im Element 0 des Argv ab; beim Put (bPut = sal_True) wird der Wert aus
231 // Element 0 gespeichert.
232 
233 // Die Methoden:
234 
Display(SbxVariable *,SbxArray * pPar_,sal_Bool)235 void SampleObject::Display( SbxVariable*, SbxArray* pPar_, sal_Bool )
236 {
237     // GetString() loest u.U. auch einen Error aus!
238     String s( pPar_->Get( 1 )->GetString() );
239     if( !IsError() )
240         InfoBox( NULL, s ).Execute();
241 }
242 
Square(SbxVariable * pVar,SbxArray * pPar_,sal_Bool)243 void SampleObject::Square( SbxVariable* pVar, SbxArray* pPar_, sal_Bool )
244 {
245     double n = pPar_->Get( 1 )->GetDouble();
246     pVar->PutDouble( n * n );
247 }
248 
249 // Callback nach BASIC:
250 
Event(SbxVariable *,SbxArray * pPar_,sal_Bool)251 void SampleObject::Event( SbxVariable*, SbxArray* pPar_, sal_Bool )
252 {
253     Call( pPar_->Get( 1 )->GetString(), NULL );
254 }
255 
256 // Neues Element anlegen
257 
Create(SbxVariable * pVar,SbxArray * pPar_,sal_Bool)258 void SampleObject::Create( SbxVariable* pVar, SbxArray* pPar_, sal_Bool )
259 {
260     pVar->PutObject(
261         MakeObject( pPar_->Get( 1 )->GetString(), String( RTL_CONSTASCII_USTRINGPARAM("SampleElement") ) ) );
262 }
263 
264 // Die Factory legt unsere beiden Objekte an.
265 
CreateObject(const String & rClass)266 SbxObject* SampleObjectFac::CreateObject( const String& rClass )
267 {
268     if( rClass.EqualsIgnoreCaseAscii( "SampleObject" ) )
269         return new SampleObject( rClass );
270     if( rClass.EqualsIgnoreCaseAscii( "SampleElement" ) )
271         return new SampleElement( rClass );
272     return NULL;
273 }
274 
275