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_dbaccess.hxx"
30 
31 #include "browserids.hxx"
32 #include "commontypes.hxx"
33 #include "dataview.hxx"
34 #include "dbu_misc.hrc"
35 #include "dbustrings.hrc"
36 #include "moduledbu.hxx"
37 #include "dbsubcomponentcontroller.hxx"
38 
39 /** === begin UNO includes === **/
40 #include <com/sun/star/frame/XUntitledNumbers.hpp>
41 #include <com/sun/star/beans/PropertyAttribute.hpp>
42 #include <com/sun/star/container/XChild.hpp>
43 #include <com/sun/star/container/XNameAccess.hpp>
44 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
45 #include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
46 #include <com/sun/star/sdbc/XDataSource.hpp>
47 #include <com/sun/star/lang/IllegalArgumentException.hpp>
48 #include <com/sun/star/frame/XUntitledNumbers.hpp>
49 /** === end UNO includes === **/
50 
51 #include <comphelper/sequence.hxx>
52 #include <comphelper/types.hxx>
53 #include <connectivity/dbexception.hxx>
54 #include <connectivity/dbtools.hxx>
55 #include <cppuhelper/typeprovider.hxx>
56 #include <rtl/ustrbuf.hxx>
57 #include <toolkit/unohlp.hxx>
58 #include <tools/debug.hxx>
59 #include <tools/diagnose_ex.h>
60 #include <vcl/msgbox.hxx>
61 
62 //........................................................................
63 namespace dbaui
64 {
65 //........................................................................
66 
67     /** === begin UNO using === **/
68     using ::com::sun::star::uno::Any;
69     using ::com::sun::star::uno::Reference;
70     using ::com::sun::star::beans::XPropertySet;
71     using ::com::sun::star::util::XNumberFormatter;
72     using ::com::sun::star::lang::XMultiServiceFactory;
73     using ::com::sun::star::uno::RuntimeException;
74     using ::com::sun::star::uno::Sequence;
75     using ::com::sun::star::uno::Type;
76     using ::com::sun::star::sdbc::XConnection;
77     using ::com::sun::star::uno::UNO_QUERY;
78     using ::com::sun::star::container::XChild;
79     using ::com::sun::star::sdbc::XDataSource;
80     using ::com::sun::star::util::XNumberFormatter;
81     using ::com::sun::star::util::XNumberFormatsSupplier;
82     using ::com::sun::star::frame::XFrame;
83     using ::com::sun::star::uno::Exception;
84     using ::com::sun::star::sdbc::SQLException;
85     using ::com::sun::star::lang::EventObject;
86     using ::com::sun::star::beans::PropertyValue;
87     using ::com::sun::star::frame::XModel;
88     using ::com::sun::star::sdb::XOfficeDatabaseDocument;
89     using ::com::sun::star::awt::XWindow;
90     using ::com::sun::star::sdbc::XDatabaseMetaData;
91     using ::com::sun::star::sdb::XDocumentDataSource;
92     using ::com::sun::star::document::XEmbeddedScripts;
93     using ::com::sun::star::lang::IllegalArgumentException;
94     using ::com::sun::star::uno::UNO_SET_THROW;
95     using ::com::sun::star::uno::UNO_QUERY_THROW;
96     using ::com::sun::star::frame::XUntitledNumbers;
97     using ::com::sun::star::beans::PropertyVetoException;
98     /** === end UNO using === **/
99 
100     class DataSourceHolder
101     {
102     public:
103         DataSourceHolder()
104         {
105         }
106 
107         DataSourceHolder( const Reference< XDataSource >& _rxDataSource )
108         {
109             m_xDataSource = _rxDataSource;
110             Reference< XDocumentDataSource > xDocDS( m_xDataSource, UNO_QUERY );
111             if ( xDocDS.is() )
112                 m_xDocument = xDocDS->getDatabaseDocument();
113 
114             m_xDataSourceProps.set( m_xDataSource, UNO_QUERY );
115         }
116 
117         const Reference< XDataSource >&             getDataSource() const { return m_xDataSource; }
118         const Reference< XPropertySet >&            getDataSourceProps() const { return m_xDataSourceProps; }
119         const Reference< XOfficeDatabaseDocument >  getDatabaseDocument() const { return m_xDocument; }
120 
121         bool is() const { return m_xDataSource.is(); }
122 
123         void clear()
124         {
125             m_xDataSource.clear();
126             m_xDocument.clear();
127         }
128 
129     private:
130         Reference< XDataSource >                m_xDataSource;
131         Reference< XPropertySet >               m_xDataSourceProps;
132         Reference< XOfficeDatabaseDocument >    m_xDocument;
133     };
134 
135     struct DBSubComponentController_Impl
136     {
137     private:
138         ::boost::optional< bool >       m_aDocScriptSupport;
139 
140     public:
141         OModuleClient                   m_aModuleClient;
142         ::dbtools::SQLExceptionInfo     m_aCurrentError;
143 
144         ::cppu::OInterfaceContainerHelper
145                                         m_aModifyListeners;
146 
147 		// <properties>
148         SharedConnection                m_xConnection;
149         ::dbtools::DatabaseMetaData     m_aSdbMetaData;
150 		// </properties>
151 		::rtl::OUString	                m_sDataSourceName;		// the data source we're working for
152 		DataSourceHolder                m_aDataSource;
153         Reference< XModel >             m_xDocument;
154 		Reference< XNumberFormatter > 	m_xFormatter;	// a number formatter working with the connection's NumberFormatsSupplier
155         sal_Int32                       m_nDocStartNumber;
156 		sal_Bool		                m_bSuspended;	// is true when the controller was already suspended
157 		sal_Bool		                m_bEditable;	// is the control readonly or not
158 		sal_Bool		                m_bModified;	// is the data modified
159         bool                            m_bNotAttached;
160 
161         DBSubComponentController_Impl( ::osl::Mutex& i_rMutex )
162             :m_aDocScriptSupport()
163             ,m_aModifyListeners( i_rMutex )
164             ,m_nDocStartNumber(0)
165             ,m_bSuspended( sal_False )
166 		    ,m_bEditable(sal_True)
167 		    ,m_bModified(sal_False)
168             ,m_bNotAttached(true)
169         {
170         }
171 
172         bool    documentHasScriptSupport() const
173         {
174             OSL_PRECOND( !!m_aDocScriptSupport,
175                 "DBSubComponentController_Impl::documentHasScriptSupport: not completely initialized, yet - don't know!?" );
176             return !!m_aDocScriptSupport && *m_aDocScriptSupport;
177         }
178 
179         void    setDocumentScriptSupport( const bool _bSupport )
180         {
181             OSL_PRECOND( !m_aDocScriptSupport,
182                 "DBSubComponentController_Impl::setDocumentScriptSupport: already initialized!" );
183             m_aDocScriptSupport = ::boost::optional< bool >( _bSupport );
184         }
185     };
186 
187 	//====================================================================
188 	//= DBSubComponentController
189 	//====================================================================
190 	//--------------------------------------------------------------------
191 	DBSubComponentController::DBSubComponentController(const Reference< XMultiServiceFactory >& _rxORB)
192         :DBSubComponentController_Base( _rxORB )
193         ,m_pImpl( new DBSubComponentController_Impl( getMutex() ) )
194 	{
195 	}
196 
197     //--------------------------------------------------------------------
198     DBSubComponentController::~DBSubComponentController()
199     {
200     }
201 
202 	//--------------------------------------------------------------------
203     void DBSubComponentController::impl_initialize()
204     {
205         OGenericUnoController::impl_initialize();
206 
207         const ::comphelper::NamedValueCollection& rArguments( getInitParams() );
208 
209 		Reference< XConnection > xConnection;
210         xConnection = rArguments.getOrDefault( (::rtl::OUString)PROPERTY_ACTIVE_CONNECTION, xConnection );
211 
212         if ( !xConnection.is() )
213             ::dbtools::isEmbeddedInDatabase( getModel(), xConnection );
214 
215 		if ( xConnection.is() )
216             initializeConnection( xConnection );
217 
218 		bool bShowError = true;
219 		if ( !isConnected() )
220         {
221 			reconnect( sal_False );
222 			bShowError = false;
223 		}
224 		if ( !isConnected() )
225 		{
226 			if ( bShowError )
227 				connectionLostMessage();
228 			throw IllegalArgumentException();
229 		}
230     }
231 
232     //--------------------------------------------------------------------
233     Any SAL_CALL DBSubComponentController::queryInterface(const Type& _rType) throw (RuntimeException)
234     {
235         if ( _rType.equals( XScriptInvocationContext::static_type() ) )
236         {
237             if ( m_pImpl->documentHasScriptSupport() )
238                 return makeAny( Reference< XScriptInvocationContext >( this ) );
239             return Any();
240         }
241 
242         return DBSubComponentController_Base::queryInterface( _rType );
243     }
244 
245     //--------------------------------------------------------------------
246     Sequence< Type > SAL_CALL DBSubComponentController::getTypes(  ) throw (RuntimeException)
247     {
248         Sequence< Type > aTypes( DBSubComponentController_Base::getTypes() );
249         if ( !m_pImpl->documentHasScriptSupport() )
250         {
251             Sequence< Type > aStrippedTypes( aTypes.getLength() - 1 );
252             ::std::remove_copy_if(
253                 aTypes.getConstArray(),
254                 aTypes.getConstArray() + aTypes.getLength(),
255                 aStrippedTypes.getArray(),
256                 ::std::bind2nd( ::std::equal_to< Type >(), XScriptInvocationContext::static_type() )
257             );
258             aTypes = aStrippedTypes;
259         }
260         return aTypes;
261     }
262 
263 	//--------------------------------------------------------------------
264 	void DBSubComponentController::initializeConnection( const Reference< XConnection >& _rxForeignConn )
265 	{
266 		DBG_ASSERT( !isConnected(), "DBSubComponentController::initializeConnection: not to be called when already connected!" );
267 			// usually this gets called from within initialize of derived classes ...
268 		if ( isConnected() )
269 			disconnect();
270 
271         m_pImpl->m_xConnection.reset( _rxForeignConn, SharedConnection::NoTakeOwnership );
272         m_pImpl->m_aSdbMetaData.reset( m_pImpl->m_xConnection );
273 		startConnectionListening( m_pImpl->m_xConnection );
274 
275 		// get the data source the connection belongs to
276 		try
277 		{
278             // determine our data source
279             OSL_PRECOND( !m_pImpl->m_aDataSource.is(), "DBSubComponentController::initializeConnection: already a data source in this phase?" );
280             {
281 			    Reference< XChild > xConnAsChild( m_pImpl->m_xConnection, UNO_QUERY );
282 			    Reference< XDataSource > xDS;
283 			    if ( xConnAsChild.is() )
284 				    xDS = Reference< XDataSource >( xConnAsChild->getParent(), UNO_QUERY );
285 
286 			    // (take the indirection through XDataSource to ensure we have a correct object ....)
287 			    m_pImpl->m_aDataSource = xDS;
288             }
289             OSL_POSTCOND( m_pImpl->m_aDataSource.is(), "DBSubComponentController::initializeConnection: unable to obtain the data source object!" );
290 
291             if ( m_pImpl->m_bNotAttached )
292             {
293                 Reference< XUntitledNumbers > xUntitledProvider( getDatabaseDocument(), UNO_QUERY );
294                 m_pImpl->m_nDocStartNumber = 1;
295                 if ( xUntitledProvider.is() )
296                     m_pImpl->m_nDocStartNumber = xUntitledProvider->leaseNumber( static_cast< XWeak* >( this ) );
297             }
298 
299             // determine the availability of script support in our document. Our own XScriptInvocationContext
300             // interface depends on this
301             m_pImpl->setDocumentScriptSupport( Reference< XEmbeddedScripts >( getDatabaseDocument(), UNO_QUERY ).is() );
302 
303             // get a number formatter
304             Reference< XPropertySet > xDataSourceProps( m_pImpl->m_aDataSource.getDataSourceProps(), UNO_SET_THROW );
305 			xDataSourceProps->getPropertyValue( PROPERTY_NAME ) >>= m_pImpl->m_sDataSourceName;
306 			DBG_ASSERT( m_pImpl->m_sDataSourceName.getLength(), "DBSubComponentController::initializeConnection: invalid data source name!" );
307 			Reference< XNumberFormatsSupplier> xSupplier = ::dbtools::getNumberFormats(m_pImpl->m_xConnection);
308 			if(xSupplier.is())
309 			{
310 				m_pImpl->m_xFormatter = Reference< XNumberFormatter >(getORB()
311 					->createInstance(::rtl::OUString::createFromAscii("com.sun.star.util.NumberFormatter")), UNO_QUERY);
312 				m_pImpl->m_xFormatter->attachNumberFormatsSupplier(xSupplier);
313 			}
314 			OSL_ENSURE(m_pImpl->m_xFormatter.is(),"No NumberFormatter!");
315 		}
316         catch( const Exception& )
317         {
318             DBG_UNHANDLED_EXCEPTION();
319         }
320 	}
321 
322 	//--------------------------------------------------------------------
323 	void DBSubComponentController::reconnect( sal_Bool _bUI )
324 	{
325 		OSL_ENSURE(!m_pImpl->m_bSuspended, "Cannot reconnect while suspended!");
326 
327 		stopConnectionListening( m_pImpl->m_xConnection );
328         m_pImpl->m_aSdbMetaData.reset( NULL );
329         m_pImpl->m_xConnection.clear();
330 
331 		// reconnect
332 		sal_Bool bReConnect = sal_True;
333 		if ( _bUI )
334 		{
335 			QueryBox aQuery( getView(), ModuleRes(QUERY_CONNECTION_LOST) );
336 			bReConnect = ( RET_YES == aQuery.Execute() );
337 		}
338 
339 		// now really reconnect ...
340 		if ( bReConnect )
341         {
342             m_pImpl->m_xConnection.reset( connect( m_pImpl->m_aDataSource.getDataSource(), NULL ), SharedConnection::TakeOwnership );
343             m_pImpl->m_aSdbMetaData.reset( m_pImpl->m_xConnection );
344         }
345 
346 		// invalidate all slots
347 		InvalidateAll();
348 	}
349 
350 	//--------------------------------------------------------------------
351 	void DBSubComponentController::disconnect()
352 	{
353 		stopConnectionListening(m_pImpl->m_xConnection);
354         m_pImpl->m_aSdbMetaData.reset( NULL );
355         m_pImpl->m_xConnection.clear();
356 
357 		InvalidateAll();
358 	}
359 
360 	//--------------------------------------------------------------------
361 	void DBSubComponentController::losingConnection()
362 	{
363 		// our connection was disposed so we need a new one
364 		reconnect( sal_True );
365 	    InvalidateAll();
366 	}
367 
368 	//--------------------------------------------------------------------
369 	void SAL_CALL DBSubComponentController::disposing()
370 	{
371 		DBSubComponentController_Base::disposing();
372 
373         disconnect();
374 
375 		attachFrame( Reference < XFrame >() );
376 
377 		m_pImpl->m_aDataSource.clear();
378 	}
379 
380 	//--------------------------------------------------------------------
381 	void SAL_CALL DBSubComponentController::disposing(const EventObject& _rSource) throw( RuntimeException )
382 	{
383         if ( _rSource.Source == getConnection() )
384         {
385 		    if (    !m_pImpl->m_bSuspended // when already suspended then we don't have to reconnect
386 			    &&	!getBroadcastHelper().bInDispose
387 			    &&	!getBroadcastHelper().bDisposed
388 			    &&	isConnected()
389 			    )
390 		    {
391 			    losingConnection();
392 		    }
393             else
394             {
395                 m_pImpl->m_xConnection.reset( m_pImpl->m_xConnection, SharedConnection::NoTakeOwnership );
396                     // this prevents the "disposeComponent" call in disconnect
397                 disconnect();
398             }
399         }
400 		else
401             DBSubComponentController_Base::disposing( _rSource );
402 	}
403 
404     //--------------------------------------------------------------------
405     void DBSubComponentController::appendError( const ::rtl::OUString& _rErrorMessage, const ::dbtools::StandardSQLState _eSQLState,
406             const sal_Int32 _nErrorCode )
407 	{
408         m_pImpl->m_aCurrentError.append( ::dbtools::SQLExceptionInfo::SQL_EXCEPTION, _rErrorMessage, getStandardSQLStateAscii( _eSQLState ),
409             _nErrorCode );
410 	}
411 	//--------------------------------------------------------------------
412 	void DBSubComponentController::clearError()
413 	{
414         m_pImpl->m_aCurrentError = ::dbtools::SQLExceptionInfo();
415 	}
416 
417 	//--------------------------------------------------------------------
418 	sal_Bool DBSubComponentController::hasError() const
419 	{
420 		return m_pImpl->m_aCurrentError.isValid();
421 	}
422 
423 	//--------------------------------------------------------------------
424     const ::dbtools::SQLExceptionInfo& DBSubComponentController::getError() const
425     {
426         return m_pImpl->m_aCurrentError;
427     }
428 
429 	//--------------------------------------------------------------------
430     void DBSubComponentController::displayError()
431     {
432         showError( m_pImpl->m_aCurrentError );
433     }
434 
435 	//--------------------------------------------------------------------
436 	sal_Bool SAL_CALL DBSubComponentController::suspend(sal_Bool bSuspend) throw( RuntimeException )
437 	{
438 		m_pImpl->m_bSuspended = bSuspend;
439 		if ( !bSuspend && !isConnected() )
440 			reconnect(sal_True);
441 
442 
443 		return sal_True;
444 	}
445 
446     // -----------------------------------------------------------------------------
447     sal_Bool SAL_CALL DBSubComponentController::attachModel( const Reference< XModel > & _rxModel) throw( RuntimeException )
448     {
449         if ( !_rxModel.is() )
450             return sal_False;
451         if ( !DBSubComponentController_Base::attachModel( _rxModel ) )
452             return sal_False;
453 
454         m_pImpl->m_bNotAttached = false;
455         if ( m_pImpl->m_nDocStartNumber == 1 )
456             releaseNumberForComponent();
457 
458         Reference< XUntitledNumbers > xUntitledProvider( _rxModel, UNO_QUERY );
459         m_pImpl->m_nDocStartNumber = 1;
460         if ( xUntitledProvider.is() )
461             m_pImpl->m_nDocStartNumber = xUntitledProvider->leaseNumber( static_cast< XWeak* >( this ) );
462 
463 		return sal_True;
464     }
465 
466 	// -----------------------------------------------------------------------------
467 	void DBSubComponentController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& _rArgs)
468 	{
469         if ( _nId == ID_BROWSER_CLOSE )
470         {
471             closeTask();
472             return;
473         }
474 
475         DBSubComponentController_Base::Execute( _nId, _rArgs );
476 		InvalidateFeature( _nId );
477 	}
478 
479 	// -----------------------------------------------------------------------------
480 	::rtl::OUString DBSubComponentController::getDataSourceName() const
481 	{
482 		::rtl::OUString sName;
483         Reference< XPropertySet > xDataSourceProps( m_pImpl->m_aDataSource.getDataSourceProps() );
484 		if ( xDataSourceProps.is() )
485 			xDataSourceProps->getPropertyValue(PROPERTY_NAME) >>= sName;
486 		return sName;
487 	}
488 	// -----------------------------------------------------------------------------
489 	void DBSubComponentController::connectionLostMessage() const
490 	{
491 		String aMessage(ModuleRes(RID_STR_CONNECTION_LOST));
492 		Reference< XWindow > xWindow = getTopMostContainerWindow();
493 		Window* pWin = NULL;
494 		if ( xWindow.is() )
495 			pWin = VCLUnoHelper::GetWindow(xWindow);
496 		if ( !pWin )
497 			pWin = getView()->Window::GetParent();
498 
499 		InfoBox(pWin, aMessage).Execute();
500 	}
501 	// -----------------------------------------------------------------------------
502 	const Reference< XConnection >& DBSubComponentController::getConnection() const
503 	{
504 		return m_pImpl->m_xConnection;
505 	}
506 
507     // -----------------------------------------------------------------------------
508     sal_Bool DBSubComponentController::isReadOnly() const
509     {
510         return !m_pImpl->m_bEditable;
511     }
512 
513 	// -----------------------------------------------------------------------------
514 	sal_Bool DBSubComponentController::isEditable() const
515     {
516         return m_pImpl->m_bEditable;
517     }
518 
519 	// -----------------------------------------------------------------------------
520     void DBSubComponentController::setEditable(sal_Bool _bEditable)
521     {
522         m_pImpl->m_bEditable = _bEditable;
523     }
524 
525 	// -----------------------------------------------------------------------------
526     const ::dbtools::DatabaseMetaData& DBSubComponentController::getSdbMetaData() const
527     {
528         return m_pImpl->m_aSdbMetaData;
529     }
530 
531 	// -----------------------------------------------------------------------------
532     sal_Bool DBSubComponentController::isConnected() const
533     {
534         return m_pImpl->m_xConnection.is();
535     }
536 
537 	// -----------------------------------------------------------------------------
538     Reference< XDatabaseMetaData > DBSubComponentController::getMetaData( ) const
539     {
540         Reference< XDatabaseMetaData > xMeta;
541         try
542         {
543             if ( isConnected() )
544                 xMeta.set( m_pImpl->m_xConnection->getMetaData(), UNO_SET_THROW );
545         }
546         catch( const Exception& )
547         {
548         	DBG_UNHANDLED_EXCEPTION();
549         }
550         return xMeta;
551     }
552 
553 	// -----------------------------------------------------------------------------
554     const Reference< XPropertySet >& DBSubComponentController::getDataSource() const
555     {
556         return m_pImpl->m_aDataSource.getDataSourceProps();
557     }
558 
559 	// -----------------------------------------------------------------------------
560     sal_Bool DBSubComponentController::haveDataSource() const
561     {
562         return m_pImpl->m_aDataSource.is();
563     }
564 
565 	// -----------------------------------------------------------------------------
566     Reference< XModel > DBSubComponentController::getDatabaseDocument() const
567     {
568         return Reference< XModel >( m_pImpl->m_aDataSource.getDatabaseDocument(), UNO_QUERY );
569     }
570 
571 	// -----------------------------------------------------------------------------
572     Reference< XNumberFormatter > DBSubComponentController::getNumberFormatter() const
573     {
574         return m_pImpl->m_xFormatter;
575     }
576 
577     // -----------------------------------------------------------------------------
578     Reference< XModel > DBSubComponentController::getPrivateModel() const
579     {
580 		return getDatabaseDocument();
581     }
582     // -----------------------------------------------------------------------------
583     // XTitle
584     ::rtl::OUString SAL_CALL DBSubComponentController::getTitle()
585         throw (RuntimeException)
586     {
587         ::osl::MutexGuard aGuard( getMutex() );
588         if ( m_bExternalTitle )
589             return impl_getTitleHelper_throw()->getTitle ();
590 
591         ::rtl::OUStringBuffer sTitle;
592         Reference< XTitle > xTitle(getPrivateModel(),UNO_QUERY);
593         if ( xTitle.is() )
594         {
595             sTitle.append( xTitle->getTitle() );
596             sTitle.appendAscii(" : ");
597         }
598         sTitle.append( getPrivateTitle() );
599         return sTitle.makeStringAndClear();
600     }
601 
602     // -----------------------------------------------------------------------------
603     sal_Int32 DBSubComponentController::getCurrentStartNumber() const
604     {
605         return m_pImpl->m_nDocStartNumber;
606     }
607 
608     // -----------------------------------------------------------------------------
609     Reference< XEmbeddedScripts > SAL_CALL DBSubComponentController::getScriptContainer() throw (RuntimeException)
610     {
611         ::osl::MutexGuard aGuard( getMutex() );
612         if ( !m_pImpl->documentHasScriptSupport() )
613             return NULL;
614 
615         return Reference< XEmbeddedScripts >( getDatabaseDocument(), UNO_QUERY_THROW );
616     }
617 
618     // -----------------------------------------------------------------------------
619     void SAL_CALL DBSubComponentController::addModifyListener( const Reference< XModifyListener >& i_Listener ) throw (RuntimeException)
620     {
621         ::osl::MutexGuard aGuard( getMutex() );
622         m_pImpl->m_aModifyListeners.addInterface( i_Listener );
623     }
624 
625     // -----------------------------------------------------------------------------
626     void SAL_CALL DBSubComponentController::removeModifyListener( const Reference< XModifyListener >& i_Listener ) throw (RuntimeException)
627     {
628         ::osl::MutexGuard aGuard( getMutex() );
629         m_pImpl->m_aModifyListeners.removeInterface( i_Listener );
630     }
631 
632     // -----------------------------------------------------------------------------
633     ::sal_Bool SAL_CALL DBSubComponentController::isModified(  ) throw (RuntimeException)
634     {
635         ::osl::MutexGuard aGuard( getMutex() );
636         return impl_isModified();
637     }
638 
639     // -----------------------------------------------------------------------------
640     void SAL_CALL DBSubComponentController::setModified( ::sal_Bool i_bModified ) throw (PropertyVetoException, RuntimeException)
641     {
642         ::osl::ClearableMutexGuard aGuard( getMutex() );
643 
644         if ( m_pImpl->m_bModified == i_bModified )
645             return;
646 
647 		m_pImpl->m_bModified = i_bModified;
648         impl_onModifyChanged();
649 
650         EventObject aEvent( *this );
651         aGuard.clear();
652         m_pImpl->m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent );
653     }
654 
655     // -----------------------------------------------------------------------------
656     sal_Bool DBSubComponentController::impl_isModified() const
657     {
658         return m_pImpl->m_bModified;
659     }
660 
661     // -----------------------------------------------------------------------------
662     void DBSubComponentController::impl_onModifyChanged()
663     {
664         InvalidateFeature( ID_BROWSER_SAVEDOC );
665         if ( isFeatureSupported( ID_BROWSER_SAVEASDOC ) )
666             InvalidateFeature( ID_BROWSER_SAVEASDOC );
667     }
668 
669 //........................................................................
670 }	// namespace dbaui
671 //........................................................................
672 
673