1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "subcomponentmanager.hxx"
21 #include "AppController.hxx"
22 #include "dbustrings.hrc"
24 #include <com/sun/star/frame/XFrame.hpp>
25 #include <com/sun/star/frame/XModel.hpp>
26 #include <com/sun/star/frame/XModel2.hpp>
27 #include <com/sun/star/util/XCloseable.hpp>
28 #include <com/sun/star/awt/XTopWindow.hpp>
29 #include <com/sun/star/embed/XComponentSupplier.hpp>
30 #include <com/sun/star/ucb/XCommandProcessor.hpp>
31 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <tools/diagnose_ex.h>
35 #include <dbaccess/dataview.hxx>
36 #include <vcl/svapp.hxx>
37 #include <osl/mutex.hxx>
45 using ::com::sun::star::uno::Reference
;
46 using ::com::sun::star::uno::XInterface
;
47 using ::com::sun::star::uno::UNO_QUERY
;
48 using ::com::sun::star::uno::UNO_QUERY_THROW
;
49 using ::com::sun::star::uno::UNO_SET_THROW
;
50 using ::com::sun::star::uno::Exception
;
51 using ::com::sun::star::uno::RuntimeException
;
52 using ::com::sun::star::uno::Any
;
53 using ::com::sun::star::uno::makeAny
;
54 using ::com::sun::star::uno::Sequence
;
55 using ::com::sun::star::uno::Type
;
56 using ::com::sun::star::frame::XFrame
;
57 using ::com::sun::star::frame::XController
;
58 using ::com::sun::star::frame::XModel
;
59 using ::com::sun::star::lang::EventObject
;
60 using ::com::sun::star::lang::XComponent
;
61 using ::com::sun::star::frame::XModel2
;
62 using ::com::sun::star::container::XEnumeration
;
63 using ::com::sun::star::util::XCloseable
;
64 using ::com::sun::star::awt::XTopWindow
;
65 using ::com::sun::star::embed::XComponentSupplier
;
66 using ::com::sun::star::ucb::XCommandProcessor
;
67 using ::com::sun::star::ucb::Command
;
68 using ::com::sun::star::document::XDocumentEventBroadcaster
;
69 using ::com::sun::star::beans::XPropertySet
;
70 using ::com::sun::star::beans::PropertyChangeEvent
;
75 struct SubComponentDescriptor
77 /// the name of the sub component, empty if it is yet unsaved
79 /// type of the component - an ElementType value, except for relation design
80 sal_Int32 nComponentType
;
81 /// the mode in which the sub component has been opened
82 ElementOpenMode eOpenMode
;
83 /// the frame which the component resides in. Must not be <NULL/>
84 Reference
< XFrame
> xFrame
;
85 /// the controller of the sub component. Must not be <NULL/>
86 Reference
< XController
> xController
;
87 /// the model of the sub component. Might be <NULL/>
88 Reference
< XModel
> xModel
;
89 /// the document definition which holds the component, if any; as CommandProcessor
90 Reference
< XCommandProcessor
> xComponentCommandProcessor
;
91 /// the document definition which holds the component, if any; as PropertySet
92 Reference
< XPropertySet
> xDocumentDefinitionProperties
;
94 SubComponentDescriptor()
97 ,eOpenMode( E_OPEN_NORMAL
)
104 SubComponentDescriptor( const OUString
& i_rName
, const sal_Int32 i_nComponentType
,
105 const ElementOpenMode i_eOpenMode
, const Reference
< XComponent
>& i_rComponent
)
107 ,nComponentType( i_nComponentType
)
108 ,eOpenMode( i_eOpenMode
)
110 if ( !impl_constructFrom( i_rComponent
) )
112 // i_rComponent is neither a model, nor a controller, nor a frame
113 // => it must be a css.sdb.DocumentDefinition
114 Reference
< XComponentSupplier
> xCompSupp( i_rComponent
, UNO_QUERY_THROW
);
115 Reference
< XComponent
> xComponent( xCompSupp
->getComponent(), UNO_QUERY_THROW
);
116 if ( !impl_constructFrom( xComponent
) )
117 throw RuntimeException("Illegal component type." );
118 xComponentCommandProcessor
.set( i_rComponent
, UNO_QUERY_THROW
);
119 xDocumentDefinitionProperties
.set( i_rComponent
, UNO_QUERY_THROW
);
123 inline bool is() const { return xFrame
.is(); }
126 bool impl_constructFrom( const Reference
< XComponent
>& _rxComponent
)
129 xModel
.set( _rxComponent
, UNO_QUERY
);
132 xController
.set( xModel
->getCurrentController() );
133 if ( xController
.is() )
134 xFrame
.set( xController
->getFrame(), UNO_SET_THROW
);
138 // is it a controller?
139 xController
.set( _rxComponent
, UNO_QUERY
);
140 if ( xController
.is() )
142 xFrame
.set( xController
->getFrame(), UNO_SET_THROW
);
147 xFrame
.set( _rxComponent
, UNO_QUERY
);
151 // ensure we have a controller
152 xController
.set( xFrame
->getController(), UNO_SET_THROW
);
155 // check whether there is a model (not required)
156 xModel
.set( xController
->getModel() );
163 struct SelectSubComponent
: public ::std::unary_function
< SubComponentDescriptor
, Reference
< XComponent
> >
165 Reference
< XComponent
> operator()( const SubComponentDescriptor
&_desc
) const
167 if ( _desc
.xModel
.is() )
168 return _desc
.xModel
.get();
169 OSL_ENSURE( _desc
.xController
.is(), "SelectSubComponent::operator(): illegal component!" );
170 return _desc
.xController
.get();
174 typedef ::std::vector
< SubComponentDescriptor
> SubComponents
;
176 struct SubComponentMatch
: public ::std::unary_function
< SubComponentDescriptor
, bool >
179 SubComponentMatch( const OUString
& i_rName
, const sal_Int32 i_nComponentType
,
180 const ElementOpenMode i_eOpenMode
)
182 ,m_nComponentType( i_nComponentType
)
183 ,m_eOpenMode( i_eOpenMode
)
187 bool operator()( const SubComponentDescriptor
& i_rCompareWith
) const
189 return ( m_sName
== i_rCompareWith
.sName
)
190 && ( m_nComponentType
== i_rCompareWith
.nComponentType
)
191 && ( m_eOpenMode
== i_rCompareWith
.eOpenMode
);
194 const OUString m_sName
;
195 const sal_Int32 m_nComponentType
;
196 const ElementOpenMode m_eOpenMode
;
200 // SubComponentManager_Data
201 struct SubComponentManager_Data
203 SubComponentManager_Data( OApplicationController
& _rController
, const ::comphelper::SharedMutex
& _rMutex
)
204 :m_rController( _rController
)
209 OApplicationController
& m_rController
;
210 mutable ::comphelper::SharedMutex m_aMutex
;
211 SubComponents m_aComponents
;
213 ::osl::Mutex
& getMutex() const { return m_aMutex
; }
216 // SubComponentManager
217 SubComponentManager::SubComponentManager( OApplicationController
& _rController
, const ::comphelper::SharedMutex
& _rMutex
)
218 :m_pData( new SubComponentManager_Data( _rController
, _rMutex
) )
222 SubComponentManager::~SubComponentManager()
226 void SubComponentManager::disposing()
228 ::osl::MutexGuard
aGuard( m_pData
->getMutex() );
229 m_pData
->m_aComponents
.clear();
234 bool lcl_fallbackToAnotherController( SubComponentDescriptor
& _rCompDesc
)
236 Reference
< XController
> xFallback
;
237 OSL_PRECOND( _rCompDesc
.xModel
.is(), "lcl_fallbackToAnotherController: illegal call!" );
238 if ( !_rCompDesc
.xModel
.is() )
241 xFallback
.set( _rCompDesc
.xModel
->getCurrentController() );
242 if ( xFallback
== _rCompDesc
.xController
)
243 // don't accept the very same controller as fallback
246 if ( !xFallback
.is() )
248 // perhaps XModel2 can be of help here
249 Reference
< XModel2
> xModel2( _rCompDesc
.xModel
, UNO_QUERY
);
250 Reference
< XEnumeration
> xControllerEnum
;
252 xControllerEnum
= xModel2
->getControllers();
253 while ( xControllerEnum
.is() && xControllerEnum
->hasMoreElements() )
255 xFallback
.set( xControllerEnum
->nextElement(), UNO_QUERY
);
256 if ( xFallback
== _rCompDesc
.xController
)
261 if ( xFallback
.is() )
263 _rCompDesc
.xController
= xFallback
;
264 _rCompDesc
.xFrame
.set( xFallback
->getFrame(), UNO_SET_THROW
);
271 bool lcl_closeComponent( const Reference
< XCommandProcessor
>& _rxCommandProcessor
)
273 bool bSuccess
= false;
276 sal_Int32 nCommandIdentifier
= _rxCommandProcessor
->createCommandIdentifier();
279 aCommand
.Name
= "close";
280 _rxCommandProcessor
->execute( aCommand
, nCommandIdentifier
, NULL
);
283 catch( const Exception
& )
285 DBG_UNHANDLED_EXCEPTION();
290 bool lcl_closeComponent( const SubComponentDescriptor
& _rComponent
)
292 if ( _rComponent
.xComponentCommandProcessor
.is() )
293 return lcl_closeComponent( _rComponent
.xComponentCommandProcessor
);
295 Reference
< XController
> xController( _rComponent
.xController
);
296 OSL_ENSURE( xController
.is(), "lcl_closeComponent: invalid controller!" );
298 // suspend the controller in the document
299 if ( xController
.is() )
300 if ( !xController
->suspend( sal_True
) )
303 bool bSuccess
= false;
306 Reference
< XCloseable
> xCloseable( _rComponent
.xFrame
, UNO_QUERY_THROW
);
307 xCloseable
->close( sal_True
);
310 catch( const Exception
& )
312 DBG_UNHANDLED_EXCEPTION();
317 void lcl_notifySubComponentEvent( const SubComponentManager_Data
& _rData
, const sal_Char
* _pAsciiEventName
,
318 const SubComponentDescriptor
& _rComponent
)
322 Reference
< XDocumentEventBroadcaster
> xBroadcaster( _rData
.m_rController
.getModel(), UNO_QUERY_THROW
);
323 xBroadcaster
->notifyDocumentEvent(
324 OUString::createFromAscii( _pAsciiEventName
),
325 &_rData
.m_rController
,
326 makeAny( _rComponent
.xFrame
)
329 catch( const Exception
& )
331 DBG_UNHANDLED_EXCEPTION();
336 void SAL_CALL
SubComponentManager::propertyChange( const PropertyChangeEvent
& i_rEvent
) throw (RuntimeException
, std::exception
)
338 if ( i_rEvent
.PropertyName
!= PROPERTY_NAME
)
339 // by definition, it's allowed to broadcast more than what we've registered for
342 // find the sub component whose name changed
343 for ( SubComponents::iterator comp
= m_pData
->m_aComponents
.begin();
344 comp
!= m_pData
->m_aComponents
.end();
348 if ( comp
->xDocumentDefinitionProperties
!= i_rEvent
.Source
)
352 OSL_VERIFY( i_rEvent
.NewValue
>>= sNewName
);
354 #if OSL_DEBUG_LEVEL > 0
355 OUString
sOldKnownName( comp
->sName
);
357 OSL_VERIFY( i_rEvent
.OldValue
>>= sOldName
);
358 OSL_ENSURE( sOldName
== sOldKnownName
, "SubComponentManager::propertyChange: inconsistency in the old names!" );
361 comp
->sName
= sNewName
;
366 void SAL_CALL
SubComponentManager::disposing( const EventObject
& _rSource
) throw (RuntimeException
, std::exception
)
368 ::osl::ClearableMutexGuard
aGuard( m_pData
->getMutex() );
370 SubComponentDescriptor aClosedComponent
;
372 for ( SubComponents::iterator comp
= m_pData
->m_aComponents
.begin();
373 comp
!= m_pData
->m_aComponents
.end();
377 bool bRemove
= false;
379 if ( comp
->xController
== _rSource
.Source
)
381 if ( !comp
->xModel
.is() )
387 // maybe this is just one view to the sub document, and only this view is closed
388 if ( !lcl_fallbackToAnotherController( *comp
) )
394 else if ( comp
->xModel
== _rSource
.Source
)
401 aClosedComponent
= *comp
;
402 m_pData
->m_aComponents
.erase( comp
);
407 if ( aClosedComponent
.is() )
410 lcl_notifySubComponentEvent( *m_pData
, "OnSubComponentClosed", aClosedComponent
);
414 Sequence
< Reference
< XComponent
> > SubComponentManager::getSubComponents() const
416 ::osl::MutexGuard
aGuard( m_pData
->getMutex() );
418 Sequence
< Reference
< XComponent
> > aComponents( m_pData
->m_aComponents
.size() );
420 m_pData
->m_aComponents
.begin(),
421 m_pData
->m_aComponents
.end(),
422 aComponents
.getArray(),
428 bool SubComponentManager::closeSubComponents()
430 SolarMutexGuard aSolarGuard
;
431 ::osl::MutexGuard
aGuard( m_pData
->getMutex() );
435 SubComponents
aWorkingCopy( m_pData
->m_aComponents
);
436 for ( SubComponents::const_iterator comp
= aWorkingCopy
.begin();
437 comp
!= aWorkingCopy
.end();
441 lcl_closeComponent( *comp
);
444 catch ( const Exception
& )
446 DBG_UNHANDLED_EXCEPTION();
452 bool SubComponentManager::empty() const
454 ::osl::MutexGuard
aGuard( m_pData
->getMutex() );
455 return m_pData
->m_aComponents
.empty();
458 void SubComponentManager::onSubComponentOpened( const OUString
& _rName
, const sal_Int32 _nComponentType
,
459 const ElementOpenMode _eOpenMode
, const Reference
< XComponent
>& _rxComponent
)
461 ::osl::ClearableMutexGuard
aGuard( m_pData
->getMutex() );
463 #if OSL_DEBUG_LEVEL > 0
464 if ( !_rName
.isEmpty() )
466 // check there does not already exist such a component
467 SubComponents::const_iterator existentPos
= ::std::find_if(
468 m_pData
->m_aComponents
.begin(),
469 m_pData
->m_aComponents
.end(),
470 SubComponentMatch( _rName
, _nComponentType
, _eOpenMode
)
472 OSL_ENSURE( existentPos
== m_pData
->m_aComponents
.end(), "already existent!" );
475 SubComponentDescriptor
aElement( _rName
, _nComponentType
, _eOpenMode
, _rxComponent
);
476 ENSURE_OR_THROW( aElement
.xModel
.is() || aElement
.xController
.is(), "illegal component" );
478 m_pData
->m_aComponents
.push_back( aElement
);
481 if ( aElement
.xController
.is() )
482 aElement
.xController
->addEventListener( this );
483 if ( aElement
.xModel
.is() )
484 aElement
.xModel
->addEventListener( this );
485 if ( aElement
.xDocumentDefinitionProperties
.is() )
486 aElement
.xDocumentDefinitionProperties
->addPropertyChangeListener( PROPERTY_NAME
, this );
488 // notify this to interested parties
490 lcl_notifySubComponentEvent( *m_pData
, "OnSubComponentOpened", aElement
);
493 bool SubComponentManager::activateSubFrame( const OUString
& _rName
, const sal_Int32 _nComponentType
,
494 const ElementOpenMode _eOpenMode
, Reference
< XComponent
>& o_rComponent
) const
496 ::osl::MutexGuard
aGuard( m_pData
->getMutex() );
498 SubComponents::const_iterator pos
= ::std::find_if(
499 m_pData
->m_aComponents
.begin(),
500 m_pData
->m_aComponents
.end(),
501 SubComponentMatch( _rName
, _nComponentType
, _eOpenMode
)
503 if ( pos
== m_pData
->m_aComponents
.end() )
504 // no component with this name/type/open mode
507 const Reference
< XFrame
> xFrame( pos
->xFrame
, UNO_SET_THROW
);
508 const Reference
< XTopWindow
> xTopWindow( xFrame
->getContainerWindow(), UNO_QUERY_THROW
);
509 xTopWindow
->toFront();
511 if ( pos
->xModel
.is() )
512 o_rComponent
= pos
->xModel
.get();
513 else if ( pos
->xController
.is() )
514 o_rComponent
= pos
->xController
.get();
516 o_rComponent
= pos
->xFrame
.get();
521 bool SubComponentManager::closeSubFrames( const OUString
& i_rName
, const sal_Int32 _nComponentType
)
523 ::osl::MutexGuard
aGuard( m_pData
->getMutex() );
524 ENSURE_OR_RETURN_FALSE( !i_rName
.isEmpty(), "SubComponentManager::closeSubFrames: illegal name!" );
526 SubComponents
aWorkingCopy( m_pData
->m_aComponents
);
527 for ( SubComponents::const_iterator comp
= aWorkingCopy
.begin();
528 comp
!= aWorkingCopy
.end();
532 if ( ( comp
->sName
!= i_rName
) || ( comp
->nComponentType
!= _nComponentType
) )
535 if ( !lcl_closeComponent( *comp
) )
542 bool SubComponentManager::lookupSubComponent( const Reference
< XComponent
>& i_rComponent
,
543 OUString
& o_rName
, sal_Int32
& o_rComponentType
)
545 for ( SubComponents::const_iterator comp
= m_pData
->m_aComponents
.begin();
546 comp
!= m_pData
->m_aComponents
.end();
550 if ( ( comp
->xModel
.is()
551 && ( comp
->xModel
== i_rComponent
)
553 || ( comp
->xController
.is()
554 && ( comp
->xController
== i_rComponent
)
556 || ( comp
->xFrame
.is()
557 && ( comp
->xFrame
== i_rComponent
)
561 o_rName
= comp
->sName
;
562 o_rComponentType
= comp
->nComponentType
;
571 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */