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