xref: /trunk/main/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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