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