update dev300-m58
[ooovba.git] / basic / source / sbx / sbxvar.cxx
blob1ecd20cc2b04b39e493cef176eea8653664b3c4d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: sbxvar.cxx,v $
10 * $Revision: 1.10 $
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_basic.hxx"
35 #include <tools/stream.hxx>
36 #include "svtools/brdcst.hxx"
38 #include <basic/sbx.hxx>
39 #include <basic/sbxbase.hxx>
40 #include "sbxres.hxx"
41 #include "sbxconv.hxx"
42 #include <math.h>
43 #include <ctype.h>
45 ///////////////////////////// SbxVariable //////////////////////////////
47 TYPEINIT1(SbxVariable,SbxValue)
48 TYPEINIT1(SbxHint,SfxSimpleHint)
50 extern UINT32 nVarCreator; // in SBXBASE.CXX, fuer LoadData()
51 #ifdef DBG_UTIL
52 static ULONG nVar = 0;
53 #endif
55 ///////////////////////////// Konstruktoren //////////////////////////////
57 SbxVariable::SbxVariable() : SbxValue()
59 pCst = NULL;
60 pParent = NULL;
61 nUserData = 0;
62 nHash = 0;
63 #ifdef DBG_UTIL
64 DbgOutf( "SbxVariable::Ctor %lx=%ld", (void*)this, ++nVar );
65 GetSbxData_Impl()->aVars.Insert( this, LIST_APPEND );
66 #endif
69 SbxVariable::SbxVariable( const SbxVariable& r )
70 : SvRefBase( r ), SbxValue( r ), mpPar( r.mpPar ), pInfo( r.pInfo )
72 pCst = NULL;
73 if( r.CanRead() )
75 pParent = r.pParent;
76 nUserData = r.nUserData;
77 maName = r.maName;
78 nHash = r.nHash;
80 else
82 pParent = NULL;
83 nUserData = 0;
84 nHash = 0;
86 #ifdef DBG_UTIL
87 static sal_Char const aCellsStr[] = "Cells";
88 if ( maName.EqualsAscii( aCellsStr ) )
89 maName.AssignAscii( aCellsStr, sizeof( aCellsStr )-1 );
90 DbgOutf( "SbxVariable::Ctor %lx=%ld", (void*)this, ++nVar );
91 GetSbxData_Impl()->aVars.Insert( this, LIST_APPEND );
92 #endif
95 SbxVariable::SbxVariable( SbxDataType t, void* p ) : SbxValue( t, p )
97 pCst = NULL;
98 pParent = NULL;
99 nUserData = 0;
100 nHash = 0;
101 #ifdef DBG_UTIL
102 DbgOutf( "SbxVariable::Ctor %lx=%ld", (void*)this, ++nVar );
103 GetSbxData_Impl()->aVars.Insert( this, LIST_APPEND );
104 #endif
107 SbxVariable::~SbxVariable()
109 #ifdef DBG_UTIL
110 ByteString aBStr( (const UniString&)maName, RTL_TEXTENCODING_ASCII_US );
111 DbgOutf( "SbxVariable::Dtor %lx (%s)", (void*)this, aBStr.GetBuffer() );
112 static sal_Char const aCellsStr[] = "Cells";
113 if ( maName.EqualsAscii( aCellsStr ) )
114 maName.AssignAscii( aCellsStr, sizeof( aCellsStr )-1 );
115 GetSbxData_Impl()->aVars.Remove( this );
116 #endif
117 delete pCst;
120 ////////////////////////////// Broadcasting //////////////////////////////
122 SfxBroadcaster& SbxVariable::GetBroadcaster()
124 if( !pCst )
125 pCst = new SfxBroadcaster;
126 return *pCst;
129 // Eines Tages kann man vielleicht den Parameter 0 schleifen,
130 // dann entfaellt die Kopiererei...
132 void SbxVariable::Broadcast( ULONG nHintId )
134 if( pCst && !IsSet( SBX_NO_BROADCAST ) && StaticIsEnabledBroadcasting() )
136 // Da die Methode von aussen aufrufbar ist, hier noch einmal
137 // die Berechtigung testen
138 if( nHintId & SBX_HINT_DATAWANTED )
139 if( !CanRead() )
140 return;
141 if( nHintId & SBX_HINT_DATACHANGED )
142 if( !CanWrite() )
143 return;
144 // Weitere Broadcasts verhindern
145 SfxBroadcaster* pSave = pCst;
146 pCst = NULL;
147 USHORT nSaveFlags = GetFlags();
148 SetFlag( SBX_READWRITE );
149 if( mpPar.Is() )
150 // this, als Element 0 eintragen, aber den Parent nicht umsetzen!
151 mpPar->GetRef( 0 ) = this;
152 pSave->Broadcast( SbxHint( nHintId, this ) );
153 delete pCst; // wer weiss schon, auf welche Gedanken mancher kommt?
154 pCst = pSave;
155 SetFlags( nSaveFlags );
159 SbxInfo* SbxVariable::GetInfo()
161 if( !pInfo )
163 Broadcast( SBX_HINT_INFOWANTED );
164 if( pInfo.Is() )
165 SetModified( TRUE );
167 return pInfo;
170 void SbxVariable::SetInfo( SbxInfo* p )
172 pInfo = p;
175 void SbxVariable::SetParameters( SbxArray* p )
177 mpPar = p;
181 /////////////////////////// Name der Variablen ///////////////////////////
183 void SbxVariable::SetName( const XubString& rName )
185 maName = rName;
186 nHash = MakeHashCode( rName );
189 const XubString& SbxVariable::GetName( SbxNameType t ) const
191 static char cSuffixes[] = " %&!#@ $";
192 if( t == SbxNAME_NONE )
193 return maName;
194 // Parameter-Infos anfordern (nicht fuer Objekte)
195 ((SbxVariable*)this)->GetInfo();
196 // Nix anfuegen, wenn einfache Property (keine leeren Klammern)
197 if( !pInfo
198 || ( !pInfo->aParams.Count() && GetClass() == SbxCLASS_PROPERTY ) )
199 return maName;
200 xub_Unicode cType = ' ';
201 XubString aTmp( maName );
202 // Kurzer Typ? Dann holen, evtl. ist dieser 0.
203 SbxDataType et = GetType();
204 if( t == SbxNAME_SHORT_TYPES )
206 if( et <= SbxSTRING )
207 cType = cSuffixes[ et ];
208 if( cType != ' ' )
209 aTmp += cType;
211 aTmp += '(';
212 for( USHORT i = 0; i < pInfo->aParams.Count(); i++ )
214 const SbxParamInfo* q = pInfo->aParams.GetObject( i );
215 int nt = q->eType & 0x0FFF;
216 if( i )
217 aTmp += ',';
218 if( q->nFlags & SBX_OPTIONAL )
219 aTmp += SbxRes( STRING_OPTIONAL );
220 if( q->eType & SbxBYREF )
221 aTmp += SbxRes( STRING_BYREF );
222 aTmp += q->aName;
223 cType = ' ';
224 // Kurzer Typ? Dann holen, evtl. ist dieser 0.
225 if( t == SbxNAME_SHORT_TYPES )
227 if( nt <= SbxSTRING )
228 cType = cSuffixes[ nt ];
230 if( cType != ' ' )
232 aTmp += cType;
233 if( q->eType & SbxARRAY )
234 aTmp.AppendAscii( "()" );
236 else
238 if( q->eType & SbxARRAY )
239 aTmp.AppendAscii( "()" );
240 // langer Typ?
241 if( t != SbxNAME_SHORT )
243 aTmp += SbxRes( STRING_AS );
244 if( nt < 32 )
245 aTmp += SbxRes(
246 sal::static_int_cast< USHORT >( STRING_TYPES + nt ) );
247 else
248 aTmp += SbxRes( STRING_ANY );
252 aTmp += ')';
253 // Langer Typ? Dann holen
254 if( t == SbxNAME_LONG_TYPES && et != SbxEMPTY )
256 aTmp += SbxRes( STRING_AS );
257 if( et < 32 )
258 aTmp += SbxRes(
259 sal::static_int_cast< USHORT >( STRING_TYPES + et ) );
260 else
261 aTmp += SbxRes( STRING_ANY );
263 ((SbxVariable*) this)->aPic = aTmp;
264 return aPic;
267 // Einen simplen Hashcode erzeugen: Es werden die ersten 6 Zeichen gewertet.
269 USHORT SbxVariable::MakeHashCode( const XubString& rName )
271 USHORT n = 0;
272 USHORT nLen = rName.Len();
273 if( nLen > 6 )
274 nLen = 6;
275 const xub_Unicode* p = rName.GetBuffer();
276 while( nLen-- )
278 BYTE c = (BYTE)*p;
279 p++;
280 // Falls wir ein Schweinezeichen haben, abbrechen!!
281 if( c >= 0x80 )
282 return 0;
283 n = sal::static_int_cast< USHORT >( ( n << 3 ) + toupper( c ) );
285 return n;
288 ////////////////////////////// Operatoren ////////////////////////////////
290 SbxVariable& SbxVariable::operator=( const SbxVariable& r )
292 SbxValue::operator=( r );
293 return *this;
296 //////////////////////////////// Konversion ////////////////////////////////
298 SbxDataType SbxVariable::GetType() const
300 if( aData.eType == SbxOBJECT )
301 return aData.pObj ? aData.pObj->GetType() : SbxOBJECT;
302 else if( aData.eType == SbxVARIANT )
303 return aData.pObj ? aData.pObj->GetType() : SbxVARIANT;
304 else
305 return aData.eType;
308 SbxClassType SbxVariable::GetClass() const
310 return SbxCLASS_VARIABLE;
313 void SbxVariable::SetModified( BOOL b )
315 if( IsSet( SBX_NO_MODIFY ) )
316 return;
317 SbxBase::SetModified( b );
318 if( pParent && pParent != this ) //??? HotFix: Rekursion raus MM
319 pParent->SetModified( b );
322 void SbxVariable::SetParent( SbxObject* p )
324 #ifdef DBG_UTIL
325 // wird der Parent eines SbxObjects gesetzt?
326 if ( p && ISA(SbxObject) )
328 // dann mu\s dieses auch Child vom neuen Parent sein
329 BOOL bFound = FALSE;
330 SbxArray *pChilds = p->GetObjects();
331 if ( pChilds )
333 for ( USHORT nIdx = 0; !bFound && nIdx < pChilds->Count(); ++nIdx )
334 bFound = ( this == pChilds->Get(nIdx) );
336 if ( !bFound )
338 String aMsg = String::CreateFromAscii( "dangling: [" );
339 aMsg += GetName();
340 aMsg.AppendAscii( "].SetParent([" );
341 aMsg += p->GetName();
342 aMsg.AppendAscii( "])" );
343 ByteString aBStr( (const UniString&)aMsg, RTL_TEXTENCODING_ASCII_US );
344 DbgOut( aBStr.GetBuffer(), DBG_OUT_WARNING, __FILE__, __LINE__);
347 #endif
349 pParent = p;
352 ////////////////////////////// Laden/Speichern /////////////////////////////
354 BOOL SbxVariable::LoadData( SvStream& rStrm, USHORT nVer )
356 UINT16 nType;
357 BYTE cMark;
358 rStrm >> cMark;
359 if( cMark == 0xFF )
361 if( !SbxValue::LoadData( rStrm, nVer ) )
362 return FALSE;
363 rStrm.ReadByteString( maName, RTL_TEXTENCODING_ASCII_US );
364 UINT32 nTemp;
365 rStrm >> nTemp;
366 nUserData = nTemp;
368 else
370 rStrm.SeekRel( -1L );
371 rStrm >> nType;
372 rStrm.ReadByteString( maName, RTL_TEXTENCODING_ASCII_US );
373 UINT32 nTemp;
374 rStrm >> nTemp;
375 nUserData = nTemp;
376 // Korrektur: Alte Methoden haben statt SbxNULL jetzt SbxEMPTY
377 if( nType == SbxNULL && GetClass() == SbxCLASS_METHOD )
378 nType = SbxEMPTY;
379 SbxValues aTmp;
380 XubString aVal;
381 aTmp.eType = aData.eType = (SbxDataType) nType;
382 aTmp.pString = &aVal;
383 switch( nType )
385 case SbxBOOL:
386 case SbxERROR:
387 case SbxINTEGER:
388 rStrm >> aTmp.nInteger; break;
389 case SbxLONG:
390 rStrm >> aTmp.nLong; break;
391 case SbxSINGLE:
393 // Floats als ASCII
394 rStrm.ReadByteString( aVal, RTL_TEXTENCODING_ASCII_US );
395 double d;
396 SbxDataType t;
397 if( ImpScan( aVal, d, t, NULL ) != SbxERR_OK || t == SbxDOUBLE )
399 aTmp.nSingle = 0;
400 return FALSE;
402 aTmp.nSingle = (float) d;
403 break;
405 case SbxDATE:
406 case SbxDOUBLE:
408 // Floats als ASCII
409 rStrm.ReadByteString( aVal, RTL_TEXTENCODING_ASCII_US );
410 SbxDataType t;
411 if( ImpScan( aVal, aTmp.nDouble, t, NULL ) != SbxERR_OK )
413 aTmp.nDouble = 0;
414 return FALSE;
416 break;
418 case SbxSTRING:
419 rStrm.ReadByteString( aVal, RTL_TEXTENCODING_ASCII_US );
420 break;
421 case SbxEMPTY:
422 case SbxNULL:
423 break;
424 default:
425 aData.eType = SbxNULL;
426 DBG_ASSERT( !this, "Nicht unterstuetzer Datentyp geladen" );
427 return FALSE;
429 // Wert putten
430 if( nType != SbxNULL && nType != SbxEMPTY && !Put( aTmp ) )
431 return FALSE;
433 rStrm >> cMark;
434 // cMark ist auch eine Versionsnummer!
435 // 1: initial version
436 // 2: mit nUserData
437 if( cMark )
439 if( cMark > 2 )
440 return FALSE;
441 pInfo = new SbxInfo;
442 pInfo->LoadData( rStrm, (USHORT) cMark );
444 // Privatdaten nur laden, wenn es eine SbxVariable ist
445 if( GetClass() == SbxCLASS_VARIABLE && !LoadPrivateData( rStrm, nVer ) )
446 return FALSE;
447 ((SbxVariable*) this)->Broadcast( SBX_HINT_DATACHANGED );
448 nHash = MakeHashCode( maName );
449 SetModified( TRUE );
450 return TRUE;
453 BOOL SbxVariable::StoreData( SvStream& rStrm ) const
455 rStrm << (BYTE) 0xFF; // Marker
456 BOOL bValStore;
457 if( this->IsA( TYPE(SbxMethod) ) )
459 // #50200 Verhindern, dass Objekte, die zur Laufzeit als Return-Wert
460 // in der Methode als Value gespeichert sind, mit gespeichert werden
461 SbxVariable* pThis = (SbxVariable*)this;
462 USHORT nSaveFlags = GetFlags();
463 pThis->SetFlag( SBX_WRITE );
464 pThis->SbxValue::Clear();
465 pThis->SetFlags( nSaveFlags );
467 // Damit die Methode in keinem Fall ausgefuehrt wird!
468 // CAST, um const zu umgehen!
469 pThis->SetFlag( SBX_NO_BROADCAST );
470 bValStore = SbxValue::StoreData( rStrm );
471 pThis->ResetFlag( SBX_NO_BROADCAST );
473 else
474 bValStore = SbxValue::StoreData( rStrm );
475 if( !bValStore )
476 return FALSE;
477 // if( !SbxValue::StoreData( rStrm ) )
478 // return FALSE;
479 rStrm.WriteByteString( maName, RTL_TEXTENCODING_ASCII_US );
480 rStrm << (UINT32)nUserData;
481 if( pInfo.Is() )
483 rStrm << (BYTE) 2; // Version 2: mit UserData!
484 pInfo->StoreData( rStrm );
486 else
487 rStrm << (BYTE) 0;
488 // Privatdaten nur speichern, wenn es eine SbxVariable ist
489 if( GetClass() == SbxCLASS_VARIABLE )
490 return StorePrivateData( rStrm );
491 else
492 return TRUE;
495 ////////////////////////////// SbxInfo ///////////////////////////////////
497 SbxInfo::SbxInfo() : aHelpFile(), nHelpId( 0 ), aParams()
500 SbxInfo::SbxInfo( const String& r, UINT32 n )
501 : aHelpFile( r ), nHelpId( n ), aParams()
504 ////////////////////////////// SbxAlias //////////////////////////////////
506 SbxAlias::SbxAlias( const XubString& rName, SbxVariable* p )
507 : SbxVariable(), xAlias( p )
509 SetName( rName );
510 SetFlags( p->GetFlags() );
511 SetFlag( SBX_DONTSTORE );
512 aData.eType = p->GetType();
513 StartListening( p->GetBroadcaster() );
516 SbxAlias::SbxAlias( const SbxAlias& r )
517 : SvRefBase( r ), SbxVariable( r ),
518 SfxListener( r ), xAlias( r.xAlias )
521 SbxAlias& SbxAlias::operator=( const SbxAlias& r )
523 xAlias = r.xAlias;
524 return *this;
527 SbxAlias::~SbxAlias()
529 if( xAlias.Is() )
530 EndListening( xAlias->GetBroadcaster() );
533 void SbxAlias::Broadcast( ULONG nHt )
535 if( xAlias.Is() && StaticIsEnabledBroadcasting() )
537 xAlias->SetParameters( GetParameters() );
538 if( nHt == SBX_HINT_DATAWANTED )
539 SbxVariable::operator=( *xAlias );
540 else if( nHt == SBX_HINT_DATACHANGED || nHt == SBX_HINT_CONVERTED )
541 *xAlias = *this;
542 else if( nHt == SBX_HINT_INFOWANTED )
544 xAlias->Broadcast( nHt );
545 pInfo = xAlias->GetInfo();
550 void SbxAlias::SFX_NOTIFY( SfxBroadcaster&, const TypeId&,
551 const SfxHint& rHint, const TypeId& )
553 const SbxHint* p = PTR_CAST(SbxHint,&rHint);
554 if( p && p->GetId() == SBX_HINT_DYING )
556 xAlias.Clear();
557 // Alias loeschen?
558 if( pParent )
559 pParent->Remove( this );
563 void SbxVariable::Dump( SvStream& rStrm, BOOL bFill )
565 ByteString aBNameStr( (const UniString&)GetName( SbxNAME_SHORT_TYPES ), RTL_TEXTENCODING_ASCII_US );
566 rStrm << "Variable( "
567 << ByteString::CreateFromInt64( (ULONG) this ).GetBuffer() << "=="
568 << aBNameStr.GetBuffer();
569 ByteString aBParentNameStr( (const UniString&)GetParent()->GetName(), RTL_TEXTENCODING_ASCII_US );
570 if ( GetParent() )
571 rStrm << " in parent '" << aBParentNameStr.GetBuffer() << "'";
572 else
573 rStrm << " no parent";
574 rStrm << " ) ";
576 // bei Object-Vars auch das Object ausgeben
577 if ( GetValues_Impl().eType == SbxOBJECT &&
578 GetValues_Impl().pObj &&
579 GetValues_Impl().pObj != this &&
580 GetValues_Impl().pObj != GetParent() )
582 rStrm << " contains ";
583 ((SbxObject*) GetValues_Impl().pObj)->Dump( rStrm, bFill );
585 else
586 rStrm << endl;