1 /*************************************************************************
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * Copyright 2000, 2010 Oracle and/or its affiliates.
5  *
6  * OpenOffice.org - a multi-platform office productivity suite
7  *
8  * This file is part of OpenOffice.org.
9  *
10  * OpenOffice.org is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License version 3
12  * only, as published by the Free Software Foundation.
13  *
14  * OpenOffice.org is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License version 3 for more details
18  * (a copy is included in the LICENSE file that accompanied this code).
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * version 3 along with OpenOffice.org.  If not, see
22  * <http://www.openoffice.org/license.html>
23  * for a copy of the LGPLv3 License.
24  *
25 ************************************************************************/
26 
27 #include "subcomponentmanager.hxx"
28 #include "AppController.hxx"
29 #include "dbustrings.hrc"
30 
31 /** === begin UNO includes === **/
32 #include <com/sun/star/frame/XFrame.hpp>
33 #include <com/sun/star/frame/XModel.hpp>
34 #include <com/sun/star/frame/XModel2.hpp>
35 #include <com/sun/star/util/XCloseable.hpp>
36 #include <com/sun/star/awt/XTopWindow.hpp>
37 #include <com/sun/star/embed/XComponentSupplier.hpp>
38 #include <com/sun/star/ucb/XCommandProcessor.hpp>
39 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
40 #include <com/sun/star/beans/XPropertySet.hpp>
41 /** === end UNO includes === **/
42 
43 #include <tools/diagnose_ex.h>
44 #include <vcl/svapp.hxx>
45 #include <vos/mutex.hxx>
46 
47 #include <hash_map>
48 #include <algorithm>
49 #include <functional>
50 
51 //......................................................................................................................
52 namespace dbaui
53 {
54 //......................................................................................................................
55 
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 === **/
84 
85     //==================================================================================================================
86     //= helper structs
87     //==================================================================================================================
88     namespace
89     {
90         //..............................................................................................................
91         struct SubComponentDescriptor
92         {
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;
109 
110             SubComponentDescriptor()
111                 :sName()
112                 ,nComponentType( -1 )
113                 ,eOpenMode( E_OPEN_NORMAL )
114                 ,xFrame()
115                 ,xController()
116                 ,xModel()
117             {
118             }
119 
120             SubComponentDescriptor( const ::rtl::OUString& i_rName, const sal_Int32 i_nComponentType,
121                     const ElementOpenMode i_eOpenMode, const Reference< XComponent >& i_rComponent )
122                 :sName( i_rName )
123                 ,nComponentType( i_nComponentType )
124                 ,eOpenMode( i_eOpenMode )
125             {
126                 if ( !impl_constructFrom( i_rComponent ) )
127                 {
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 );
136                 }
137             }
138 
139             inline bool is() const { return xFrame.is(); }
140 
141         private:
142             bool impl_constructFrom( const Reference< XComponent >& _rxComponent )
143             {
144                 // is it a model?
145                 xModel.set( _rxComponent, UNO_QUERY );
146                 if ( xModel.is() )
147                 {
148                     xController.set( xModel->getCurrentController() );
149                     if ( xController.is() )
150                         xFrame.set( xController->getFrame(), UNO_SET_THROW );
151                 }
152                 else
153                 {
154                     // is it a controller?
155                     xController.set( _rxComponent, UNO_QUERY );
156                     if ( xController.is() )
157                     {
158                         xFrame.set( xController->getFrame(), UNO_SET_THROW );
159                     }
160                     else
161                     {
162                         // is it a frame?
163                         xFrame.set( _rxComponent, UNO_QUERY );
164                         if ( !xFrame.is() )
165                             return false;
166 
167                         // ensure we have a controller
168                         xController.set( xFrame->getController(), UNO_SET_THROW );
169                     }
170 
171                     // check wether there is a model (not required)
172                     xModel.set( xController->getModel() );
173                 }
174 
175                 return true;
176             }
177         };
178 
179         //..............................................................................................................
180         struct SelectSubComponent : public ::std::unary_function< SubComponentDescriptor, Reference< XComponent > >
181         {
182             Reference< XComponent > operator()( const SubComponentDescriptor _desc ) const
183             {
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();
188             }
189         };
190 
191         //..............................................................................................................
192         typedef ::std::vector< SubComponentDescriptor > SubComponents;
193 
194         //..............................................................................................................
195         struct SubComponentMatch : public ::std::unary_function< SubComponentDescriptor, bool >
196         {
197         public:
198             SubComponentMatch( const ::rtl::OUString& i_rName, const sal_Int32 i_nComponentType,
199                     const ElementOpenMode i_eOpenMode )
200                 :m_sName( i_rName )
201                 ,m_nComponentType( i_nComponentType )
202                 ,m_eOpenMode( i_eOpenMode )
203             {
204             }
205 
206             bool operator()( const SubComponentDescriptor& i_rCompareWith ) const
207             {
208                 return  (   m_sName             ==  i_rCompareWith.sName          )
209                     &&  (   m_nComponentType    ==  i_rCompareWith.nComponentType )
210                     &&  (   m_eOpenMode         ==  i_rCompareWith.eOpenMode      );
211             }
212         private:
213             const ::rtl::OUString   m_sName;
214             const sal_Int32         m_nComponentType;
215             const ElementOpenMode   m_eOpenMode;
216         };
217     }
218 
219     //==================================================================================================================
220     //= SubComponentManager_Data
221     //==================================================================================================================
222     struct SubComponentManager_Data
223     {
224         SubComponentManager_Data( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex )
225             :m_rController( _rController )
226             ,m_aMutex( _rMutex )
227         {
228         }
229 
230         OApplicationController&             m_rController;
231         mutable ::comphelper::SharedMutex   m_aMutex;
232         SubComponents                       m_aComponents;
233 
234         ::osl::Mutex&   getMutex() const { return m_aMutex; }
235     };
236 
237     //==================================================================================================================
238 	//= SubComponentManager
239     //==================================================================================================================
240 	//------------------------------------------------------------------------------------------------------------------
241     SubComponentManager::SubComponentManager( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex )
242         :m_pData( new SubComponentManager_Data( _rController, _rMutex ) )
243     {
244     }
245 
246 	//------------------------------------------------------------------------------------------------------------------
247     SubComponentManager::~SubComponentManager()
248     {
249     }
250 
251 	//------------------------------------------------------------------------------------------------------------------
252     void SubComponentManager::disposing()
253     {
254         ::osl::MutexGuard aGuard( m_pData->getMutex() );
255         m_pData->m_aComponents.clear();
256     }
257 
258 	//------------------------------------------------------------------------------------------------------------------
259     namespace
260     {
261 	    //..............................................................................................................
262         bool lcl_fallbackToAnotherController( SubComponentDescriptor& _rCompDesc )
263         {
264             Reference< XController > xFallback;
265             OSL_PRECOND( _rCompDesc.xModel.is(), "lcl_fallbackToAnotherController: illegal call!" );
266             if ( !_rCompDesc.xModel.is() )
267                 return false;
268 
269             xFallback.set( _rCompDesc.xModel->getCurrentController() );
270             if ( xFallback == _rCompDesc.xController )
271                 // don't accept the very same controller as fallback
272                 xFallback.clear();
273 
274             if ( !xFallback.is() )
275             {
276                 // perhaps XModel2 can be of help here
277                 Reference< XModel2 > xModel2( _rCompDesc.xModel, UNO_QUERY );
278                 Reference< XEnumeration > xControllerEnum;
279                 if ( xModel2.is() )
280                     xControllerEnum = xModel2->getControllers();
281                 while ( xControllerEnum.is() && xControllerEnum->hasMoreElements() )
282                 {
283                     xFallback.set( xControllerEnum->nextElement(), UNO_QUERY );
284                     if ( xFallback == _rCompDesc.xController )
285                         xFallback.clear();
286                 }
287             }
288 
289             if ( xFallback.is() )
290             {
291                 _rCompDesc.xController = xFallback;
292                 _rCompDesc.xFrame.set( xFallback->getFrame(), UNO_SET_THROW );
293                 return true;
294             }
295 
296             return false;
297         }
298 
299 	    //..............................................................................................................
300         bool lcl_closeComponent( const Reference< XCommandProcessor >& _rxCommandProcessor )
301         {
302             bool bSuccess = false;
303             try
304             {
305                 Reference< XCommandProcessor > xCommandProcessor( _rxCommandProcessor, UNO_SET_THROW );
306                 sal_Int32 nCommandIdentifier = xCommandProcessor->createCommandIdentifier();
307 
308                 Command aCommand;
309                 aCommand.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "close" ) );
310                 xCommandProcessor->execute( aCommand, nCommandIdentifier, NULL );
311                 bSuccess = true;
312             }
313             catch( const Exception& )
314             {
315             	DBG_UNHANDLED_EXCEPTION();
316             }
317             return bSuccess;
318         }
319 
320 	    //..............................................................................................................
321         bool lcl_closeComponent( const SubComponentDescriptor& _rComponent )
322         {
323             if ( _rComponent.xComponentCommandProcessor.is() )
324                 return lcl_closeComponent( _rComponent.xComponentCommandProcessor );
325 
326             Reference< XController > xController( _rComponent.xController );
327             OSL_ENSURE( xController.is(), "lcl_closeComponent: invalid controller!" );
328 
329             // suspend the controller in the document
330             if ( xController.is() )
331                 if ( !xController->suspend( sal_True ) )
332                     return false;
333 
334             bool bSuccess = false;
335             try
336             {
337                 Reference< XCloseable > xCloseable( _rComponent.xFrame, UNO_QUERY_THROW );
338                 xCloseable->close( sal_True );
339                 bSuccess = true;
340             }
341             catch( const Exception& )
342             {
343                 DBG_UNHANDLED_EXCEPTION();
344             }
345             return bSuccess;
346         }
347 
348 	    //..............................................................................................................
349         void lcl_notifySubComponentEvent( const SubComponentManager_Data& _rData, const sal_Char* _pAsciiEventName,
350                 const SubComponentDescriptor& _rComponent )
351         {
352             try
353             {
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 )
359                 );
360             }
361             catch( const Exception& )
362             {
363         	    DBG_UNHANDLED_EXCEPTION();
364             }
365         }
366     }
367 
368 	//------------------------------------------------------------------------------------------------------------------
369     void SAL_CALL SubComponentManager::propertyChange( const PropertyChangeEvent& i_rEvent ) throw (RuntimeException)
370     {
371         if ( i_rEvent.PropertyName != PROPERTY_NAME )
372             // by definition, it's allowed to broadcast more than what we've registered for
373             return;
374 
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();
378                 ++comp
379             )
380         {
381             if ( comp->xDocumentDefinitionProperties != i_rEvent.Source )
382                 continue;
383 
384             ::rtl::OUString sNewName;
385             OSL_VERIFY( i_rEvent.NewValue >>= sNewName );
386 
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!" );
392         #endif
393 
394             comp->sName = sNewName;
395             break;
396         }
397     }
398 
399 	//------------------------------------------------------------------------------------------------------------------
400     void SAL_CALL SubComponentManager::disposing( const EventObject& _rSource ) throw (RuntimeException)
401     {
402         ::osl::ClearableMutexGuard aGuard( m_pData->getMutex() );
403 
404         SubComponentDescriptor aClosedComponent;
405 
406         for (   SubComponents::iterator comp = m_pData->m_aComponents.begin();
407                 comp != m_pData->m_aComponents.end();
408                 ++comp
409             )
410         {
411             bool bRemove = false;
412 
413             if ( comp->xController == _rSource.Source )
414             {
415                 if ( !comp->xModel.is() )
416                 {
417                     bRemove = true;
418                 }
419                 else
420                 {
421                     // maybe this is just one view to the sub document, and only this view is closed
422                     if ( !lcl_fallbackToAnotherController( *comp ) )
423                     {
424                         bRemove = true;
425                     }
426                 }
427             }
428             else if ( comp->xModel == _rSource.Source )
429             {
430                 bRemove = true;
431             }
432 
433             if ( bRemove )
434             {
435                 aClosedComponent = *comp;
436                 m_pData->m_aComponents.erase( comp );
437                 break;
438             }
439         }
440 
441         if ( aClosedComponent.is() )
442         {
443             aGuard.clear();
444             lcl_notifySubComponentEvent( *m_pData, "OnSubComponentClosed", aClosedComponent );
445         }
446     }
447 
448 	//------------------------------------------------------------------------------------------------------------------
449     Sequence< Reference< XComponent> > SubComponentManager::getSubComponents() const
450     {
451         ::osl::MutexGuard aGuard( m_pData->getMutex() );
452 
453         Sequence< Reference< XComponent > > aComponents( m_pData->m_aComponents.size() );
454         ::std::transform(
455             m_pData->m_aComponents.begin(),
456             m_pData->m_aComponents.end(),
457             aComponents.getArray(),
458             SelectSubComponent()
459         );
460         return aComponents;
461     }
462 
463 	//------------------------------------------------------------------------------------------------------------------
464     sal_Bool SubComponentManager::closeSubComponents()
465     {
466 	    ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
467 	    ::osl::MutexGuard aGuard( m_pData->getMutex() );
468 
469 	    try
470 	    {
471             SubComponents aWorkingCopy( m_pData->m_aComponents );
472 		    for (   SubComponents::const_iterator comp = aWorkingCopy.begin();
473                     comp != aWorkingCopy.end();
474                     ++comp
475                 )
476             {
477                 lcl_closeComponent( *comp );
478             }
479 	    }
480 	    catch ( const Exception& )
481 	    {
482             DBG_UNHANDLED_EXCEPTION();
483 	    }
484 
485 	    return empty();
486     }
487 
488 	//------------------------------------------------------------------------------------------------------------------
489     bool SubComponentManager::empty() const
490     {
491 	    ::osl::MutexGuard aGuard( m_pData->getMutex() );
492         return m_pData->m_aComponents.empty();
493     }
494 
495 	//------------------------------------------------------------------------------------------------------------------
496     void SubComponentManager::onSubComponentOpened( const ::rtl::OUString&  _rName, const sal_Int32 _nComponentType,
497         const ElementOpenMode _eOpenMode, const Reference< XComponent >& _rxComponent )
498     {
499 	    ::osl::ClearableMutexGuard aGuard( m_pData->getMutex() );
500 
501 #if OSL_DEBUG_LEVEL > 0
502         if ( _rName.getLength() )
503         {
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 )
509             );
510             OSL_ENSURE( existentPos == m_pData->m_aComponents.end(), "already existent!" );
511         }
512 #endif
513         SubComponentDescriptor aElement( _rName, _nComponentType, _eOpenMode, _rxComponent );
514         ENSURE_OR_THROW( aElement.xModel.is() || aElement.xController.is(), "illegal component" );
515 
516         m_pData->m_aComponents.push_back( aElement );
517 
518         // add as listener
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 );
525 
526         // notify this to interested parties
527         aGuard.clear();
528         lcl_notifySubComponentEvent( *m_pData, "OnSubComponentOpened", aElement );
529     }
530 
531 	//------------------------------------------------------------------------------------------------------------------
532     bool SubComponentManager::activateSubFrame( const ::rtl::OUString& _rName, const sal_Int32 _nComponentType,
533         const ElementOpenMode _eOpenMode, Reference< XComponent >& o_rComponent ) const
534     {
535 	    ::osl::MutexGuard aGuard( m_pData->getMutex() );
536 
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 )
541         );
542         if ( pos == m_pData->m_aComponents.end() )
543             // no component with this name/type/open mode
544             return false;
545 
546         const Reference< XFrame > xFrame( pos->xFrame, UNO_SET_THROW );
547         const Reference< XTopWindow > xTopWindow( xFrame->getContainerWindow(), UNO_QUERY_THROW );
548         xTopWindow->toFront();
549 
550         if ( pos->xModel.is() )
551             o_rComponent = pos->xModel.get();
552         else if ( pos->xController.is() )
553             o_rComponent = pos->xController.get();
554         else
555             o_rComponent = pos->xFrame.get();
556 
557         return true;
558     }
559 
560 	//------------------------------------------------------------------------------------------------------------------
561     bool SubComponentManager::closeSubFrames( const ::rtl::OUString& i_rName, const sal_Int32 _nComponentType )
562     {
563 	    ::osl::MutexGuard aGuard( m_pData->getMutex() );
564         ENSURE_OR_RETURN_FALSE( i_rName.getLength(), "SubComponentManager::closeSubFrames: illegal name!" );
565 
566         SubComponents aWorkingCopy( m_pData->m_aComponents );
567         for (   SubComponents::const_iterator comp = aWorkingCopy.begin();
568                 comp != aWorkingCopy.end();
569                 ++comp
570             )
571         {
572             if ( ( comp->sName != i_rName ) || ( comp->nComponentType != _nComponentType ) )
573                 continue;
574 
575             if ( !lcl_closeComponent( *comp ) )
576                 return false;
577         }
578 
579         return true;
580     }
581 
582 	//------------------------------------------------------------------------------------------------------------------
583     bool SubComponentManager::lookupSubComponent( const Reference< XComponent >& i_rComponent,
584             ::rtl::OUString& o_rName, sal_Int32& o_rComponentType )
585     {
586         for (   SubComponents::const_iterator comp = m_pData->m_aComponents.begin();
587                 comp != m_pData->m_aComponents.end();
588                 ++comp
589             )
590         {
591             if  (   (   comp->xModel.is()
592                     &&  ( comp->xModel == i_rComponent )
593                     )
594                 ||  (   comp->xController.is()
595                     &&  ( comp->xController == i_rComponent )
596                     )
597                 ||  (   comp->xFrame.is()
598                     &&  ( comp->xFrame == i_rComponent )
599                     )
600                 )
601             {
602                 o_rName = comp->sName;
603                 o_rComponentType = comp->nComponentType;
604                 return true;
605             }
606         }
607         return false;
608     }
609 
610 //......................................................................................................................
611 } // namespace dbaui
612 //......................................................................................................................
613