1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 #include "subcomponentmanager.hxx"
29 #include "AppController.hxx"
30 #include "dbustrings.hrc"
32 /** === begin UNO includes === **/
33 #include <com/sun/star/frame/XFrame.hpp>
34 #include <com/sun/star/frame/XModel.hpp>
35 #include <com/sun/star/frame/XModel2.hpp>
36 #include <com/sun/star/util/XCloseable.hpp>
37 #include <com/sun/star/awt/XTopWindow.hpp>
38 #include <com/sun/star/embed/XComponentSupplier.hpp>
39 #include <com/sun/star/ucb/XCommandProcessor.hpp>
40 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 /** === end UNO includes === **/
44 #include <tools/diagnose_ex.h>
45 #include <vcl/svapp.hxx>
46 #include <osl/mutex.hxx>
51 //......................................................................................................................
54 //......................................................................................................................
56 /** === begin UNO using === **/
57 using ::com::sun::star::uno::Reference
;
58 using ::com::sun::star::uno::XInterface
;
59 using ::com::sun::star::uno::UNO_QUERY
;
60 using ::com::sun::star::uno::UNO_QUERY_THROW
;
61 using ::com::sun::star::uno::UNO_SET_THROW
;
62 using ::com::sun::star::uno::Exception
;
63 using ::com::sun::star::uno::RuntimeException
;
64 using ::com::sun::star::uno::Any
;
65 using ::com::sun::star::uno::makeAny
;
66 using ::com::sun::star::uno::Sequence
;
67 using ::com::sun::star::uno::Type
;
68 using ::com::sun::star::frame::XFrame
;
69 using ::com::sun::star::frame::XController
;
70 using ::com::sun::star::frame::XModel
;
71 using ::com::sun::star::lang::EventObject
;
72 using ::com::sun::star::lang::XComponent
;
73 using ::com::sun::star::frame::XModel2
;
74 using ::com::sun::star::container::XEnumeration
;
75 using ::com::sun::star::util::XCloseable
;
76 using ::com::sun::star::awt::XTopWindow
;
77 using ::com::sun::star::embed::XComponentSupplier
;
78 using ::com::sun::star::ucb::XCommandProcessor
;
79 using ::com::sun::star::ucb::Command
;
80 using ::com::sun::star::document::XDocumentEventBroadcaster
;
81 using ::com::sun::star::beans::XPropertySet
;
82 using ::com::sun::star::beans::PropertyChangeEvent
;
83 /** === end UNO using === **/
85 //==================================================================================================================
87 //==================================================================================================================
90 //..............................................................................................................
91 struct SubComponentDescriptor
93 /// the name of the sub component, empty if it is yet unsaved
94 ::rtl::OUString sName
;
95 /// type of the component - an ElementType value, except for relation design
96 sal_Int32 nComponentType
;
97 /// the mode in which the sub component has been opened
98 ElementOpenMode eOpenMode
;
99 /// the frame which the component resides in. Must not be <NULL/>
100 Reference
< XFrame
> xFrame
;
101 /// the controller of the sub component. Must not be <NULL/>
102 Reference
< XController
> xController
;
103 /// the model of the sub component. Might be <NULL/>
104 Reference
< XModel
> xModel
;
105 /// the document definition which holds the component, if any; as CommandProcessor
106 Reference
< XCommandProcessor
> xComponentCommandProcessor
;
107 /// the document definition which holds the component, if any; as PropertySet
108 Reference
< XPropertySet
> xDocumentDefinitionProperties
;
110 SubComponentDescriptor()
112 ,nComponentType( -1 )
113 ,eOpenMode( E_OPEN_NORMAL
)
120 SubComponentDescriptor( const ::rtl::OUString
& i_rName
, const sal_Int32 i_nComponentType
,
121 const ElementOpenMode i_eOpenMode
, const Reference
< XComponent
>& i_rComponent
)
123 ,nComponentType( i_nComponentType
)
124 ,eOpenMode( i_eOpenMode
)
126 if ( !impl_constructFrom( i_rComponent
) )
128 // i_rComponent is neither a model, nor a controller, nor a frame
129 // => it must be a css.sdb.DocumentDefinition
130 Reference
< XComponentSupplier
> xCompSupp( i_rComponent
, UNO_QUERY_THROW
);
131 Reference
< XComponent
> xComponent( xCompSupp
->getComponent(), UNO_QUERY_THROW
);
132 if ( !impl_constructFrom( xComponent
) )
133 throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Illegal component type." ) ), NULL
);
134 xComponentCommandProcessor
.set( i_rComponent
, UNO_QUERY_THROW
);
135 xDocumentDefinitionProperties
.set( i_rComponent
, UNO_QUERY_THROW
);
139 inline bool is() const { return xFrame
.is(); }
142 bool impl_constructFrom( const Reference
< XComponent
>& _rxComponent
)
145 xModel
.set( _rxComponent
, UNO_QUERY
);
148 xController
.set( xModel
->getCurrentController() );
149 if ( xController
.is() )
150 xFrame
.set( xController
->getFrame(), UNO_SET_THROW
);
154 // is it a controller?
155 xController
.set( _rxComponent
, UNO_QUERY
);
156 if ( xController
.is() )
158 xFrame
.set( xController
->getFrame(), UNO_SET_THROW
);
163 xFrame
.set( _rxComponent
, UNO_QUERY
);
167 // ensure we have a controller
168 xController
.set( xFrame
->getController(), UNO_SET_THROW
);
171 // check whether there is a model (not required)
172 xModel
.set( xController
->getModel() );
179 //..............................................................................................................
180 struct SelectSubComponent
: public ::std::unary_function
< SubComponentDescriptor
, Reference
< XComponent
> >
182 Reference
< XComponent
> operator()( const SubComponentDescriptor
&_desc
) const
184 if ( _desc
.xModel
.is() )
185 return _desc
.xModel
.get();
186 OSL_ENSURE( _desc
.xController
.is(), "SelectSubComponent::operator(): illegal component!" );
187 return _desc
.xController
.get();
191 //..............................................................................................................
192 typedef ::std::vector
< SubComponentDescriptor
> SubComponents
;
194 //..............................................................................................................
195 struct SubComponentMatch
: public ::std::unary_function
< SubComponentDescriptor
, bool >
198 SubComponentMatch( const ::rtl::OUString
& i_rName
, const sal_Int32 i_nComponentType
,
199 const ElementOpenMode i_eOpenMode
)
201 ,m_nComponentType( i_nComponentType
)
202 ,m_eOpenMode( i_eOpenMode
)
206 bool operator()( const SubComponentDescriptor
& i_rCompareWith
) const
208 return ( m_sName
== i_rCompareWith
.sName
)
209 && ( m_nComponentType
== i_rCompareWith
.nComponentType
)
210 && ( m_eOpenMode
== i_rCompareWith
.eOpenMode
);
213 const ::rtl::OUString m_sName
;
214 const sal_Int32 m_nComponentType
;
215 const ElementOpenMode m_eOpenMode
;
219 //==================================================================================================================
220 //= SubComponentManager_Data
221 //==================================================================================================================
222 struct SubComponentManager_Data
224 SubComponentManager_Data( OApplicationController
& _rController
, const ::comphelper::SharedMutex
& _rMutex
)
225 :m_rController( _rController
)
230 OApplicationController
& m_rController
;
231 mutable ::comphelper::SharedMutex m_aMutex
;
232 SubComponents m_aComponents
;
234 ::osl::Mutex
& getMutex() const { return m_aMutex
; }
237 //==================================================================================================================
238 //= SubComponentManager
239 //==================================================================================================================
240 //------------------------------------------------------------------------------------------------------------------
241 SubComponentManager::SubComponentManager( OApplicationController
& _rController
, const ::comphelper::SharedMutex
& _rMutex
)
242 :m_pData( new SubComponentManager_Data( _rController
, _rMutex
) )
246 //------------------------------------------------------------------------------------------------------------------
247 SubComponentManager::~SubComponentManager()
251 //------------------------------------------------------------------------------------------------------------------
252 void SubComponentManager::disposing()
254 ::osl::MutexGuard
aGuard( m_pData
->getMutex() );
255 m_pData
->m_aComponents
.clear();
258 //------------------------------------------------------------------------------------------------------------------
261 //..............................................................................................................
262 bool lcl_fallbackToAnotherController( SubComponentDescriptor
& _rCompDesc
)
264 Reference
< XController
> xFallback
;
265 OSL_PRECOND( _rCompDesc
.xModel
.is(), "lcl_fallbackToAnotherController: illegal call!" );
266 if ( !_rCompDesc
.xModel
.is() )
269 xFallback
.set( _rCompDesc
.xModel
->getCurrentController() );
270 if ( xFallback
== _rCompDesc
.xController
)
271 // don't accept the very same controller as fallback
274 if ( !xFallback
.is() )
276 // perhaps XModel2 can be of help here
277 Reference
< XModel2
> xModel2( _rCompDesc
.xModel
, UNO_QUERY
);
278 Reference
< XEnumeration
> xControllerEnum
;
280 xControllerEnum
= xModel2
->getControllers();
281 while ( xControllerEnum
.is() && xControllerEnum
->hasMoreElements() )
283 xFallback
.set( xControllerEnum
->nextElement(), UNO_QUERY
);
284 if ( xFallback
== _rCompDesc
.xController
)
289 if ( xFallback
.is() )
291 _rCompDesc
.xController
= xFallback
;
292 _rCompDesc
.xFrame
.set( xFallback
->getFrame(), UNO_SET_THROW
);
299 //..............................................................................................................
300 bool lcl_closeComponent( const Reference
< XCommandProcessor
>& _rxCommandProcessor
)
302 bool bSuccess
= false;
305 Reference
< XCommandProcessor
> xCommandProcessor( _rxCommandProcessor
, UNO_SET_THROW
);
306 sal_Int32 nCommandIdentifier
= xCommandProcessor
->createCommandIdentifier();
309 aCommand
.Name
= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "close" ) );
310 xCommandProcessor
->execute( aCommand
, nCommandIdentifier
, NULL
);
313 catch( const Exception
& )
315 DBG_UNHANDLED_EXCEPTION();
320 //..............................................................................................................
321 bool lcl_closeComponent( const SubComponentDescriptor
& _rComponent
)
323 if ( _rComponent
.xComponentCommandProcessor
.is() )
324 return lcl_closeComponent( _rComponent
.xComponentCommandProcessor
);
326 Reference
< XController
> xController( _rComponent
.xController
);
327 OSL_ENSURE( xController
.is(), "lcl_closeComponent: invalid controller!" );
329 // suspend the controller in the document
330 if ( xController
.is() )
331 if ( !xController
->suspend( sal_True
) )
334 bool bSuccess
= false;
337 Reference
< XCloseable
> xCloseable( _rComponent
.xFrame
, UNO_QUERY_THROW
);
338 xCloseable
->close( sal_True
);
341 catch( const Exception
& )
343 DBG_UNHANDLED_EXCEPTION();
348 //..............................................................................................................
349 void lcl_notifySubComponentEvent( const SubComponentManager_Data
& _rData
, const sal_Char
* _pAsciiEventName
,
350 const SubComponentDescriptor
& _rComponent
)
354 Reference
< XDocumentEventBroadcaster
> xBroadcaster( _rData
.m_rController
.getModel(), UNO_QUERY_THROW
);
355 xBroadcaster
->notifyDocumentEvent(
356 ::rtl::OUString::createFromAscii( _pAsciiEventName
),
357 &_rData
.m_rController
,
358 makeAny( _rComponent
.xFrame
)
361 catch( const Exception
& )
363 DBG_UNHANDLED_EXCEPTION();
368 //------------------------------------------------------------------------------------------------------------------
369 void SAL_CALL
SubComponentManager::propertyChange( const PropertyChangeEvent
& i_rEvent
) throw (RuntimeException
)
371 if ( i_rEvent
.PropertyName
!= PROPERTY_NAME
)
372 // by definition, it's allowed to broadcast more than what we've registered for
375 // find the sub component whose name changed
376 for ( SubComponents::iterator comp
= m_pData
->m_aComponents
.begin();
377 comp
!= m_pData
->m_aComponents
.end();
381 if ( comp
->xDocumentDefinitionProperties
!= i_rEvent
.Source
)
384 ::rtl::OUString sNewName
;
385 OSL_VERIFY( i_rEvent
.NewValue
>>= sNewName
);
387 #if OSL_DEBUG_LEVEL > 0
388 ::rtl::OUString
sOldKnownName( comp
->sName
);
389 ::rtl::OUString sOldName
;
390 OSL_VERIFY( i_rEvent
.OldValue
>>= sOldName
);
391 OSL_ENSURE( sOldName
== sOldKnownName
, "SubComponentManager::propertyChange: inconsistency in the old names!" );
394 comp
->sName
= sNewName
;
399 //------------------------------------------------------------------------------------------------------------------
400 void SAL_CALL
SubComponentManager::disposing( const EventObject
& _rSource
) throw (RuntimeException
)
402 ::osl::ClearableMutexGuard
aGuard( m_pData
->getMutex() );
404 SubComponentDescriptor aClosedComponent
;
406 for ( SubComponents::iterator comp
= m_pData
->m_aComponents
.begin();
407 comp
!= m_pData
->m_aComponents
.end();
411 bool bRemove
= false;
413 if ( comp
->xController
== _rSource
.Source
)
415 if ( !comp
->xModel
.is() )
421 // maybe this is just one view to the sub document, and only this view is closed
422 if ( !lcl_fallbackToAnotherController( *comp
) )
428 else if ( comp
->xModel
== _rSource
.Source
)
435 aClosedComponent
= *comp
;
436 m_pData
->m_aComponents
.erase( comp
);
441 if ( aClosedComponent
.is() )
444 lcl_notifySubComponentEvent( *m_pData
, "OnSubComponentClosed", aClosedComponent
);
448 //------------------------------------------------------------------------------------------------------------------
449 Sequence
< Reference
< XComponent
> > SubComponentManager::getSubComponents() const
451 ::osl::MutexGuard
aGuard( m_pData
->getMutex() );
453 Sequence
< Reference
< XComponent
> > aComponents( m_pData
->m_aComponents
.size() );
455 m_pData
->m_aComponents
.begin(),
456 m_pData
->m_aComponents
.end(),
457 aComponents
.getArray(),
463 //------------------------------------------------------------------------------------------------------------------
464 sal_Bool
SubComponentManager::closeSubComponents()
466 SolarMutexGuard aSolarGuard
;
467 ::osl::MutexGuard
aGuard( m_pData
->getMutex() );
471 SubComponents
aWorkingCopy( m_pData
->m_aComponents
);
472 for ( SubComponents::const_iterator comp
= aWorkingCopy
.begin();
473 comp
!= aWorkingCopy
.end();
477 lcl_closeComponent( *comp
);
480 catch ( const Exception
& )
482 DBG_UNHANDLED_EXCEPTION();
488 //------------------------------------------------------------------------------------------------------------------
489 bool SubComponentManager::empty() const
491 ::osl::MutexGuard
aGuard( m_pData
->getMutex() );
492 return m_pData
->m_aComponents
.empty();
495 //------------------------------------------------------------------------------------------------------------------
496 void SubComponentManager::onSubComponentOpened( const ::rtl::OUString
& _rName
, const sal_Int32 _nComponentType
,
497 const ElementOpenMode _eOpenMode
, const Reference
< XComponent
>& _rxComponent
)
499 ::osl::ClearableMutexGuard
aGuard( m_pData
->getMutex() );
501 #if OSL_DEBUG_LEVEL > 0
502 if ( !_rName
.isEmpty() )
504 // check there does not already exist such a component
505 SubComponents::const_iterator existentPos
= ::std::find_if(
506 m_pData
->m_aComponents
.begin(),
507 m_pData
->m_aComponents
.end(),
508 SubComponentMatch( _rName
, _nComponentType
, _eOpenMode
)
510 OSL_ENSURE( existentPos
== m_pData
->m_aComponents
.end(), "already existent!" );
513 SubComponentDescriptor
aElement( _rName
, _nComponentType
, _eOpenMode
, _rxComponent
);
514 ENSURE_OR_THROW( aElement
.xModel
.is() || aElement
.xController
.is(), "illegal component" );
516 m_pData
->m_aComponents
.push_back( aElement
);
519 if ( aElement
.xController
.is() )
520 aElement
.xController
->addEventListener( this );
521 if ( aElement
.xModel
.is() )
522 aElement
.xModel
->addEventListener( this );
523 if ( aElement
.xDocumentDefinitionProperties
.is() )
524 aElement
.xDocumentDefinitionProperties
->addPropertyChangeListener( PROPERTY_NAME
, this );
526 // notify this to interested parties
528 lcl_notifySubComponentEvent( *m_pData
, "OnSubComponentOpened", aElement
);
531 //------------------------------------------------------------------------------------------------------------------
532 bool SubComponentManager::activateSubFrame( const ::rtl::OUString
& _rName
, const sal_Int32 _nComponentType
,
533 const ElementOpenMode _eOpenMode
, Reference
< XComponent
>& o_rComponent
) const
535 ::osl::MutexGuard
aGuard( m_pData
->getMutex() );
537 SubComponents::const_iterator pos
= ::std::find_if(
538 m_pData
->m_aComponents
.begin(),
539 m_pData
->m_aComponents
.end(),
540 SubComponentMatch( _rName
, _nComponentType
, _eOpenMode
)
542 if ( pos
== m_pData
->m_aComponents
.end() )
543 // no component with this name/type/open mode
546 const Reference
< XFrame
> xFrame( pos
->xFrame
, UNO_SET_THROW
);
547 const Reference
< XTopWindow
> xTopWindow( xFrame
->getContainerWindow(), UNO_QUERY_THROW
);
548 xTopWindow
->toFront();
550 if ( pos
->xModel
.is() )
551 o_rComponent
= pos
->xModel
.get();
552 else if ( pos
->xController
.is() )
553 o_rComponent
= pos
->xController
.get();
555 o_rComponent
= pos
->xFrame
.get();
560 //------------------------------------------------------------------------------------------------------------------
561 bool SubComponentManager::closeSubFrames( const ::rtl::OUString
& i_rName
, const sal_Int32 _nComponentType
)
563 ::osl::MutexGuard
aGuard( m_pData
->getMutex() );
564 ENSURE_OR_RETURN_FALSE( !i_rName
.isEmpty(), "SubComponentManager::closeSubFrames: illegal name!" );
566 SubComponents
aWorkingCopy( m_pData
->m_aComponents
);
567 for ( SubComponents::const_iterator comp
= aWorkingCopy
.begin();
568 comp
!= aWorkingCopy
.end();
572 if ( ( comp
->sName
!= i_rName
) || ( comp
->nComponentType
!= _nComponentType
) )
575 if ( !lcl_closeComponent( *comp
) )
582 //------------------------------------------------------------------------------------------------------------------
583 bool SubComponentManager::lookupSubComponent( const Reference
< XComponent
>& i_rComponent
,
584 ::rtl::OUString
& o_rName
, sal_Int32
& o_rComponentType
)
586 for ( SubComponents::const_iterator comp
= m_pData
->m_aComponents
.begin();
587 comp
!= m_pData
->m_aComponents
.end();
591 if ( ( comp
->xModel
.is()
592 && ( comp
->xModel
== i_rComponent
)
594 || ( comp
->xController
.is()
595 && ( comp
->xController
== i_rComponent
)
597 || ( comp
->xFrame
.is()
598 && ( comp
->xFrame
== i_rComponent
)
602 o_rName
= comp
->sName
;
603 o_rComponentType
= comp
->nComponentType
;
610 //......................................................................................................................
612 //......................................................................................................................
614 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */