xref: /AOO41X/main/basic/source/sbx/sbxobj.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/stream.hxx>
27 #include <vcl/sound.hxx>
28 #include <basic/sbx.hxx>
29 #include <basic/sbxbase.hxx>
30 #include "sbxres.hxx"
31 #include <svl/brdcst.hxx>
32 
33 TYPEINIT1(SbxMethod,SbxVariable)
34 TYPEINIT1(SbxProperty,SbxVariable)
35 TYPEINIT2(SbxObject,SbxVariable,SfxListener)
36 
37 static const char* pNameProp;               // Name-Property
38 static const char* pParentProp;             // Parent-Property
39 
40 static sal_uInt16 nNameHash = 0, nParentHash = 0;
41 
42 /////////////////////////////////////////////////////////////////////////
43 
44 /////////////////////////////////////////////////////////////////////////
45 
SbxObject(const XubString & rClass)46 SbxObject::SbxObject( const XubString& rClass )
47          : SbxVariable( SbxOBJECT ), aClassName( rClass )
48 {
49     aData.pObj = this;
50     if( !nNameHash )
51     {
52         pNameProp = GetSbxRes( STRING_NAMEPROP );
53         pParentProp = GetSbxRes( STRING_PARENTPROP );
54         nNameHash = MakeHashCode( String::CreateFromAscii( pNameProp ) );
55         nParentHash = MakeHashCode( String::CreateFromAscii( pParentProp ) );
56     }
57     SbxObject::Clear();
58     SbxObject::SetName( rClass );
59 }
60 
SbxObject(const SbxObject & rObj)61 SbxObject::SbxObject( const SbxObject& rObj )
62     : SvRefBase( rObj ), SbxVariable( rObj.GetType() ),
63       SfxListener( rObj )
64 {
65     *this = rObj;
66 }
67 
operator =(const SbxObject & r)68 SbxObject& SbxObject::operator=( const SbxObject& r )
69 {
70     if( &r != this )
71     {
72         SbxVariable::operator=( r );
73         aClassName = r.aClassName;
74         pMethods   = new SbxArray;
75         pProps     = new SbxArray;
76         pObjs      = new SbxArray( SbxOBJECT );
77         // Die Arrays werden kopiert, die Inhalte uebernommen
78         *pMethods  = *r.pMethods;
79         *pProps    = *r.pProps;
80         *pObjs     = *r.pObjs;
81         // Da die Variablen uebernommen wurden, ist dies OK
82         pDfltProp  = r.pDfltProp;
83         SetName( r.GetName() );
84         SetFlags( r.GetFlags() );
85         SetModified( sal_True );
86     }
87     return *this;
88 }
89 
CheckParentsOnDelete(SbxObject * pObj,SbxArray * p)90 static void CheckParentsOnDelete( SbxObject* pObj, SbxArray* p )
91 {
92     for( sal_uInt16 i = 0; i < p->Count(); i++ )
93     {
94         SbxVariableRef& rRef = p->GetRef( i );
95         if( rRef->IsBroadcaster() )
96             pObj->EndListening( rRef->GetBroadcaster(), sal_True );
97         // Hat das Element mehr als eine Referenz und noch einen Listener?
98         if( rRef->GetRefCount() > 1 )
99         {
100             rRef->SetParent( NULL );
101             DBG_ASSERT( !rRef->IsBroadcaster() || rRef->GetBroadcaster().GetListenerCount(), "Object element with dangling parent" );
102         }
103     }
104 }
105 
~SbxObject()106 SbxObject::~SbxObject()
107 {
108     CheckParentsOnDelete( this, pProps );
109     CheckParentsOnDelete( this, pMethods );
110     CheckParentsOnDelete( this, pObjs );
111 
112     // avoid handling in ~SbxVariable as SBX_DIM_AS_NEW == SBX_GBLSEARCH
113     ResetFlag( SBX_DIM_AS_NEW );
114 }
115 
GetType() const116 SbxDataType SbxObject::GetType() const
117 {
118     return SbxOBJECT;
119 }
120 
GetClass() const121 SbxClassType SbxObject::GetClass() const
122 {
123     return SbxCLASS_OBJECT;
124 }
125 
Clear()126 void SbxObject::Clear()
127 {
128     pMethods   = new SbxArray;
129     pProps     = new SbxArray;
130     pObjs      = new SbxArray( SbxOBJECT );
131     SbxVariable* p;
132     p = Make( String::CreateFromAscii( pNameProp ), SbxCLASS_PROPERTY, SbxSTRING );
133     p->SetFlag( SBX_DONTSTORE );
134     p = Make( String::CreateFromAscii( pParentProp ), SbxCLASS_PROPERTY, SbxOBJECT );
135     p->ResetFlag( SBX_WRITE );
136     p->SetFlag( SBX_DONTSTORE );
137     pDfltProp  = NULL;
138     SetModified( sal_False );
139 }
140 
SFX_NOTIFY(SfxBroadcaster &,const TypeId &,const SfxHint & rHint,const TypeId &)141 void SbxObject::SFX_NOTIFY( SfxBroadcaster&, const TypeId&,
142                             const SfxHint& rHint, const TypeId& )
143 {
144     const SbxHint* p = PTR_CAST(SbxHint,&rHint);
145     if( p )
146     {
147         sal_uIntPtr nId = p->GetId();
148         sal_Bool bRead  = sal_Bool( nId == SBX_HINT_DATAWANTED );
149         sal_Bool bWrite = sal_Bool( nId == SBX_HINT_DATACHANGED );
150         SbxVariable* pVar = p->GetVar();
151         if( bRead || bWrite )
152         {
153             XubString aVarName( pVar->GetName() );
154             sal_uInt16 nHash_ = MakeHashCode( aVarName );
155             if( nHash_ == nNameHash
156              && aVarName.EqualsIgnoreCaseAscii( pNameProp ) )
157             {
158                 if( bRead )
159                     pVar->PutString( GetName() );
160                 else
161                     SetName( pVar->GetString() );
162             }
163             else if( nHash_ == nParentHash
164              && aVarName.EqualsIgnoreCaseAscii( pParentProp ) )
165             {
166                 SbxObject* p_ = GetParent();
167                 if( !p_ )
168                     p_ = this;
169                 pVar->PutObject( p_ );
170             }
171         }
172     }
173 }
174 
IsClass(const XubString & rName) const175 sal_Bool SbxObject::IsClass( const XubString& rName ) const
176 {
177     return sal_Bool( aClassName.EqualsIgnoreCaseAscii( rName ) );
178 }
179 
FindUserData(sal_uInt32 nData)180 SbxVariable* SbxObject::FindUserData( sal_uInt32 nData )
181 {
182     if( !GetAll( SbxCLASS_DONTCARE ) )
183         return NULL;
184 
185     SbxVariable* pRes = pMethods->FindUserData( nData );
186     if( !pRes )
187         pRes = pProps->FindUserData( nData );
188     if( !pRes )
189         pRes = pObjs->FindUserData( nData );
190     // Search in den Parents?
191     if( !pRes && IsSet( SBX_GBLSEARCH ) )
192     {
193         SbxObject* pCur = this;
194         while( !pRes && pCur->pParent )
195         {
196             // Ich selbst bin schon durchsucht worden!
197             sal_uInt16 nOwn = pCur->GetFlags();
198             pCur->ResetFlag( SBX_EXTSEARCH );
199             // Ich suche bereits global!
200             sal_uInt16 nPar = pCur->pParent->GetFlags();
201             pCur->pParent->ResetFlag( SBX_GBLSEARCH );
202             pRes = pCur->pParent->FindUserData( nData );
203             pCur->SetFlags( nOwn );
204             pCur->pParent->SetFlags( nPar );
205             pCur = pCur->pParent;
206         }
207     }
208     return pRes;
209 }
210 
Find(const XubString & rName,SbxClassType t)211 SbxVariable* SbxObject::Find( const XubString& rName, SbxClassType t )
212 {
213 #ifdef DBG_UTIL
214     static sal_uInt16 nLvl = 0;
215     static const char* pCls[] =
216     { "DontCare","Array","Value","Variable","Method","Property","Object" };
217     ByteString aNameStr1( (const UniString&)rName, RTL_TEXTENCODING_ASCII_US );
218     ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
219     DbgOutf( "SBX: Search %.*s %s %s in %s",
220         nLvl++, "                              ",
221         ( t >= SbxCLASS_DONTCARE && t <= SbxCLASS_OBJECT )
222          ? pCls[ t-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() );
223 #endif
224 
225     if( !GetAll( t ) )
226         return NULL;
227     SbxVariable* pRes = NULL;
228     pObjs->SetFlag( SBX_EXTSEARCH );
229     if( t == SbxCLASS_DONTCARE )
230     {
231         pRes = pMethods->Find( rName, SbxCLASS_METHOD );
232         if( !pRes )
233             pRes = pProps->Find( rName, SbxCLASS_PROPERTY );
234         if( !pRes )
235             pRes = pObjs->Find( rName, t );
236     }
237     else
238     {
239         SbxArray* pArray = NULL;
240         switch( t )
241         {
242             case SbxCLASS_VARIABLE:
243             case SbxCLASS_PROPERTY: pArray = pProps;    break;
244             case SbxCLASS_METHOD:   pArray = pMethods;  break;
245             case SbxCLASS_OBJECT:   pArray = pObjs;     break;
246             default:
247                 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
248         }
249         if( pArray )
250             pRes = pArray->Find( rName, t );
251     }
252     // Extended Search im Objekt-Array?
253     // Fuer Objekte und DontCare ist das Objektarray bereits
254     // durchsucht worden
255     if( !pRes && ( t == SbxCLASS_METHOD || t == SbxCLASS_PROPERTY ) )
256         pRes = pObjs->Find( rName, t );
257     // Search in den Parents?
258     if( !pRes && IsSet( SBX_GBLSEARCH ) )
259     {
260         SbxObject* pCur = this;
261         while( !pRes && pCur->pParent )
262         {
263             // Ich selbst bin schon durchsucht worden!
264             sal_uInt16 nOwn = pCur->GetFlags();
265             pCur->ResetFlag( SBX_EXTSEARCH );
266             // Ich suche bereits global!
267             sal_uInt16 nPar = pCur->pParent->GetFlags();
268             pCur->pParent->ResetFlag( SBX_GBLSEARCH );
269             pRes = pCur->pParent->Find( rName, t );
270             pCur->SetFlags( nOwn );
271             pCur->pParent->SetFlags( nPar );
272             pCur = pCur->pParent;
273         }
274     }
275 #ifdef DBG_UTIL
276     nLvl--;
277     if( pRes )
278     {
279         ByteString aNameStr3( (const UniString&)rName, RTL_TEXTENCODING_ASCII_US );
280         ByteString aNameStr4( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
281         DbgOutf( "SBX: Found %.*s %s in %s",
282             nLvl, "                              ", aNameStr3.GetBuffer(), aNameStr4.GetBuffer() );
283     }
284 #endif
285     return pRes;
286 }
287 
288 // Kurzform: Die Parent-Kette wird durchsucht
289 // Das ganze rekursiv, da Call() ueberladen sein kann
290 // Qualified Names sind zugelassen
291 
Call(const XubString & rName,SbxArray * pParam)292 sal_Bool SbxObject::Call( const XubString& rName, SbxArray* pParam )
293 {
294     SbxVariable* pMeth = FindQualified( rName, SbxCLASS_DONTCARE);
295     if( pMeth && pMeth->ISA(SbxMethod) )
296     {
297         // FindQualified() koennte schon zugeschlagen haben!
298         if( pParam )
299             pMeth->SetParameters( pParam );
300         pMeth->Broadcast( SBX_HINT_DATAWANTED );
301         pMeth->SetParameters( NULL );
302         return sal_True;
303     }
304     SetError( SbxERR_NO_METHOD );
305     return sal_False;
306 }
307 
GetDfltProperty()308 SbxProperty* SbxObject::GetDfltProperty()
309 {
310     if ( !pDfltProp && aDfltPropName.Len() )
311     {
312         pDfltProp = (SbxProperty*) Find( aDfltPropName, SbxCLASS_PROPERTY );
313         if( !pDfltProp )
314             pDfltProp = (SbxProperty*) Make( aDfltPropName, SbxCLASS_PROPERTY, SbxVARIANT );
315     }
316     return pDfltProp;
317 }
SetDfltProperty(const XubString & rName)318 void SbxObject::SetDfltProperty( const XubString& rName )
319 {
320     if ( rName != aDfltPropName )
321         pDfltProp = NULL;
322     aDfltPropName = rName;
323     SetModified( sal_True );
324 }
325 
SetDfltProperty(SbxProperty * p)326 void SbxObject::SetDfltProperty( SbxProperty* p )
327 {
328     if( p )
329     {
330         sal_uInt16 n;
331         SbxArray* pArray = FindVar( p, n );
332         pArray->Put( p, n );
333         if( p->GetParent() != this )
334             p->SetParent( this );
335         Broadcast( SBX_HINT_OBJECTCHANGED );
336     }
337     pDfltProp = p;
338     SetModified( sal_True );
339 }
340 
341 // Suchen einer bereits vorhandenen Variablen. Falls sie gefunden wurde,
342 // wird der Index gesetzt, sonst wird der Count des Arrays geliefert.
343 // In jedem Fall wird das korrekte Array geliefert.
344 
FindVar(SbxVariable * pVar,sal_uInt16 & nArrayIdx)345 SbxArray* SbxObject::FindVar( SbxVariable* pVar, sal_uInt16& nArrayIdx )
346 {
347     SbxArray* pArray = NULL;
348     if( pVar ) switch( pVar->GetClass() )
349     {
350         case SbxCLASS_VARIABLE:
351         case SbxCLASS_PROPERTY: pArray = pProps;    break;
352         case SbxCLASS_METHOD:   pArray = pMethods;  break;
353         case SbxCLASS_OBJECT:   pArray = pObjs;     break;
354         default:
355             DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
356     }
357     if( pArray )
358     {
359         nArrayIdx = pArray->Count();
360         // ist die Variable per Name vorhanden?
361         pArray->ResetFlag( SBX_EXTSEARCH );
362         SbxVariable* pOld = pArray->Find( pVar->GetName(), pVar->GetClass() );
363         if( pOld )
364           for( sal_uInt16 i = 0; i < pArray->Count(); i++ )
365         {
366             SbxVariableRef& rRef = pArray->GetRef( i );
367             if( (SbxVariable*) rRef == pOld )
368             {
369                 nArrayIdx = i; break;
370             }
371         }
372     }
373     return pArray;
374 }
375 
376 // Falls ein neues Objekt eingerichtet wird, wird es, falls es bereits
377 // eines mit diesem Namen gibt, indiziert.
378 
Make(const XubString & rName,SbxClassType ct,SbxDataType dt)379 SbxVariable* SbxObject::Make( const XubString& rName, SbxClassType ct, SbxDataType dt )
380 {
381     // Ist das Objekt bereits vorhanden?
382     SbxArray* pArray = NULL;
383     switch( ct )
384     {
385         case SbxCLASS_VARIABLE:
386         case SbxCLASS_PROPERTY: pArray = pProps;    break;
387         case SbxCLASS_METHOD:   pArray = pMethods;  break;
388         case SbxCLASS_OBJECT:   pArray = pObjs;     break;
389         default:
390             DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
391     }
392     if( !pArray )
393         return NULL;
394     // Collections duerfen gleichnamige Objekte enthalten
395     if( !( ct == SbxCLASS_OBJECT && ISA(SbxCollection) ) )
396     {
397         SbxVariable* pRes = pArray->Find( rName, ct );
398         if( pRes )
399         {
400 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus
401 #ifdef DBG_UTIL
402             if( pRes->GetHashCode() != nNameHash
403              && pRes->GetHashCode() != nParentHash )
404             {
405                 XubString aMsg( "SBX-Element \"" );
406                 aMsg += pRes->GetName();
407                 aMsg += "\"\n in Objekt \"";
408                 aMsg += GetName();
409                 aMsg += "\" bereits vorhanden";
410                 DbgError( (const char*)aMsg.GetStr() );
411             }
412 #endif
413 */
414             return pRes;
415         }
416     }
417     SbxVariable* pVar = NULL;
418     switch( ct )
419     {
420         case SbxCLASS_VARIABLE:
421         case SbxCLASS_PROPERTY:
422             pVar = new SbxProperty( rName, dt );
423             break;
424         case SbxCLASS_METHOD:
425             pVar = new SbxMethod( rName, dt );
426             break;
427         case SbxCLASS_OBJECT:
428             pVar = CreateObject( rName );
429             break;
430         default: break;
431     }
432     pVar->SetParent( this );
433     pArray->Put( pVar, pArray->Count() );
434     SetModified( sal_True );
435     // Das Objekt lauscht immer
436     StartListening( pVar->GetBroadcaster(), sal_True );
437     Broadcast( SBX_HINT_OBJECTCHANGED );
438     return pVar;
439 }
440 
MakeObject(const XubString & rName,const XubString & rClass)441 SbxObject* SbxObject::MakeObject( const XubString& rName, const XubString& rClass )
442 {
443     // Ist das Objekt bereits vorhanden?
444     if( !ISA(SbxCollection) )
445     {
446         SbxVariable* pRes = pObjs->Find( rName, SbxCLASS_OBJECT );
447         if( pRes )
448         {
449 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus
450 #ifdef DBG_UTIL
451             if( pRes->GetHashCode() != nNameHash
452              && pRes->GetHashCode() != nParentHash )
453             {
454                 XubString aMsg( "SBX-Objekt \"" );
455                 aMsg += pRes->GetName();
456                 aMsg += "\"\n in Objekt \"";
457                 aMsg += GetName();
458                 aMsg += "\" bereits vorhanden";
459                 DbgError( (const char*)aMsg.GetStr() );
460             }
461 #endif
462 */
463             return PTR_CAST(SbxObject,pRes);
464         }
465     }
466     SbxObject* pVar = CreateObject( rClass );
467     if( pVar )
468     {
469         pVar->SetName( rName );
470         pVar->SetParent( this );
471         pObjs->Put( pVar, pObjs->Count() );
472         SetModified( sal_True );
473         // Das Objekt lauscht immer
474         StartListening( pVar->GetBroadcaster(), sal_True );
475         Broadcast( SBX_HINT_OBJECTCHANGED );
476     }
477     return pVar;
478 }
479 
Insert(SbxVariable * pVar)480 void SbxObject::Insert( SbxVariable* pVar )
481 {
482     sal_uInt16 nIdx;
483     SbxArray* pArray = FindVar( pVar, nIdx );
484     if( pArray )
485     {
486         // Hinein damit. Man sollte allerdings auf die Pointer aufpassen!
487         if( nIdx < pArray->Count() )
488         {
489             // dann gibt es dieses Element bereits
490             // Bei Collections duerfen gleichnamige Objekte hinein
491             if( pArray == pObjs && ISA(SbxCollection) )
492                 nIdx = pArray->Count();
493             else
494             {
495                 SbxVariable* pOld = pArray->Get( nIdx );
496                 // schon drin: ueberschreiben
497                 if( pOld == pVar )
498                     return;
499 
500 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus
501 #ifdef DBG_UTIL
502                 if( pOld->GetHashCode() != nNameHash
503                  && pOld->GetHashCode() != nParentHash )
504                 {
505                     XubString aMsg( "SBX-Element \"" );
506                     aMsg += pVar->GetName();
507                     aMsg += "\"\n in Objekt \"";
508                     aMsg += GetName();
509                     aMsg += "\" bereits vorhanden";
510                     DbgError( (const char*)aMsg.GetStr() );
511                 }
512 #endif
513 */
514                 EndListening( pOld->GetBroadcaster(), sal_True );
515                 if( pVar->GetClass() == SbxCLASS_PROPERTY )
516                 {
517                     if( pOld == pDfltProp )
518                         pDfltProp = (SbxProperty*) pVar;
519                 }
520             }
521         }
522         StartListening( pVar->GetBroadcaster(), sal_True );
523         pArray->Put( pVar, nIdx );
524         if( pVar->GetParent() != this )
525             pVar->SetParent( this );
526         SetModified( sal_True );
527         Broadcast( SBX_HINT_OBJECTCHANGED );
528 #ifdef DBG_UTIL
529     static const char* pCls[] =
530     { "DontCare","Array","Value","Variable","Method","Property","Object" };
531     XubString aVarName( pVar->GetName() );
532     if ( !aVarName.Len() && pVar->ISA(SbxObject) )
533         aVarName = PTR_CAST(SbxObject,pVar)->GetClassName();
534     ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US );
535     ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
536     DbgOutf( "SBX: Insert %s %s in %s",
537         ( pVar->GetClass() >= SbxCLASS_DONTCARE &&
538           pVar->GetClass() <= SbxCLASS_OBJECT )
539             ? pCls[ pVar->GetClass()-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() );
540 #endif
541     }
542 }
543 
544 // AB 23.4.1997, Optimierung, Einfuegen ohne Ueberpruefung auf doppelte
545 // Eintraege und ohne Broadcasts, wird nur in SO2/auto.cxx genutzt
QuickInsert(SbxVariable * pVar)546 void SbxObject::QuickInsert( SbxVariable* pVar )
547 {
548     SbxArray* pArray = NULL;
549     if( pVar )
550     {
551         switch( pVar->GetClass() )
552         {
553             case SbxCLASS_VARIABLE:
554             case SbxCLASS_PROPERTY: pArray = pProps;    break;
555             case SbxCLASS_METHOD:   pArray = pMethods;  break;
556             case SbxCLASS_OBJECT:   pArray = pObjs;     break;
557             default:
558                 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
559         }
560     }
561     if( pArray )
562     {
563         StartListening( pVar->GetBroadcaster(), sal_True );
564         pArray->Put( pVar, pArray->Count() );
565         if( pVar->GetParent() != this )
566             pVar->SetParent( this );
567         SetModified( sal_True );
568 #ifdef DBG_UTIL
569     static const char* pCls[] =
570     { "DontCare","Array","Value","Variable","Method","Property","Object" };
571     XubString aVarName( pVar->GetName() );
572     if ( !aVarName.Len() && pVar->ISA(SbxObject) )
573         aVarName = PTR_CAST(SbxObject,pVar)->GetClassName();
574     ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US );
575     ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
576     DbgOutf( "SBX: Insert %s %s in %s",
577         ( pVar->GetClass() >= SbxCLASS_DONTCARE &&
578           pVar->GetClass() <= SbxCLASS_OBJECT )
579             ? pCls[ pVar->GetClass()-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() );
580 #endif
581     }
582 }
583 
584 // AB 23.3.1997, Spezial-Methode, gleichnamige Controls zulassen
VCPtrInsert(SbxVariable * pVar)585 void SbxObject::VCPtrInsert( SbxVariable* pVar )
586 {
587     SbxArray* pArray = NULL;
588     if( pVar )
589     {
590         switch( pVar->GetClass() )
591         {
592             case SbxCLASS_VARIABLE:
593             case SbxCLASS_PROPERTY: pArray = pProps;    break;
594             case SbxCLASS_METHOD:   pArray = pMethods;  break;
595             case SbxCLASS_OBJECT:   pArray = pObjs;     break;
596             default:
597                 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
598         }
599     }
600     if( pArray )
601     {
602         StartListening( pVar->GetBroadcaster(), sal_True );
603         pArray->Put( pVar, pArray->Count() );
604         if( pVar->GetParent() != this )
605             pVar->SetParent( this );
606         SetModified( sal_True );
607         Broadcast( SBX_HINT_OBJECTCHANGED );
608     }
609 }
610 
Remove(const XubString & rName,SbxClassType t)611 void SbxObject::Remove( const XubString& rName, SbxClassType t )
612 {
613     Remove( SbxObject::Find( rName, t ) );
614 }
615 
Remove(SbxVariable * pVar)616 void SbxObject::Remove( SbxVariable* pVar )
617 {
618     sal_uInt16 nIdx;
619     SbxArray* pArray = FindVar( pVar, nIdx );
620     if( pArray && nIdx < pArray->Count() )
621     {
622 #ifdef DBG_UTIL
623     XubString aVarName( pVar->GetName() );
624     if ( !aVarName.Len() && pVar->ISA(SbxObject) )
625         aVarName = PTR_CAST(SbxObject,pVar)->GetClassName();
626     ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US );
627     ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
628 #endif
629         SbxVariableRef pVar_ = pArray->Get( nIdx );
630         if( pVar_->IsBroadcaster() )
631             EndListening( pVar_->GetBroadcaster(), sal_True );
632         if( (SbxVariable*) pVar_ == pDfltProp )
633             pDfltProp = NULL;
634         pArray->Remove( nIdx );
635         if( pVar_->GetParent() == this )
636             pVar_->SetParent( NULL );
637         SetModified( sal_True );
638         Broadcast( SBX_HINT_OBJECTCHANGED );
639     }
640 }
641 
642 // AB 23.3.1997, Loeschen per Pointer fuer Controls (doppelte Namen!)
VCPtrRemove(SbxVariable * pVar)643 void SbxObject::VCPtrRemove( SbxVariable* pVar )
644 {
645     sal_uInt16 nIdx;
646     // Neu FindVar-Methode, sonst identisch mit normaler Methode
647     SbxArray* pArray = VCPtrFindVar( pVar, nIdx );
648     if( pArray && nIdx < pArray->Count() )
649     {
650         SbxVariableRef xVar = pArray->Get( nIdx );
651         if( xVar->IsBroadcaster() )
652             EndListening( xVar->GetBroadcaster(), sal_True );
653         if( (SbxVariable*) xVar == pDfltProp )
654             pDfltProp = NULL;
655         pArray->Remove( nIdx );
656         if( xVar->GetParent() == this )
657             xVar->SetParent( NULL );
658         SetModified( sal_True );
659         Broadcast( SBX_HINT_OBJECTCHANGED );
660     }
661 }
662 
663 // AB 23.3.1997, Zugehoerige Spezial-Methode, nur ueber Pointer suchen
VCPtrFindVar(SbxVariable * pVar,sal_uInt16 & nArrayIdx)664 SbxArray* SbxObject::VCPtrFindVar( SbxVariable* pVar, sal_uInt16& nArrayIdx )
665 {
666     SbxArray* pArray = NULL;
667     if( pVar ) switch( pVar->GetClass() )
668     {
669         case SbxCLASS_VARIABLE:
670         case SbxCLASS_PROPERTY: pArray = pProps;    break;
671         case SbxCLASS_METHOD:   pArray = pMethods;  break;
672         case SbxCLASS_OBJECT:   pArray = pObjs;     break;
673         default:
674             DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
675     }
676     if( pArray )
677     {
678         nArrayIdx = pArray->Count();
679         for( sal_uInt16 i = 0; i < pArray->Count(); i++ )
680         {
681             SbxVariableRef& rRef = pArray->GetRef( i );
682             if( (SbxVariable*) rRef == pVar )
683             {
684                 nArrayIdx = i; break;
685             }
686         }
687     }
688     return pArray;
689 }
690 
691 
692 
SetPos(SbxVariable * pVar,sal_uInt16 nPos)693 void SbxObject::SetPos( SbxVariable* pVar, sal_uInt16 nPos )
694 {
695     sal_uInt16 nIdx;
696     SbxArray* pArray = FindVar( pVar, nIdx );
697     if( pArray )
698     {
699         if( nPos >= pArray->Count() )
700             nPos = pArray->Count() - 1;
701         if( nIdx < ( pArray->Count() - 1 ) )
702         {
703             SbxVariableRef refVar = pArray->Get( nIdx );
704             pArray->Remove( nIdx );
705             pArray->Insert( refVar, nPos );
706         }
707     }
708 //  SetModified( sal_True );
709 //  Broadcast( SBX_HINT_OBJECTCHANGED );
710 }
711 
LoadArray(SvStream & rStrm,SbxObject * pThis,SbxArray * pArray)712 static sal_Bool LoadArray( SvStream& rStrm, SbxObject* pThis, SbxArray* pArray )
713 {
714     SbxArrayRef p = (SbxArray*) SbxBase::Load( rStrm );
715     if( !p.Is() )
716         return sal_False;
717     for( sal_uInt16 i = 0; i < p->Count(); i++ )
718     {
719         SbxVariableRef& r = p->GetRef( i );
720         SbxVariable* pVar = r;
721         if( pVar )
722         {
723             pVar->SetParent( pThis );
724             pThis->StartListening( pVar->GetBroadcaster(), sal_True );
725         }
726     }
727     pArray->Merge( p );
728     return sal_True;
729 }
730 
731 // Der Load eines Objekts ist additiv!
732 
LoadData(SvStream & rStrm,sal_uInt16 nVer)733 sal_Bool SbxObject::LoadData( SvStream& rStrm, sal_uInt16 nVer )
734 {
735     // Hilfe fuer das Einlesen alter Objekte: einfach sal_True zurueck,
736     // LoadPrivateData() muss Default-Zustand herstellen
737     if( !nVer )
738         return sal_True;
739 
740     pDfltProp = NULL;
741     if( !SbxVariable::LoadData( rStrm, nVer ) )
742         return sal_False;
743     // Wenn kein fremdes Objekt enthalten ist, uns selbst eintragen
744     if( aData.eType == SbxOBJECT && !aData.pObj )
745         aData.pObj = this;
746     sal_uInt32 nSize;
747     XubString aDfltProp;
748     rStrm.ReadByteString( aClassName, RTL_TEXTENCODING_ASCII_US );
749     rStrm.ReadByteString( aDfltProp, RTL_TEXTENCODING_ASCII_US );
750     sal_uIntPtr nPos = rStrm.Tell();
751     rStrm >> nSize;
752     if( !LoadPrivateData( rStrm, nVer ) )
753         return sal_False;
754     sal_uIntPtr nNewPos = rStrm.Tell();
755     nPos += nSize;
756     DBG_ASSERT( nPos >= nNewPos, "SBX: Zu viele Daten eingelesen" );
757     if( nPos != nNewPos )
758         rStrm.Seek( nPos );
759     if( !LoadArray( rStrm, this, pMethods )
760      || !LoadArray( rStrm, this, pProps )
761      || !LoadArray( rStrm, this, pObjs ) )
762         return sal_False;
763     // Properties setzen
764     if( aDfltProp.Len() )
765         pDfltProp = (SbxProperty*) pProps->Find( aDfltProp, SbxCLASS_PROPERTY );
766     SetModified( sal_False );
767     return sal_True;
768 }
769 
StoreData(SvStream & rStrm) const770 sal_Bool SbxObject::StoreData( SvStream& rStrm ) const
771 {
772     if( !SbxVariable::StoreData( rStrm ) )
773         return sal_False;
774     XubString aDfltProp;
775     if( pDfltProp )
776         aDfltProp = pDfltProp->GetName();
777     rStrm.WriteByteString( aClassName, RTL_TEXTENCODING_ASCII_US );
778     rStrm.WriteByteString( aDfltProp, RTL_TEXTENCODING_ASCII_US );
779     sal_uIntPtr nPos = rStrm.Tell();
780     rStrm << (sal_uInt32) 0L;
781     if( !StorePrivateData( rStrm ) )
782         return sal_False;
783     sal_uIntPtr nNew = rStrm.Tell();
784     rStrm.Seek( nPos );
785     rStrm << (sal_uInt32) ( nNew - nPos );
786     rStrm.Seek( nNew );
787     if( !pMethods->Store( rStrm ) )
788         return sal_False;
789     if( !pProps->Store( rStrm ) )
790         return sal_False;
791     if( !pObjs->Store( rStrm ) )
792         return sal_False;
793     ((SbxObject*) this)->SetModified( sal_False );
794     return sal_True;
795 }
796 
GenerateSource(const XubString & rLinePrefix,const SbxObject *)797 XubString SbxObject::GenerateSource( const XubString &rLinePrefix,
798                                   const SbxObject* )
799 {
800     // Properties in einem String einsammeln
801     XubString aSource;
802     SbxArrayRef xProps( GetProperties() );
803     bool bLineFeed = false;
804     for ( sal_uInt16 nProp = 0; nProp < xProps->Count(); ++nProp )
805     {
806         SbxPropertyRef xProp = (SbxProperty*) xProps->Get(nProp);
807         XubString aPropName( xProp->GetName() );
808         if ( xProp->CanWrite()
809          && !( xProp->GetHashCode() == nNameHash
810             && aPropName.EqualsIgnoreCaseAscii( pNameProp ) ) )
811         {
812             // ausser vor dem ersten Property immer einen Umbruch einfuegen
813             if ( bLineFeed )
814                 aSource.AppendAscii( "\n" );
815             else
816                 bLineFeed = true;
817 
818             aSource += rLinePrefix;
819             aSource += '.';
820             aSource += aPropName;
821             aSource.AppendAscii( " = " );
822 
823             // den Property-Wert textuell darstellen
824             switch ( xProp->GetType() )
825             {
826                 case SbxEMPTY:
827                 case SbxNULL:
828                     // kein Wert
829                     break;
830 
831                 case SbxSTRING:
832                 {
833                     // Strings in Anf"uhrungszeichen
834                     aSource.AppendAscii( "\"" );
835                     aSource += xProp->GetString();
836                     aSource.AppendAscii( "\"" );
837                     break;
838                 }
839 
840                 default:
841                 {
842                     // sonstiges wie z.B. Zahlen direkt
843                     aSource += xProp->GetString();
844                     break;
845                 }
846             }
847         }
848     }
849     return aSource;
850 }
851 
CollectAttrs(const SbxBase * p,XubString & rRes)852 static sal_Bool CollectAttrs( const SbxBase* p, XubString& rRes )
853 {
854     XubString aAttrs;
855     if( p->IsHidden() )
856         aAttrs.AssignAscii( "Hidden" );
857     if( p->IsSet( SBX_EXTSEARCH ) )
858     {
859         if( aAttrs.Len() )
860             aAttrs += ',';
861         aAttrs.AppendAscii( "ExtSearch" );
862     }
863     if( !p->IsVisible() )
864     {
865         if( aAttrs.Len() )
866             aAttrs += ',';
867         aAttrs.AppendAscii( "Invisible" );
868     }
869     if( p->IsSet( SBX_DONTSTORE ) )
870     {
871         if( aAttrs.Len() )
872             aAttrs += ',';
873         aAttrs.AppendAscii( "DontStore" );
874     }
875     if( aAttrs.Len() )
876     {
877         rRes.AssignAscii( " (" );
878         rRes += aAttrs;
879         rRes += ')';
880         return sal_True;
881     }
882     else
883     {
884         rRes.Erase();
885         return sal_False;
886     }
887 }
888 
Dump(SvStream & rStrm,sal_Bool bFill)889 void SbxObject::Dump( SvStream& rStrm, sal_Bool bFill )
890 {
891     // Einr"uckung
892     static sal_uInt16 nLevel = 0;
893     if ( nLevel > 10 )
894     {
895         rStrm << "<too deep>" << endl;
896         return;
897     }
898     ++nLevel;
899     String aIndent;
900     for ( sal_uInt16 n = 1; n < nLevel; ++n )
901         aIndent.AppendAscii( "    " );
902 
903     // ggf. Objekt vervollst"andigen
904     if ( bFill )
905         GetAll( SbxCLASS_DONTCARE );
906 
907     // Daten des Objekts selbst ausgeben
908     ByteString aNameStr( (const UniString&)GetName(), RTL_TEXTENCODING_ASCII_US );
909     ByteString aClassNameStr( (const UniString&)aClassName, RTL_TEXTENCODING_ASCII_US );
910     rStrm << "Object( "
911           << ByteString::CreateFromInt64( (sal_uIntPtr) this ).GetBuffer() << "=='"
912           << ( aNameStr.Len() ? aNameStr.GetBuffer() : "<unnamed>" ) << "', "
913           << "of class '" << aClassNameStr.GetBuffer() << "', "
914           << "counts "
915           << ByteString::CreateFromInt64( GetRefCount() ).GetBuffer()
916           << " refs, ";
917     if ( GetParent() )
918     {
919         ByteString aParentNameStr( (const UniString&)GetName(), RTL_TEXTENCODING_ASCII_US );
920         rStrm << "in parent "
921               << ByteString::CreateFromInt64( (sal_uIntPtr) GetParent() ).GetBuffer()
922               << "=='" << ( aParentNameStr.Len() ? aParentNameStr.GetBuffer() : "<unnamed>" ) << "'";
923     }
924     else
925         rStrm << "no parent ";
926     rStrm << " )" << endl;
927     ByteString aIndentNameStr( (const UniString&)aIndent, RTL_TEXTENCODING_ASCII_US );
928     rStrm << aIndentNameStr.GetBuffer() << "{" << endl;
929 
930     // Flags
931     XubString aAttrs;
932     if( CollectAttrs( this, aAttrs ) )
933     {
934         ByteString aAttrStr( (const UniString&)aAttrs, RTL_TEXTENCODING_ASCII_US );
935         rStrm << aIndentNameStr.GetBuffer() << "- Flags: " << aAttrStr.GetBuffer() << endl;
936     }
937 
938     // Methods
939     rStrm << aIndentNameStr.GetBuffer() << "- Methods:" << endl;
940     for( sal_uInt16 i = 0; i < pMethods->Count(); i++ )
941     {
942         SbxVariableRef& r = pMethods->GetRef( i );
943         SbxVariable* pVar = r;
944         if( pVar )
945         {
946             XubString aLine( aIndent );
947             aLine.AppendAscii( "  - " );
948             aLine += pVar->GetName( SbxNAME_SHORT_TYPES );
949             XubString aAttrs2;
950             if( CollectAttrs( pVar, aAttrs2 ) )
951                 aLine += aAttrs2;
952             if( !pVar->IsA( TYPE(SbxMethod) ) )
953                 aLine.AppendAscii( "  !! Not a Method !!" );
954             rStrm.WriteByteString( aLine, RTL_TEXTENCODING_ASCII_US );
955 
956             // bei Object-Methods auch das Object ausgeben
957             if ( pVar->GetValues_Impl().eType == SbxOBJECT &&
958                     pVar->GetValues_Impl().pObj &&
959                     pVar->GetValues_Impl().pObj != this &&
960                     pVar->GetValues_Impl().pObj != GetParent() )
961             {
962                 rStrm << " contains ";
963                 ((SbxObject*) pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill );
964             }
965             else
966                 rStrm << endl;
967         }
968     }
969 
970     // Properties
971     rStrm << aIndentNameStr.GetBuffer() << "- Properties:" << endl;
972     {
973         for( sal_uInt16 i = 0; i < pProps->Count(); i++ )
974         {
975             SbxVariableRef& r = pProps->GetRef( i );
976             SbxVariable* pVar = r;
977             if( pVar )
978             {
979                 XubString aLine( aIndent );
980                 aLine.AppendAscii( "  - " );
981                 aLine += pVar->GetName( SbxNAME_SHORT_TYPES );
982                 XubString aAttrs3;
983                 if( CollectAttrs( pVar, aAttrs3 ) )
984                     aLine += aAttrs3;
985                 if( !pVar->IsA( TYPE(SbxProperty) ) )
986                     aLine.AppendAscii( "  !! Not a Property !!" );
987                 rStrm.WriteByteString( aLine, RTL_TEXTENCODING_ASCII_US );
988 
989                 // bei Object-Properties auch das Object ausgeben
990                 if ( pVar->GetValues_Impl().eType == SbxOBJECT &&
991                         pVar->GetValues_Impl().pObj &&
992                         pVar->GetValues_Impl().pObj != this &&
993                         pVar->GetValues_Impl().pObj != GetParent() )
994                 {
995                     rStrm << " contains ";
996                     ((SbxObject*) pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill );
997                 }
998                 else
999                     rStrm << endl;
1000             }
1001         }
1002     }
1003 
1004     // Objects
1005     rStrm << aIndentNameStr.GetBuffer() << "- Objects:" << endl;
1006     {
1007         for( sal_uInt16 i = 0; i < pObjs->Count(); i++ )
1008         {
1009             SbxVariableRef& r = pObjs->GetRef( i );
1010             SbxVariable* pVar = r;
1011             if ( pVar )
1012             {
1013                 rStrm << aIndentNameStr.GetBuffer() << "  - Sub";
1014                 if ( pVar->ISA(SbxObject) )
1015                     ((SbxObject*) pVar)->Dump( rStrm, bFill );
1016                 else if ( pVar->ISA(SbxVariable) )
1017                     ((SbxVariable*) pVar)->Dump( rStrm, bFill );
1018             }
1019         }
1020     }
1021 
1022     rStrm << aIndentNameStr.GetBuffer() << "}" << endl << endl;
1023     --nLevel;
1024 }
1025 
GetSvDispatch()1026 SvDispatch* SbxObject::GetSvDispatch()
1027 {
1028     return NULL;
1029 }
1030 
Run(SbxValues * pValues)1031 sal_Bool SbxMethod::Run( SbxValues* pValues )
1032 {
1033     SbxValues aRes;
1034     if( !pValues )
1035         pValues = &aRes;
1036     pValues->eType = SbxVARIANT;
1037     return Get( *pValues );
1038 }
1039 
GetClass() const1040 SbxClassType SbxMethod::GetClass() const
1041 {
1042     return SbxCLASS_METHOD;
1043 }
1044 
GetClass() const1045 SbxClassType SbxProperty::GetClass() const
1046 {
1047     return SbxCLASS_PROPERTY;
1048 }
1049 
GarbageCollection(sal_uIntPtr nObjects)1050 void SbxObject::GarbageCollection( sal_uIntPtr nObjects )
1051 
1052 /*  [Beschreibung]
1053 
1054     Diese statische Methode durchsucht die n"achsten 'nObjects' der zur Zeit
1055     existierenden <SbxObject>-Instanzen nach zyklischen Referenzen, die sich
1056     nur noch selbst am Leben erhalten. Ist 'nObjects==0', dann werden
1057     alle existierenden durchsucht.
1058 
1059     zur Zeit nur implementiert: Object -> Parent-Property -> Parent -> Object
1060 */
1061 
1062 {
1063     (void)nObjects;
1064 
1065     static sal_Bool bInGarbageCollection = sal_False;
1066     if ( bInGarbageCollection )
1067         return;
1068     bInGarbageCollection = sal_True;
1069 
1070 #if 0
1071     // erstes Object dieser Runde anspringen
1072     sal_Bool bAll = !nObjects;
1073     if ( bAll )
1074         rObjects.First();
1075     SbxObject *pObj = rObjects.GetCurObject();
1076     if ( !pObj )
1077         pObj = rObjects.First();
1078 
1079     while ( pObj && 0 != nObjects-- )
1080     {
1081         // hat der Parent nur noch 1 Ref-Count?
1082         SbxObject *pParent = PTR_CAST( SbxObject, pObj->GetParent() );
1083         if ( pParent && 1 == pParent->GetRefCount() )
1084         {
1085             // dann alle Properies des Objects durchsuchen
1086             SbxArray *pProps = pObj->GetProperties();
1087             for ( sal_uInt16 n = 0; n < pProps->Count(); ++n )
1088             {
1089                 // verweist die Property auf den Parent des Object?
1090                 SbxVariable *pProp = pProps->Get(n);
1091                 const SbxValues &rValues = pProp->GetValues_Impl();
1092                 if ( SbxOBJECT == rValues.eType &&
1093                      pParent == rValues.pObj )
1094                 {
1095 #ifdef DBG_UTIL
1096                     DbgOutf( "SBX: %s.%s with Object %s was garbage",
1097                              pObj->GetName().GetStr(),
1098                              pProp->GetName().GetStr(),
1099                              pParent->GetName().GetStr() );
1100 #endif
1101                     // dann freigeben
1102                     pProp->SbxValue::Clear();
1103                     Sound::Beep();
1104                     break;
1105                 }
1106             }
1107         }
1108 
1109         // zum n"achsten
1110         pObj = rObjects.Next();
1111         if ( !bAll && !pObj )
1112             pObj = rObjects.First();
1113     }
1114 #endif
1115 
1116 // AB 28.10. Zur 507a vorerst raus, da SfxBroadcaster::Enable() wegfaellt
1117 #if 0
1118 #ifdef DBG_UTIL
1119     SbxVarList_Impl &rVars = GetSbxData_Impl()->aVars;
1120     DbgOutf( "SBX: garbage collector done, %lu objects remainding",
1121              rVars.Count() );
1122     if ( rVars.Count() > 200 && rVars.Count() < 210 )
1123     {
1124         SvFileStream aStream( "d:\\tmp\\dump.sbx", STREAM_STD_WRITE );
1125         SfxBroadcaster::Enable(sal_False);
1126         for ( sal_uIntPtr n = 0; n < rVars.Count(); ++n )
1127         {
1128             SbxVariable *pVar = rVars.GetObject(n);
1129             SbxObject *pObj = PTR_CAST(SbxObject, pVar);
1130             sal_uInt16 nFlags = pVar->GetFlags();
1131             pVar->SetFlag(SBX_NO_BROADCAST);
1132             if ( pObj )
1133                 pObj->Dump(aStream);
1134             else if ( !pVar->GetParent() || !pVar->GetParent()->ISA(SbxObject) )
1135                 pVar->Dump(aStream);
1136             pVar->SetFlags(nFlags);
1137         }
1138         SfxBroadcaster::Enable(sal_True);
1139     }
1140 #endif
1141 #endif
1142     bInGarbageCollection = sal_False;
1143 }
1144 
1145