Update ooo320-m1
[ooovba.git] / basic / source / basmgr / basicmanagerrepository.cxx
blob3c4980e266dcc5cc5b75af862aca6d5a9e907d6e
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: basicmanagerrepository.cxx,v $
10 * $Revision: 1.11 $
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"
33 #include <basic/basicmanagerrepository.hxx>
34 #include <basic/basmgr.hxx>
35 #include "scriptcont.hxx"
36 #include "dlgcont.hxx"
37 #include <basic/sbuno.hxx>
38 #include "sbintern.hxx"
40 /** === begin UNO includes === **/
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/document/XStorageBasedDocument.hpp>
43 #include <com/sun/star/document/XEmbeddedScripts.hpp>
44 /** === end UNO includes === **/
45 #include <svtools/ehdl.hxx>
46 #include <svtools/sfxecode.hxx>
47 #include <svtools/pathoptions.hxx>
48 #include <svtools/smplhint.hxx>
49 #include <vcl/svapp.hxx>
50 #include <tools/debug.hxx>
51 #include <tools/diagnose_ex.h>
52 #include <tools/urlobj.hxx>
53 #include <comphelper/stl_types.hxx>
54 #include <comphelper/processfactory.hxx>
55 #include <comphelper/documentinfo.hxx>
56 #include <unotools/eventlisteneradapter.hxx>
58 #ifndef INCLUDED_OSL_DOUBLECHECKEDLOCKING_H
59 #include <rtl/instance.hxx>
60 #endif
62 #include <map>
64 //........................................................................
65 namespace basic
67 //........................................................................
69 /** === begin UNO using === **/
70 using ::com::sun::star::uno::Reference;
71 using ::com::sun::star::frame::XModel;
72 using ::com::sun::star::uno::XInterface;
73 using ::com::sun::star::uno::UNO_QUERY;
74 using ::com::sun::star::embed::XStorage;
75 using ::com::sun::star::script::XPersistentLibraryContainer;
76 using ::com::sun::star::uno::Any;
77 using ::com::sun::star::lang::XMultiServiceFactory;
78 using ::com::sun::star::uno::UNO_QUERY_THROW;
79 using ::com::sun::star::beans::XPropertySet;
80 using ::com::sun::star::uno::Exception;
81 using ::com::sun::star::document::XStorageBasedDocument;
82 using ::com::sun::star::lang::XComponent;
83 using ::com::sun::star::document::XEmbeddedScripts;
84 /** === end UNO using === **/
86 typedef BasicManager* BasicManagerPointer;
87 typedef ::std::map< Reference< XInterface >, BasicManagerPointer, ::comphelper::OInterfaceCompare< XInterface > > BasicManagerStore;
89 typedef ::std::vector< BasicManagerCreationListener* > CreationListeners;
91 //====================================================================
92 //= BasicManagerCleaner
93 //====================================================================
94 /// is the only instance which is allowed to delete a BasicManager instance
95 class BasicManagerCleaner
97 public:
98 static void deleteBasicManager( BasicManager*& _rpManager )
100 delete _rpManager;
101 _rpManager = NULL;
105 //====================================================================
106 //= ImplRepository
107 //====================================================================
108 class ImplRepository : public ::utl::OEventListenerAdapter, public SfxListener
110 private:
111 friend struct CreateImplRepository;
112 ImplRepository();
114 private:
115 ::osl::Mutex m_aMutex;
116 BasicManagerStore m_aStore;
117 CreationListeners m_aCreationListeners;
119 public:
120 static ImplRepository& Instance();
122 BasicManager* getDocumentBasicManager( const Reference< XModel >& _rxDocumentModel );
123 BasicManager* getApplicationBasicManager( bool _bCreate );
124 void setApplicationBasicManager( BasicManager* _pBasicManager );
125 void registerCreationListener( BasicManagerCreationListener& _rListener );
126 void revokeCreationListener( BasicManagerCreationListener& _rListener );
128 private:
129 /** retrieves the location at which the BasicManager for the given model
130 is stored.
132 If previously, the BasicManager for this model has never been requested,
133 then the model is added to the map, with an initial NULL BasicManager.
135 @param _rxDocumentModel
136 the model whose BasicManager's location is to be retrieved. Must not be <NULL/>.
138 @precond
139 our mutex is locked
141 BasicManagerPointer&
142 impl_getLocationForModel( const Reference< XModel >& _rxDocumentModel );
144 /** creates a new BasicManager instance for the given model
146 BasicManagerPointer
147 impl_createManagerForModel( const Reference< XModel >& _rxDocumentModel );
149 /** creates the application-wide BasicManager
151 BasicManagerPointer impl_createApplicationBasicManager();
153 /** notifies all listeners which expressed interest in the creation of BasicManager instances.
155 void impl_notifyCreationListeners(
156 const Reference< XModel >& _rxDocumentModel,
157 BasicManager& _rManager
160 /** retrieves the current storage of a given document
162 @param _rxDocument
163 the document whose storage is to be retrieved.
165 @param _out_rStorage
166 takes the storage upon successful return. Note that this might be <NULL/> even
167 if <TRUE/> is returned. In this case, the document has not yet been saved.
169 @return
170 <TRUE/> if the storage could be successfully retrieved (in which case
171 <arg>_out_rStorage</arg> might or might not be <NULL/>), <FALSE/> otherwise.
172 In the latter case, processing this document should stop.
174 bool impl_getDocumentStorage_nothrow( const Reference< XModel >& _rxDocument, Reference< XStorage >& _out_rStorage );
176 /** retrieves the containers for Basic and Dialog libraries for a given document
178 @param _rxDocument
179 the document whose containers are to be retrieved.
181 @param _out_rxBasicLibraries
182 takes the basic library container upon successful return
184 @param _out_rxDialogLibraries
185 takes the dialog library container upon successful return
187 @return
188 <TRUE/> if and only if both containers exist, and could successfully be retrieved
190 bool impl_getDocumentLibraryContainers_nothrow(
191 const Reference< XModel >& _rxDocument,
192 Reference< XPersistentLibraryContainer >& _out_rxBasicLibraries,
193 Reference< XPersistentLibraryContainer >& _out_rxDialogLibraries
196 /** initializes the given library containers, which belong to a document
198 void impl_initDocLibraryContainers_nothrow(
199 const Reference< XPersistentLibraryContainer >& _rxBasicLibraries,
200 const Reference< XPersistentLibraryContainer >& _rxDialogLibraries
203 // OEventListenerAdapter overridables
204 virtual void _disposing( const ::com::sun::star::lang::EventObject& _rSource );
206 // SfxListener overridables
207 virtual void Notify( SfxBroadcaster& _rBC, const SfxHint& _rHint );
209 /** removes the Model/BasicManager pair given by iterator from our store
211 void impl_removeFromRepository( BasicManagerStore::iterator _pos );
213 private:
214 StarBASIC* impl_getDefaultAppBasicLibrary();
217 //====================================================================
218 //= CreateImplRepository
219 //====================================================================
220 struct CreateImplRepository
222 ImplRepository* operator()()
224 static ImplRepository* pRepository = new ImplRepository;
225 return pRepository;
230 //====================================================================
231 //= ImplRepository
232 //====================================================================
233 //--------------------------------------------------------------------
234 ImplRepository::ImplRepository()
238 //--------------------------------------------------------------------
239 ImplRepository& ImplRepository::Instance()
241 return *rtl_Instance< ImplRepository, CreateImplRepository, ::osl::MutexGuard, ::osl::GetGlobalMutex >::
242 create( CreateImplRepository(), ::osl::GetGlobalMutex() );
245 //--------------------------------------------------------------------
246 BasicManager* ImplRepository::getDocumentBasicManager( const Reference< XModel >& _rxDocumentModel )
248 ::osl::MutexGuard aGuard( m_aMutex );
250 BasicManagerPointer& pBasicManager = impl_getLocationForModel( _rxDocumentModel );
251 if ( pBasicManager == NULL )
252 pBasicManager = impl_createManagerForModel( _rxDocumentModel );
254 return pBasicManager;
257 //--------------------------------------------------------------------
258 BasicManager* ImplRepository::getApplicationBasicManager( bool _bCreate )
260 ::osl::MutexGuard aGuard( m_aMutex );
262 BasicManager* pAppManager = GetSbData()->pAppBasMgr;
263 if ( ( pAppManager == NULL ) && _bCreate )
264 pAppManager = impl_createApplicationBasicManager();
266 return pAppManager;
269 //--------------------------------------------------------------------
270 void ImplRepository::setApplicationBasicManager( BasicManager* _pBasicManager )
272 ::osl::MutexGuard aGuard( m_aMutex );
274 BasicManager* pPreviousManager = getApplicationBasicManager( false );
275 BasicManagerCleaner::deleteBasicManager( pPreviousManager );
277 GetSbData()->pAppBasMgr = _pBasicManager;
280 //--------------------------------------------------------------------
281 BasicManager* ImplRepository::impl_createApplicationBasicManager()
283 ::osl::MutexGuard aGuard( m_aMutex );
284 OSL_PRECOND( getApplicationBasicManager( false ) == NULL, "ImplRepository::impl_createApplicationBasicManager: there already is one!" );
286 // Determine Directory
287 SvtPathOptions aPathCFG;
288 String aAppBasicDir( aPathCFG.GetBasicPath() );
289 if ( !aAppBasicDir.Len() )
290 aPathCFG.SetBasicPath( String::CreateFromAscii("$(prog)") );
292 // #58293# soffice.new search only in user dir => first dir
293 String aAppFirstBasicDir = aAppBasicDir.GetToken(1);
295 // Create basic and load it
296 // MT: #47347# AppBasicDir is now a PATH
297 INetURLObject aAppBasic( SvtPathOptions().SubstituteVariable( String::CreateFromAscii("$(progurl)") ) );
298 aAppBasic.insertName( Application::GetAppName() );
300 BasicManager* pBasicManager = new BasicManager( new StarBASIC, &aAppBasicDir );
301 setApplicationBasicManager( pBasicManager );
303 // Als Destination das erste Dir im Pfad:
304 String aFileName( aAppBasic.getName() );
305 aAppBasic = INetURLObject( aAppBasicDir.GetToken(1) );
306 DBG_ASSERT( aAppBasic.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" );
307 aAppBasic.insertName( aFileName );
308 pBasicManager->SetStorageName( aAppBasic.PathToFileName() );
310 // Basic container
311 SfxScriptLibraryContainer* pBasicCont = new SfxScriptLibraryContainer( Reference< XStorage >() );
312 Reference< XPersistentLibraryContainer > xBasicCont( pBasicCont );
313 pBasicCont->setBasicManager( pBasicManager );
315 // Dialog container
316 SfxDialogLibraryContainer* pDialogCont = new SfxDialogLibraryContainer( Reference< XStorage >() );
317 Reference< XPersistentLibraryContainer > xDialogCont( pDialogCont );
319 LibraryContainerInfo aInfo( xBasicCont, xDialogCont, static_cast< OldBasicPassword* >( pBasicCont ) );
320 pBasicManager->SetLibraryContainerInfo( aInfo );
322 // global constants
324 // StarDesktop
325 Reference< XMultiServiceFactory > xSMgr = ::comphelper::getProcessServiceFactory();
326 pBasicManager->SetGlobalUNOConstant(
327 "StarDesktop",
328 makeAny( xSMgr->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.Desktop" ) ) ) )
331 // (BasicLibraries and DialogLibraries have automatically been added in SetLibraryContainerInfo)
333 // notify
334 impl_notifyCreationListeners( NULL, *pBasicManager );
336 // outta here
337 return pBasicManager;
340 //--------------------------------------------------------------------
341 void ImplRepository::registerCreationListener( BasicManagerCreationListener& _rListener )
343 ::osl::MutexGuard aGuard( m_aMutex );
344 m_aCreationListeners.push_back( &_rListener );
347 //--------------------------------------------------------------------
348 void ImplRepository::revokeCreationListener( BasicManagerCreationListener& _rListener )
350 ::osl::MutexGuard aGuard( m_aMutex );
351 CreationListeners::iterator pos = ::std::find( m_aCreationListeners.begin(), m_aCreationListeners.end(), &_rListener );
352 if ( pos != m_aCreationListeners.end() )
353 m_aCreationListeners.erase( pos );
354 else {
355 DBG_ERROR( "ImplRepository::revokeCreationListener: listener is not registered!" );
359 //--------------------------------------------------------------------
360 void ImplRepository::impl_notifyCreationListeners( const Reference< XModel >& _rxDocumentModel, BasicManager& _rManager )
362 for ( CreationListeners::const_iterator loop = m_aCreationListeners.begin();
363 loop != m_aCreationListeners.end();
364 ++loop
367 (*loop)->onBasicManagerCreated( _rxDocumentModel, _rManager );
371 //--------------------------------------------------------------------
372 StarBASIC* ImplRepository::impl_getDefaultAppBasicLibrary()
374 BasicManager* pAppManager = getApplicationBasicManager( true );
376 StarBASIC* pAppBasic = pAppManager ? pAppManager->GetLib(0) : NULL;
377 DBG_ASSERT( pAppBasic != NULL, "impl_getApplicationBasic: unable to determine the default application's Basic library!" );
378 return pAppBasic;
381 //--------------------------------------------------------------------
382 BasicManagerPointer& ImplRepository::impl_getLocationForModel( const Reference< XModel >& _rxDocumentModel )
384 Reference< XInterface > xNormalized( _rxDocumentModel, UNO_QUERY );
385 DBG_ASSERT( xNormalized.is(), "ImplRepository::impl_getLocationForModel: invalid model!" );
387 BasicManagerPointer& location = m_aStore[ xNormalized ];
388 return location;
391 //--------------------------------------------------------------------
392 void ImplRepository::impl_initDocLibraryContainers_nothrow( const Reference< XPersistentLibraryContainer >& _rxBasicLibraries, const Reference< XPersistentLibraryContainer >& _rxDialogLibraries )
394 OSL_PRECOND( _rxBasicLibraries.is() && _rxDialogLibraries.is(),
395 "ImplRepository::impl_initDocLibraryContainers_nothrow: illegal library containers, this will crash!" );
399 // ensure there's a standard library in the basic container
400 ::rtl::OUString aStdLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) );
401 if ( !_rxBasicLibraries->hasByName( aStdLibName ) )
402 _rxBasicLibraries->createLibrary( aStdLibName );
403 // as well as in the dialog container
404 if ( !_rxDialogLibraries->hasByName( aStdLibName ) )
405 _rxDialogLibraries->createLibrary( aStdLibName );
407 catch( const Exception& )
409 DBG_UNHANDLED_EXCEPTION();
413 //--------------------------------------------------------------------
414 BasicManagerPointer ImplRepository::impl_createManagerForModel( const Reference< XModel >& _rxDocumentModel )
416 StarBASIC* pAppBasic = impl_getDefaultAppBasicLibrary();
418 BasicManager* pBasicManager( NULL );
419 Reference< XStorage > xStorage;
420 if ( !impl_getDocumentStorage_nothrow( _rxDocumentModel, xStorage ) )
421 // the document is not able to provide the storage it is based on.
422 return pBasicManager;
424 Reference< XPersistentLibraryContainer > xBasicLibs;
425 Reference< XPersistentLibraryContainer > xDialogLibs;
426 if ( !impl_getDocumentLibraryContainers_nothrow( _rxDocumentModel, xBasicLibs, xDialogLibs ) )
427 // the document does not have BasicLibraries and DialogLibraries
428 return pBasicManager;
430 if ( xStorage.is() )
432 // load BASIC-manager
433 SfxErrorContext aErrContext( ERRCTX_SFX_LOADBASIC,
434 ::comphelper::DocumentInfo::getDocumentTitle( _rxDocumentModel ) );
435 String aAppBasicDir = SvtPathOptions().GetBasicPath();
437 // Storage and BaseURL are only needed by binary documents!
438 SotStorageRef xDummyStor = new SotStorage( ::rtl::OUString() );
439 pBasicManager = new BasicManager( *xDummyStor, String() /* TODO/LATER: xStorage */,
440 pAppBasic,
441 &aAppBasicDir, TRUE );
442 if ( pBasicManager->HasErrors() )
444 // handle errors
445 BasicError* pErr = pBasicManager->GetFirstError();
446 while ( pErr )
448 // show message to user
449 if ( ERRCODE_BUTTON_CANCEL == ErrorHandler::HandleError( pErr->GetErrorId() ) )
451 // user wants to break loading of BASIC-manager
452 BasicManagerCleaner::deleteBasicManager( pBasicManager );
453 xStorage.clear();
454 break;
456 pErr = pBasicManager->GetNextError();
461 // not loaded?
462 if ( !xStorage.is() )
464 // create new BASIC-manager
465 StarBASIC* pBasic = new StarBASIC( pAppBasic );
466 pBasic->SetFlag( SBX_EXTSEARCH );
467 pBasicManager = new BasicManager( pBasic, NULL, TRUE );
470 // knit the containers with the BasicManager
471 LibraryContainerInfo aInfo( xBasicLibs, xDialogLibs, dynamic_cast< OldBasicPassword* >( xBasicLibs.get() ) );
472 OSL_ENSURE( aInfo.mpOldBasicPassword, "ImplRepository::impl_createManagerForModel: wrong BasicLibraries implementation!" );
473 pBasicManager->SetLibraryContainerInfo( aInfo );
474 //pBasicCont->setBasicManager( pBasicManager );
475 // that's not needed anymore today. The containers will retrieve their associated
476 // BasicManager from the BasicManagerRepository, when needed.
478 // initialize the containers
479 impl_initDocLibraryContainers_nothrow( xBasicLibs, xDialogLibs );
481 // damit auch Dialoge etc. 'qualifiziert' angesprochen werden k"onnen
482 pBasicManager->GetLib(0)->SetParent( pAppBasic );
484 // global properties in the document's Basic
485 pBasicManager->SetGlobalUNOConstant( "ThisComponent", makeAny( _rxDocumentModel ) );
487 // notify
488 impl_notifyCreationListeners( _rxDocumentModel, *pBasicManager );
490 // register as listener for this model being disposed/closed
491 Reference< XComponent > xDocumentComponent( _rxDocumentModel, UNO_QUERY );
492 OSL_ENSURE( xDocumentComponent.is(), "ImplRepository::impl_createManagerForModel: the document must be an XComponent!" );
493 startComponentListening( xDocumentComponent );
495 // register as listener for the BasicManager being destroyed
496 StartListening( *pBasicManager );
498 return pBasicManager;
501 //--------------------------------------------------------------------
502 bool ImplRepository::impl_getDocumentStorage_nothrow( const Reference< XModel >& _rxDocument, Reference< XStorage >& _out_rStorage )
504 _out_rStorage.clear();
507 Reference< XStorageBasedDocument > xStorDoc( _rxDocument, UNO_QUERY_THROW );
508 _out_rStorage.set( xStorDoc->getDocumentStorage() );
510 catch( const Exception& )
512 DBG_UNHANDLED_EXCEPTION();
513 return false;
515 return true;
518 //--------------------------------------------------------------------
519 bool ImplRepository::impl_getDocumentLibraryContainers_nothrow( const Reference< XModel >& _rxDocument,
520 Reference< XPersistentLibraryContainer >& _out_rxBasicLibraries, Reference< XPersistentLibraryContainer >& _out_rxDialogLibraries )
522 _out_rxBasicLibraries.clear();
523 _out_rxDialogLibraries.clear();
526 Reference< XEmbeddedScripts > xScripts( _rxDocument, UNO_QUERY_THROW );
527 _out_rxBasicLibraries.set( xScripts->getBasicLibraries(), UNO_QUERY_THROW );
528 _out_rxDialogLibraries.set( xScripts->getDialogLibraries(), UNO_QUERY_THROW );
530 catch( const Exception& )
532 DBG_UNHANDLED_EXCEPTION();
534 return _out_rxBasicLibraries.is() && _out_rxDialogLibraries.is();
537 //--------------------------------------------------------------------
538 void ImplRepository::impl_removeFromRepository( BasicManagerStore::iterator _pos )
540 OSL_PRECOND( _pos != m_aStore.end(), "ImplRepository::impl_removeFromRepository: invalid position!" );
542 BasicManager* pManager = _pos->second;
544 // *first* remove from map (else Notify won't work properly)
545 m_aStore.erase( _pos );
547 // *then* delete the BasicManager
548 EndListening( *pManager );
549 BasicManagerCleaner::deleteBasicManager( pManager );
552 //--------------------------------------------------------------------
553 void ImplRepository::_disposing( const ::com::sun::star::lang::EventObject& _rSource )
555 ::osl::MutexGuard aGuard( m_aMutex );
557 Reference< XInterface > xNormalizedSource( _rSource.Source, UNO_QUERY );
558 #if OSL_DEBUG_LEVEL > 0
559 bool bFound = false;
560 #endif
562 for ( BasicManagerStore::iterator loop = m_aStore.begin();
563 loop != m_aStore.end();
564 ++loop
567 if ( loop->first.get() == xNormalizedSource.get() )
569 impl_removeFromRepository( loop );
570 #if OSL_DEBUG_LEVEL > 0
571 bFound = true;
572 #endif
573 break;
577 OSL_ENSURE( bFound, "ImplRepository::_disposing: where does this come from?" );
580 //--------------------------------------------------------------------
581 void ImplRepository::Notify( SfxBroadcaster& _rBC, const SfxHint& _rHint )
583 const SfxSimpleHint* pSimpleHint = dynamic_cast< const SfxSimpleHint* >( &_rHint );
584 if ( !pSimpleHint || ( pSimpleHint->GetId() != SFX_HINT_DYING ) )
585 // not interested in
586 return;
588 BasicManager* pManager = dynamic_cast< BasicManager* >( &_rBC );
589 OSL_ENSURE( pManager, "ImplRepository::Notify: where does this come from?" );
591 for ( BasicManagerStore::iterator loop = m_aStore.begin();
592 loop != m_aStore.end();
593 ++loop
596 if ( loop->second == pManager )
598 // a BasicManager which is still in our repository is being deleted.
599 // That's bad, since by definition, we *own* all instances in our
600 // repository.
601 OSL_ENSURE( false, "ImplRepository::Notify: nobody should tamper with the managers, except ourself!" );
602 m_aStore.erase( loop );
603 break;
608 //====================================================================
609 //= BasicManagerRepository
610 //====================================================================
611 //--------------------------------------------------------------------
612 BasicManager* BasicManagerRepository::getDocumentBasicManager( const Reference< XModel >& _rxDocumentModel )
614 return ImplRepository::Instance().getDocumentBasicManager( _rxDocumentModel );
617 //--------------------------------------------------------------------
618 BasicManager* BasicManagerRepository::getApplicationBasicManager( bool _bCreate )
620 return ImplRepository::Instance().getApplicationBasicManager( _bCreate );
623 //--------------------------------------------------------------------
624 void BasicManagerRepository::resetApplicationBasicManager()
626 return ImplRepository::Instance().setApplicationBasicManager( NULL );
629 //--------------------------------------------------------------------
630 void BasicManagerRepository::registerCreationListener( BasicManagerCreationListener& _rListener )
632 ImplRepository::Instance().registerCreationListener( _rListener );
635 //--------------------------------------------------------------------
636 void BasicManagerRepository::revokeCreationListener( BasicManagerCreationListener& _rListener )
638 ImplRepository::Instance().revokeCreationListener( _rListener );
641 //........................................................................
642 } // namespace basic
643 //........................................................................