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 #include "subcomponentmanager.hxx"
25 #include "AppController.hxx"
26 #include "dbustrings.hrc"
27 
28 /** === begin UNO includes === **/
29 #include <com/sun/star/frame/XFrame.hpp>
30 #include <com/sun/star/frame/XModel.hpp>
31 #include <com/sun/star/frame/XModel2.hpp>
32 #include <com/sun/star/util/XCloseable.hpp>
33 #include <com/sun/star/awt/XTopWindow.hpp>
34 #include <com/sun/star/embed/XComponentSupplier.hpp>
35 #include <com/sun/star/ucb/XCommandProcessor.hpp>
36 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 /** === end UNO includes === **/
39 
40 #include <tools/diagnose_ex.h>
41 #include <vcl/svapp.hxx>
42 #include <vos/mutex.hxx>
43 
44 #include <hash_map>
45 #include <algorithm>
46 #include <functional>
47 
48 //......................................................................................................................
49 namespace dbaui
50 {
51 //......................................................................................................................
52 
53 	/** === begin UNO using === **/
54 	using ::com::sun::star::uno::Reference;
55 	using ::com::sun::star::uno::XInterface;
56 	using ::com::sun::star::uno::UNO_QUERY;
57 	using ::com::sun::star::uno::UNO_QUERY_THROW;
58 	using ::com::sun::star::uno::UNO_SET_THROW;
59 	using ::com::sun::star::uno::Exception;
60 	using ::com::sun::star::uno::RuntimeException;
61 	using ::com::sun::star::uno::Any;
62 	using ::com::sun::star::uno::makeAny;
63 	using ::com::sun::star::uno::Sequence;
64 	using ::com::sun::star::uno::Type;
65     using ::com::sun::star::frame::XFrame;
66     using ::com::sun::star::frame::XController;
67     using ::com::sun::star::frame::XModel;
68     using ::com::sun::star::lang::EventObject;
69     using ::com::sun::star::lang::XComponent;
70     using ::com::sun::star::frame::XModel2;
71     using ::com::sun::star::container::XEnumeration;
72     using ::com::sun::star::util::XCloseable;
73     using ::com::sun::star::awt::XTopWindow;
74     using ::com::sun::star::embed::XComponentSupplier;
75     using ::com::sun::star::ucb::XCommandProcessor;
76     using ::com::sun::star::ucb::Command;
77     using ::com::sun::star::document::XDocumentEventBroadcaster;
78     using ::com::sun::star::beans::XPropertySet;
79     using ::com::sun::star::beans::PropertyChangeEvent;
80 	/** === end UNO using === **/
81 
82     //==================================================================================================================
83     //= helper structs
84     //==================================================================================================================
85     namespace
86     {
87         //..............................................................................................................
88         struct SubComponentDescriptor
89         {
90             /// the name of the sub component, empty if it is yet unsaved
91             ::rtl::OUString sName;
92             /// type of the component - an ElementType value, except for relation design
93             sal_Int32       nComponentType;
94             /// the mode in which the sub component has been opened
95             ElementOpenMode eOpenMode;
96             /// the frame which the component resides in. Must not be <NULL/>
97             Reference< XFrame >             xFrame;
98             /// the controller of the sub component. Must not be <NULL/>
99             Reference< XController >        xController;
100             /// the model of the sub component. Might be <NULL/>
101             Reference< XModel >             xModel;
102             /// the document definition which holds the component, if any; as CommandProcessor
103             Reference< XCommandProcessor >  xComponentCommandProcessor;
104             /// the document definition which holds the component, if any; as PropertySet
105             Reference< XPropertySet >       xDocumentDefinitionProperties;
106 
107             SubComponentDescriptor()
108                 :sName()
109                 ,nComponentType( -1 )
110                 ,eOpenMode( E_OPEN_NORMAL )
111                 ,xFrame()
112                 ,xController()
113                 ,xModel()
114             {
115             }
116 
117             SubComponentDescriptor( const ::rtl::OUString& i_rName, const sal_Int32 i_nComponentType,
118                     const ElementOpenMode i_eOpenMode, const Reference< XComponent >& i_rComponent )
119                 :sName( i_rName )
120                 ,nComponentType( i_nComponentType )
121                 ,eOpenMode( i_eOpenMode )
122             {
123                 if ( !impl_constructFrom( i_rComponent ) )
124                 {
125                     // i_rComponent is neither a model, nor a controller, nor a frame
126                     // => it must be a css.sdb.DocumentDefinition
127                     Reference< XComponentSupplier > xCompSupp( i_rComponent, UNO_QUERY_THROW );
128                     Reference< XComponent > xComponent( xCompSupp->getComponent(), UNO_QUERY_THROW );
129                     if ( !impl_constructFrom( xComponent ) )
130                         throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Illegal component type." ) ), NULL );
131                     xComponentCommandProcessor.set( i_rComponent, UNO_QUERY_THROW );
132                     xDocumentDefinitionProperties.set( i_rComponent, UNO_QUERY_THROW );
133                 }
134             }
135 
136             inline bool is() const { return xFrame.is(); }
137 
138         private:
139             bool impl_constructFrom( const Reference< XComponent >& _rxComponent )
140             {
141                 // is it a model?
142                 xModel.set( _rxComponent, UNO_QUERY );
143                 if ( xModel.is() )
144                 {
145                     xController.set( xModel->getCurrentController() );
146                     if ( xController.is() )
147                         xFrame.set( xController->getFrame(), UNO_SET_THROW );
148                 }
149                 else
150                 {
151                     // is it a controller?
152                     xController.set( _rxComponent, UNO_QUERY );
153                     if ( xController.is() )
154                     {
155                         xFrame.set( xController->getFrame(), UNO_SET_THROW );
156                     }
157                     else
158                     {
159                         // is it a frame?
160                         xFrame.set( _rxComponent, UNO_QUERY );
161                         if ( !xFrame.is() )
162                             return false;
163 
164                         // ensure we have a controller
165                         xController.set( xFrame->getController(), UNO_SET_THROW );
166                     }
167 
168                     // check wether there is a model (not required)
169                     xModel.set( xController->getModel() );
170                 }
171 
172                 return true;
173             }
174         };
175 
176         //..............................................................................................................
177         struct SelectSubComponent : public ::std::unary_function< SubComponentDescriptor, Reference< XComponent > >
178         {
179             Reference< XComponent > operator()( const SubComponentDescriptor _desc ) const
180             {
181                 if ( _desc.xModel.is() )
182                     return _desc.xModel.get();
183                 OSL_ENSURE( _desc.xController.is(), "SelectSubComponent::operator(): illegal component!" );
184                 return _desc.xController.get();
185             }
186         };
187 
188         //..............................................................................................................
189         typedef ::std::vector< SubComponentDescriptor > SubComponents;
190 
191         //..............................................................................................................
192         struct SubComponentMatch : public ::std::unary_function< SubComponentDescriptor, bool >
193         {
194         public:
195             SubComponentMatch( const ::rtl::OUString& i_rName, const sal_Int32 i_nComponentType,
196                     const ElementOpenMode i_eOpenMode )
197                 :m_sName( i_rName )
198                 ,m_nComponentType( i_nComponentType )
199                 ,m_eOpenMode( i_eOpenMode )
200             {
201             }
202 
203             bool operator()( const SubComponentDescriptor& i_rCompareWith ) const
204             {
205                 return  (   m_sName             ==  i_rCompareWith.sName          )
206                     &&  (   m_nComponentType    ==  i_rCompareWith.nComponentType )
207                     &&  (   m_eOpenMode         ==  i_rCompareWith.eOpenMode      );
208             }
209         private:
210             const ::rtl::OUString   m_sName;
211             const sal_Int32         m_nComponentType;
212             const ElementOpenMode   m_eOpenMode;
213         };
214     }
215 
216     //==================================================================================================================
217     //= SubComponentManager_Data
218     //==================================================================================================================
219     struct SubComponentManager_Data
220     {
221         SubComponentManager_Data( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex )
222             :m_rController( _rController )
223             ,m_aMutex( _rMutex )
224         {
225         }
226 
227         OApplicationController&             m_rController;
228         mutable ::comphelper::SharedMutex   m_aMutex;
229         SubComponents                       m_aComponents;
230 
231         ::osl::Mutex&   getMutex() const { return m_aMutex; }
232     };
233 
234     //==================================================================================================================
235 	//= SubComponentManager
236     //==================================================================================================================
237 	//------------------------------------------------------------------------------------------------------------------
238     SubComponentManager::SubComponentManager( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex )
239         :m_pData( new SubComponentManager_Data( _rController, _rMutex ) )
240     {
241     }
242 
243 	//------------------------------------------------------------------------------------------------------------------
244     SubComponentManager::~SubComponentManager()
245     {
246     }
247 
248 	//------------------------------------------------------------------------------------------------------------------
249     void SubComponentManager::disposing()
250     {
251         ::osl::MutexGuard aGuard( m_pData->getMutex() );
252         m_pData->m_aComponents.clear();
253     }
254 
255 	//------------------------------------------------------------------------------------------------------------------
256     namespace
257     {
258 	    //..............................................................................................................
259         bool lcl_fallbackToAnotherController( SubComponentDescriptor& _rCompDesc )
260         {
261             Reference< XController > xFallback;
262             OSL_PRECOND( _rCompDesc.xModel.is(), "lcl_fallbackToAnotherController: illegal call!" );
263             if ( !_rCompDesc.xModel.is() )
264                 return false;
265 
266             xFallback.set( _rCompDesc.xModel->getCurrentController() );
267             if ( xFallback == _rCompDesc.xController )
268                 // don't accept the very same controller as fallback
269                 xFallback.clear();
270 
271             if ( !xFallback.is() )
272             {
273                 // perhaps XModel2 can be of help here
274                 Reference< XModel2 > xModel2( _rCompDesc.xModel, UNO_QUERY );
275                 Reference< XEnumeration > xControllerEnum;
276                 if ( xModel2.is() )
277                     xControllerEnum = xModel2->getControllers();
278                 while ( xControllerEnum.is() && xControllerEnum->hasMoreElements() )
279                 {
280                     xFallback.set( xControllerEnum->nextElement(), UNO_QUERY );
281                     if ( xFallback == _rCompDesc.xController )
282                         xFallback.clear();
283                 }
284             }
285 
286             if ( xFallback.is() )
287             {
288                 _rCompDesc.xController = xFallback;
289                 _rCompDesc.xFrame.set( xFallback->getFrame(), UNO_SET_THROW );
290                 return true;
291             }
292 
293             return false;
294         }
295 
296 	    //..............................................................................................................
297         bool lcl_closeComponent( const Reference< XCommandProcessor >& _rxCommandProcessor )
298         {
299             bool bSuccess = false;
300             try
301             {
302                 Reference< XCommandProcessor > xCommandProcessor( _rxCommandProcessor, UNO_SET_THROW );
303                 sal_Int32 nCommandIdentifier = xCommandProcessor->createCommandIdentifier();
304 
305                 Command aCommand;
306                 aCommand.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "close" ) );
307                 xCommandProcessor->execute( aCommand, nCommandIdentifier, NULL );
308                 bSuccess = true;
309             }
310             catch( const Exception& )
311             {
312             	DBG_UNHANDLED_EXCEPTION();
313             }
314             return bSuccess;
315         }
316 
317 	    //..............................................................................................................
318         bool lcl_closeComponent( const SubComponentDescriptor& _rComponent )
319         {
320             if ( _rComponent.xComponentCommandProcessor.is() )
321                 return lcl_closeComponent( _rComponent.xComponentCommandProcessor );
322 
323             Reference< XController > xController( _rComponent.xController );
324             OSL_ENSURE( xController.is(), "lcl_closeComponent: invalid controller!" );
325 
326             // suspend the controller in the document
327             if ( xController.is() )
328                 if ( !xController->suspend( sal_True ) )
329                     return false;
330 
331             bool bSuccess = false;
332             try
333             {
334                 Reference< XCloseable > xCloseable( _rComponent.xFrame, UNO_QUERY_THROW );
335                 xCloseable->close( sal_True );
336                 bSuccess = true;
337             }
338             catch( const Exception& )
339             {
340                 DBG_UNHANDLED_EXCEPTION();
341             }
342             return bSuccess;
343         }
344 
345 	    //..............................................................................................................
346         void lcl_notifySubComponentEvent( const SubComponentManager_Data& _rData, const sal_Char* _pAsciiEventName,
347                 const SubComponentDescriptor& _rComponent )
348         {
349             try
350             {
351                 Reference< XDocumentEventBroadcaster > xBroadcaster( _rData.m_rController.getModel(), UNO_QUERY_THROW );
352                 xBroadcaster->notifyDocumentEvent(
353                     ::rtl::OUString::createFromAscii( _pAsciiEventName ),
354                     &_rData.m_rController,
355                     makeAny( _rComponent.xFrame )
356                 );
357             }
358             catch( const Exception& )
359             {
360         	    DBG_UNHANDLED_EXCEPTION();
361             }
362         }
363     }
364 
365 	//------------------------------------------------------------------------------------------------------------------
366     void SAL_CALL SubComponentManager::propertyChange( const PropertyChangeEvent& i_rEvent ) throw (RuntimeException)
367     {
368         if ( i_rEvent.PropertyName != PROPERTY_NAME )
369             // by definition, it's allowed to broadcast more than what we've registered for
370             return;
371 
372         // find the sub component whose name changed
373         for (   SubComponents::iterator comp = m_pData->m_aComponents.begin();
374                 comp != m_pData->m_aComponents.end();
375                 ++comp
376             )
377         {
378             if ( comp->xDocumentDefinitionProperties != i_rEvent.Source )
379                 continue;
380 
381             ::rtl::OUString sNewName;
382             OSL_VERIFY( i_rEvent.NewValue >>= sNewName );
383 
384         #if OSL_DEBUG_LEVEL > 0
385             ::rtl::OUString sOldKnownName( comp->sName );
386             ::rtl::OUString sOldName;
387             OSL_VERIFY( i_rEvent.OldValue >>= sOldName );
388             OSL_ENSURE( sOldName == sOldKnownName, "SubComponentManager::propertyChange: inconsistency in the old names!" );
389         #endif
390 
391             comp->sName = sNewName;
392             break;
393         }
394     }
395 
396 	//------------------------------------------------------------------------------------------------------------------
397     void SAL_CALL SubComponentManager::disposing( const EventObject& _rSource ) throw (RuntimeException)
398     {
399         ::osl::ClearableMutexGuard aGuard( m_pData->getMutex() );
400 
401         SubComponentDescriptor aClosedComponent;
402 
403         for (   SubComponents::iterator comp = m_pData->m_aComponents.begin();
404                 comp != m_pData->m_aComponents.end();
405                 ++comp
406             )
407         {
408             bool bRemove = false;
409 
410             if ( comp->xController == _rSource.Source )
411             {
412                 if ( !comp->xModel.is() )
413                 {
414                     bRemove = true;
415                 }
416                 else
417                 {
418                     // maybe this is just one view to the sub document, and only this view is closed
419                     if ( !lcl_fallbackToAnotherController( *comp ) )
420                     {
421                         bRemove = true;
422                     }
423                 }
424             }
425             else if ( comp->xModel == _rSource.Source )
426             {
427                 bRemove = true;
428             }
429 
430             if ( bRemove )
431             {
432                 aClosedComponent = *comp;
433                 m_pData->m_aComponents.erase( comp );
434                 break;
435             }
436         }
437 
438         if ( aClosedComponent.is() )
439         {
440             aGuard.clear();
441             lcl_notifySubComponentEvent( *m_pData, "OnSubComponentClosed", aClosedComponent );
442         }
443     }
444 
445 	//------------------------------------------------------------------------------------------------------------------
446     Sequence< Reference< XComponent> > SubComponentManager::getSubComponents() const
447     {
448         ::osl::MutexGuard aGuard( m_pData->getMutex() );
449 
450         Sequence< Reference< XComponent > > aComponents( m_pData->m_aComponents.size() );
451         ::std::transform(
452             m_pData->m_aComponents.begin(),
453             m_pData->m_aComponents.end(),
454             aComponents.getArray(),
455             SelectSubComponent()
456         );
457         return aComponents;
458     }
459 
460 	//------------------------------------------------------------------------------------------------------------------
461     sal_Bool SubComponentManager::closeSubComponents()
462     {
463 	    ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
464 	    ::osl::MutexGuard aGuard( m_pData->getMutex() );
465 
466 	    try
467 	    {
468             SubComponents aWorkingCopy( m_pData->m_aComponents );
469 		    for (   SubComponents::const_iterator comp = aWorkingCopy.begin();
470                     comp != aWorkingCopy.end();
471                     ++comp
472                 )
473             {
474                 lcl_closeComponent( *comp );
475             }
476 	    }
477 	    catch ( const Exception& )
478 	    {
479             DBG_UNHANDLED_EXCEPTION();
480 	    }
481 
482 	    return empty();
483     }
484 
485 	//------------------------------------------------------------------------------------------------------------------
486     bool SubComponentManager::empty() const
487     {
488 	    ::osl::MutexGuard aGuard( m_pData->getMutex() );
489         return m_pData->m_aComponents.empty();
490     }
491 
492 	//------------------------------------------------------------------------------------------------------------------
493     void SubComponentManager::onSubComponentOpened( const ::rtl::OUString&  _rName, const sal_Int32 _nComponentType,
494         const ElementOpenMode _eOpenMode, const Reference< XComponent >& _rxComponent )
495     {
496 	    ::osl::ClearableMutexGuard aGuard( m_pData->getMutex() );
497 
498 #if OSL_DEBUG_LEVEL > 0
499         if ( _rName.getLength() )
500         {
501             // check there does not already exist such a component
502             SubComponents::const_iterator existentPos = ::std::find_if(
503                 m_pData->m_aComponents.begin(),
504                 m_pData->m_aComponents.end(),
505                 SubComponentMatch( _rName, _nComponentType, _eOpenMode )
506             );
507             OSL_ENSURE( existentPos == m_pData->m_aComponents.end(), "already existent!" );
508         }
509 #endif
510         SubComponentDescriptor aElement( _rName, _nComponentType, _eOpenMode, _rxComponent );
511         ENSURE_OR_THROW( aElement.xModel.is() || aElement.xController.is(), "illegal component" );
512 
513         m_pData->m_aComponents.push_back( aElement );
514 
515         // add as listener
516         if ( aElement.xController.is() )
517             aElement.xController->addEventListener( this );
518         if ( aElement.xModel.is() )
519             aElement.xModel->addEventListener( this );
520         if ( aElement.xDocumentDefinitionProperties.is() )
521             aElement.xDocumentDefinitionProperties->addPropertyChangeListener( PROPERTY_NAME, this );
522 
523         // notify this to interested parties
524         aGuard.clear();
525         lcl_notifySubComponentEvent( *m_pData, "OnSubComponentOpened", aElement );
526     }
527 
528 	//------------------------------------------------------------------------------------------------------------------
529     bool SubComponentManager::activateSubFrame( const ::rtl::OUString& _rName, const sal_Int32 _nComponentType,
530         const ElementOpenMode _eOpenMode, Reference< XComponent >& o_rComponent ) const
531     {
532 	    ::osl::MutexGuard aGuard( m_pData->getMutex() );
533 
534         SubComponents::const_iterator pos = ::std::find_if(
535             m_pData->m_aComponents.begin(),
536             m_pData->m_aComponents.end(),
537             SubComponentMatch( _rName, _nComponentType, _eOpenMode )
538         );
539         if ( pos == m_pData->m_aComponents.end() )
540             // no component with this name/type/open mode
541             return false;
542 
543         const Reference< XFrame > xFrame( pos->xFrame, UNO_SET_THROW );
544         const Reference< XTopWindow > xTopWindow( xFrame->getContainerWindow(), UNO_QUERY_THROW );
545         xTopWindow->toFront();
546 
547         if ( pos->xModel.is() )
548             o_rComponent = pos->xModel.get();
549         else if ( pos->xController.is() )
550             o_rComponent = pos->xController.get();
551         else
552             o_rComponent = pos->xFrame.get();
553 
554         return true;
555     }
556 
557 	//------------------------------------------------------------------------------------------------------------------
558     bool SubComponentManager::closeSubFrames( const ::rtl::OUString& i_rName, const sal_Int32 _nComponentType )
559     {
560 	    ::osl::MutexGuard aGuard( m_pData->getMutex() );
561         ENSURE_OR_RETURN_FALSE( i_rName.getLength(), "SubComponentManager::closeSubFrames: illegal name!" );
562 
563         SubComponents aWorkingCopy( m_pData->m_aComponents );
564         for (   SubComponents::const_iterator comp = aWorkingCopy.begin();
565                 comp != aWorkingCopy.end();
566                 ++comp
567             )
568         {
569             if ( ( comp->sName != i_rName ) || ( comp->nComponentType != _nComponentType ) )
570                 continue;
571 
572             if ( !lcl_closeComponent( *comp ) )
573                 return false;
574         }
575 
576         return true;
577     }
578 
579 	//------------------------------------------------------------------------------------------------------------------
580     bool SubComponentManager::lookupSubComponent( const Reference< XComponent >& i_rComponent,
581             ::rtl::OUString& o_rName, sal_Int32& o_rComponentType )
582     {
583         for (   SubComponents::const_iterator comp = m_pData->m_aComponents.begin();
584                 comp != m_pData->m_aComponents.end();
585                 ++comp
586             )
587         {
588             if  (   (   comp->xModel.is()
589                     &&  ( comp->xModel == i_rComponent )
590                     )
591                 ||  (   comp->xController.is()
592                     &&  ( comp->xController == i_rComponent )
593                     )
594                 ||  (   comp->xFrame.is()
595                     &&  ( comp->xFrame == i_rComponent )
596                     )
597                 )
598             {
599                 o_rName = comp->sName;
600                 o_rComponentType = comp->nComponentType;
601                 return true;
602             }
603         }
604         return false;
605     }
606 
607 //......................................................................................................................
608 } // namespace dbaui
609 //......................................................................................................................
610