1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
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.
14  *
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).
20  *
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.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_extensions.hxx"
30 #include "composeduiupdate.hxx"
31 
32 /** === begin UNO includes === **/
33 #include <com/sun/star/inspection/XObjectInspectorUI.hpp>
34 #include <com/sun/star/lang/DisposedException.hpp>
35 #include <com/sun/star/inspection/PropertyLineElement.hpp>
36 /** === end UNO includes === **/
37 #include <osl/mutex.hxx>
38 #include <rtl/ref.hxx>
39 
40 #include <algorithm>
41 
42 //........................................................................
43 namespace pcr
44 {
45 //........................................................................
46 
47     /** === begin UNO using === **/
48     using ::com::sun::star::uno::Exception;
49     using ::com::sun::star::lang::DisposedException;
50     using ::com::sun::star::lang::NullPointerException;
51     using ::com::sun::star::inspection::XPropertyHandler;
52     using ::com::sun::star::uno::Reference;
53     using ::com::sun::star::inspection::XObjectInspectorUI;
54     using ::com::sun::star::inspection::XPropertyControl;
55     using ::com::sun::star::uno::RuntimeException;
56     using ::com::sun::star::lang::NoSupportException;
57     using ::com::sun::star::inspection::XPropertyControlObserver;
58     /** === end UNO using === **/
59 
60     namespace PropertyLineElement = ::com::sun::star::inspection::PropertyLineElement;
61 
62     //====================================================================
63 	//= helper
64 	//====================================================================
65     namespace
66     {
67         struct HandlerLess : public ::std::binary_function  <	Reference< XPropertyHandler >
68 									                        ,   Reference< XPropertyHandler >
69 									                        ,	bool
70                                                             >
71         {
72 	        bool operator()( const Reference< XPropertyHandler >& lhs, const Reference< XPropertyHandler >& rhs) const
73 	        {
74 		        return lhs.get() < rhs.get();
75             }
76         };
77 
78         //================================================================
79         typedef ::std::set< ::rtl::OUString >       StringBag;
80         typedef ::std::map< sal_Int16, StringBag >  MapIntToStringBag;
81     }
82 
83     //====================================================================
84 	//= callbacks for CachedInspectorUI
85 	//====================================================================
86     typedef void (ComposedPropertyUIUpdate::*FNotifySingleUIChange)();
87 
88     //====================================================================
89 	//= CachedInspectorUI
90 	//====================================================================
91     typedef ::cppu::WeakImplHelper1 <   ::com::sun::star::inspection::XObjectInspectorUI
92                                     >   CachedInspectorUI_Base;
93     struct CachedInspectorUI : public CachedInspectorUI_Base
94     {
95     private:
96         ::osl::Mutex            m_aMutex;
97         oslInterlockedCount     m_refCount;
98         bool                    m_bDisposed;
99         ComposedPropertyUIUpdate&
100                                 m_rMaster;
101         FNotifySingleUIChange   m_pUIChangeNotification;
102 
103         // enablePropertyUI cache
104         StringBag               aEnabledProperties;
105         StringBag               aDisabledProperties;
106 
107         // show/hidePropertyUI cache
108         StringBag               aShownProperties;
109         StringBag               aHiddenProperties;
110 
111         // rebuildPropertyUI cache
112         StringBag               aRebuiltProperties;
113 
114         // showCategory cache
115         StringBag               aShownCategories;
116         StringBag               aHiddenCategories;
117 
118         // enablePropertyUIElements cache
119         MapIntToStringBag       aEnabledElements;
120         MapIntToStringBag       aDisabledElements;
121 
122     public:
123         typedef StringBag& (CachedInspectorUI::*FGetStringBag)();
124 
125         // enablePropertyUI cache
126         StringBag&  getEnabledProperties()          { return aEnabledProperties; }
127         StringBag&  getDisabledProperties()         { return aDisabledProperties; }
128 
129         // show/hidePropertyUI cache
130         StringBag&  getShownProperties()            { return aShownProperties; }
131         StringBag&  getHiddenProperties()           { return aHiddenProperties; }
132 
133         // rebuildPropertyUI cache
134         StringBag&  getRebuiltProperties()          { return aRebuiltProperties; }
135 
136         // showCategory cache
137         StringBag&  getShownCategories()            { return aShownCategories; }
138         StringBag&  getHiddenCategories()           { return aHiddenCategories; }
139 
140         // enablePropertyUIElements
141         StringBag&  getEnabledInputControls()       { return aEnabledElements[ PropertyLineElement::InputControl ]; }
142         StringBag&  getDisabledInputControls()      { return aDisabledElements[ PropertyLineElement::InputControl ]; }
143         StringBag&  getEnabledPrimaryButtons()      { return aEnabledElements[ PropertyLineElement::PrimaryButton ]; }
144         StringBag&  getDisabledPrimaryButtons()     { return aDisabledElements[ PropertyLineElement::PrimaryButton ]; }
145         StringBag&  getEnabledSecondaryButtons()    { return aEnabledElements[ PropertyLineElement::SecondaryButton ]; }
146         StringBag&  getDisabledSecondaryButtons()   { return aDisabledElements[ PropertyLineElement::SecondaryButton ]; }
147 
148     public:
149         CachedInspectorUI( ComposedPropertyUIUpdate& _rMaster, FNotifySingleUIChange _pUIChangeNotification );
150 
151         /// disposes the instance
152         void dispose();
153 
154         // XObjectInspectorUI overridables
155         virtual void SAL_CALL enablePropertyUI( const ::rtl::OUString& _rPropertyName, ::sal_Bool _bEnable ) throw (RuntimeException);
156         virtual void SAL_CALL enablePropertyUIElements( const ::rtl::OUString& _rPropertyName, ::sal_Int16 _nElements, ::sal_Bool _bEnable ) throw (RuntimeException);
157         virtual void SAL_CALL rebuildPropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException);
158         virtual void SAL_CALL showPropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException);
159         virtual void SAL_CALL hidePropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException);
160         virtual void SAL_CALL showCategory( const ::rtl::OUString& _rCategory, ::sal_Bool _bShow ) throw (RuntimeException);
161         virtual Reference< XPropertyControl > SAL_CALL getPropertyControl( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException);
162         virtual void SAL_CALL registerControlObserver( const Reference< XPropertyControlObserver >& Observer ) throw (RuntimeException);
163         virtual void SAL_CALL revokeControlObserver( const Reference< XPropertyControlObserver >& Observer ) throw (RuntimeException);
164         virtual void SAL_CALL setHelpSectionText( const ::rtl::OUString& _HelpText ) throw (NoSupportException, RuntimeException);
165 
166         // UNOCompatibleNonUNOReference overridables
167 		virtual void SAL_CALL acquire() throw();
168 		virtual void SAL_CALL release() throw();
169 
170     protected:
171         ~CachedInspectorUI();
172 
173         /// determines whether the instance is already disposed
174         inline bool isDisposed() const { return m_bDisposed; }
175 
176         /// throws an exception if the component is already disposed
177         void checkDisposed() const;
178 
179     private:
180         void    impl_markElementEnabledOrDisabled( const ::rtl::OUString& _rPropertyName, sal_Int16 _nElementIdOrZero, sal_Bool _bEnable );
181 
182         /** calls <member>m_pUIChangeNotification</member> at <member>m_rMaster</member>
183         */
184         void    impl_notifySingleUIChange() const;
185 
186     private:
187         CachedInspectorUI( const CachedInspectorUI& );              // never implemented
188         CachedInspectorUI& operator=( const CachedInspectorUI& );   // never implemented
189 
190     private:
191         class MethodGuard;
192         friend class MethodGuard;
193         class MethodGuard : public ::osl::MutexGuard
194         {
195         public:
196             MethodGuard( CachedInspectorUI& rInstance )
197                 : ::osl::MutexGuard( rInstance.m_aMutex )
198             {
199                 rInstance.checkDisposed();
200             }
201         };
202     };
203 
204     //----------------------------------------------------------------
205     CachedInspectorUI::CachedInspectorUI( ComposedPropertyUIUpdate& _rMaster, FNotifySingleUIChange _pUIChangeNotification )
206         :m_refCount( 0 )
207         ,m_bDisposed( false )
208         ,m_rMaster( _rMaster )
209         ,m_pUIChangeNotification( _pUIChangeNotification )
210     {
211     }
212 
213     //----------------------------------------------------------------
214     CachedInspectorUI::~CachedInspectorUI()
215     {
216     }
217 
218     //----------------------------------------------------------------
219     void CachedInspectorUI::dispose()
220     {
221         ::osl::MutexGuard aGuard( m_aMutex );
222         m_bDisposed = true;
223 
224         clearContainer( aEnabledProperties );
225         clearContainer( aDisabledProperties );
226         clearContainer( aRebuiltProperties );
227         clearContainer( aShownProperties );
228         clearContainer( aHiddenProperties );
229         clearContainer( aShownCategories );
230         clearContainer( aHiddenCategories );
231         clearContainer( aEnabledElements );
232         clearContainer( aDisabledElements );
233     }
234 
235     //----------------------------------------------------------------
236     void SAL_CALL CachedInspectorUI::acquire() throw()
237     {
238         osl_incrementInterlockedCount( &m_refCount );
239     }
240 
241     //----------------------------------------------------------------
242     void SAL_CALL CachedInspectorUI::release() throw()
243     {
244         if ( 0 == osl_decrementInterlockedCount( &m_refCount ) )
245             delete this;
246     }
247 
248 
249 	//----------------------------------------------------------------
250     void CachedInspectorUI::checkDisposed() const
251     {
252         if ( isDisposed() )
253             throw DisposedException();
254     }
255 
256     //----------------------------------------------------------------
257     namespace
258     {
259         void lcl_markStringKeyPositiveOrNegative( const ::rtl::OUString& _rKeyName, StringBag& _rPositives, StringBag& _rNegatives, sal_Bool _bMarkPositive )
260         {
261             if ( _bMarkPositive )
262             {
263                 _rPositives.insert( _rKeyName );
264                 // if the same key has been remember as in the "negative" list before, clear this information, since it's overruled
265                 _rNegatives.erase( _rKeyName );
266             }
267             else
268                 _rNegatives.insert( _rKeyName );
269         }
270     }
271 
272     //----------------------------------------------------------------
273     void CachedInspectorUI::enablePropertyUI( const ::rtl::OUString& _rPropertyName, sal_Bool _bEnable ) throw (RuntimeException)
274     {
275         MethodGuard aGuard( *this );
276         if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) )
277             return;
278 
279         lcl_markStringKeyPositiveOrNegative( _rPropertyName, aEnabledProperties, aDisabledProperties, _bEnable );
280         impl_notifySingleUIChange();
281     }
282 
283     //----------------------------------------------------------------
284     void CachedInspectorUI::impl_markElementEnabledOrDisabled( const ::rtl::OUString& _rPropertyName, sal_Int16 _nElementIdOrZero, sal_Bool _bEnable )
285     {
286         if ( _nElementIdOrZero == 0 )
287             return;
288 
289         lcl_markStringKeyPositiveOrNegative(
290             _rPropertyName,
291             aEnabledElements[ _nElementIdOrZero ],
292             aDisabledElements[ _nElementIdOrZero ],
293             _bEnable
294         );
295     }
296 
297     //----------------------------------------------------------------
298     void CachedInspectorUI::impl_notifySingleUIChange() const
299     {
300         (m_rMaster.*m_pUIChangeNotification)();
301     }
302 
303     //----------------------------------------------------------------
304     void CachedInspectorUI::enablePropertyUIElements( const ::rtl::OUString& _rPropertyName, sal_Int16 _nElements, sal_Bool _bEnable ) throw (RuntimeException)
305     {
306         MethodGuard aGuard( *this );
307         if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) )
308             return;
309 
310         impl_markElementEnabledOrDisabled( _rPropertyName, _nElements & PropertyLineElement::InputControl,    _bEnable );
311         impl_markElementEnabledOrDisabled( _rPropertyName, _nElements & PropertyLineElement::PrimaryButton,   _bEnable );
312         impl_markElementEnabledOrDisabled( _rPropertyName, _nElements & PropertyLineElement::SecondaryButton, _bEnable );
313 
314         impl_notifySingleUIChange();
315     }
316 
317     //----------------------------------------------------------------
318     void CachedInspectorUI::rebuildPropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException)
319     {
320         MethodGuard aGuard( *this );
321         if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) )
322             return;
323 
324         aRebuiltProperties.insert( _rPropertyName );
325 
326         impl_notifySingleUIChange();
327     }
328 
329     //----------------------------------------------------------------
330     void CachedInspectorUI::showPropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException)
331     {
332         MethodGuard aGuard( *this );
333         if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) )
334             return;
335 
336         aShownProperties.insert( _rPropertyName );
337         // if the same category has been hidden before, clear this information, since it's overruled
338         aHiddenProperties.erase( _rPropertyName );
339 
340         impl_notifySingleUIChange();
341     }
342 
343     //----------------------------------------------------------------
344     void CachedInspectorUI::hidePropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException)
345     {
346         MethodGuard aGuard( *this );
347         if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) )
348             return;
349 
350         aHiddenProperties.insert( _rPropertyName );
351         impl_notifySingleUIChange();
352     }
353 
354     //----------------------------------------------------------------
355     void CachedInspectorUI::showCategory( const ::rtl::OUString& _rCategory, sal_Bool _bShow ) throw (RuntimeException)
356     {
357         MethodGuard aGuard( *this );
358 
359         lcl_markStringKeyPositiveOrNegative( _rCategory, aShownCategories, aHiddenCategories, _bShow );
360         impl_notifySingleUIChange();
361     }
362 
363     //----------------------------------------------------------------
364     Reference< XPropertyControl > SAL_CALL CachedInspectorUI::getPropertyControl( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException)
365     {
366         MethodGuard aGuard( *this );
367         if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) )
368             return Reference< XPropertyControl >();
369 
370         return m_rMaster.getDelegatorUI()->getPropertyControl( _rPropertyName );
371     }
372 
373     //--------------------------------------------------------------------
374     void SAL_CALL CachedInspectorUI::registerControlObserver( const Reference< XPropertyControlObserver >& _Observer ) throw (RuntimeException)
375     {
376         OSL_ENSURE( false, "CachedInspectorUI::registerControlObserver: not expected to be called!" );
377             // CachedInspectorUI is used as context for the controls, and we don't expect them to
378             // register listeners themself
379         m_rMaster.getDelegatorUI()->registerControlObserver( _Observer );
380     }
381 
382     //--------------------------------------------------------------------
383     void SAL_CALL CachedInspectorUI::revokeControlObserver( const Reference< XPropertyControlObserver >& _Observer ) throw (RuntimeException)
384     {
385         OSL_ENSURE( false, "CachedInspectorUI::revokeControlObserver: not expected to be called!" );
386             // CachedInspectorUI is used as context for the controls, and we don't expect them to
387             // register listeners themself
388         m_rMaster.getDelegatorUI()->revokeControlObserver( _Observer );
389     }
390 
391     //----------------------------------------------------------------
392     void SAL_CALL CachedInspectorUI::setHelpSectionText( const ::rtl::OUString& _HelpText ) throw (NoSupportException, RuntimeException)
393     {
394         m_rMaster.getDelegatorUI()->setHelpSectionText( _HelpText );
395     }
396 
397     //====================================================================
398 	//= HandlerMap
399 	//====================================================================
400     typedef ::std::map  <   Reference< XPropertyHandler >
401                         ,   ::rtl::Reference< CachedInspectorUI >
402                         ,   HandlerLess
403                         >   ImplMapHandlerToUI;
404     struct MapHandlerToUI
405     {
406         ImplMapHandlerToUI aHandlers;
407     };
408 
409     //====================================================================
410 	//= ComposedPropertyUIUpdate
411 	//====================================================================
412 	//----------------------------------------------------------------
413     ComposedPropertyUIUpdate::ComposedPropertyUIUpdate( const Reference< XObjectInspectorUI >& _rxDelegatorUI,
414         IPropertyExistenceCheck* _pPropertyCheck )
415         :m_pCollectedUIs( new MapHandlerToUI )
416         ,m_xDelegatorUI( _rxDelegatorUI )
417         ,m_nSuspendCounter( 0 )
418         ,m_pPropertyCheck( _pPropertyCheck )
419     {
420         if ( !m_xDelegatorUI.is() )
421             throw NullPointerException();
422     }
423 
424 	//----------------------------------------------------------------
425     ComposedPropertyUIUpdate::~ComposedPropertyUIUpdate( )
426     {
427     }
428 
429 	//----------------------------------------------------------------
430     Reference< XObjectInspectorUI > ComposedPropertyUIUpdate::getUIForPropertyHandler( const Reference< XPropertyHandler >& _rxHandler )
431     {
432         impl_checkDisposed();
433 
434         ::rtl::Reference< CachedInspectorUI >& rUI = m_pCollectedUIs->aHandlers[ _rxHandler ];
435         if ( !rUI.is() )
436             rUI = new CachedInspectorUI( *this, &ComposedPropertyUIUpdate::callback_inspectorUIChanged_throw );
437         return rUI.get();
438     }
439 
440 	//----------------------------------------------------------------
441     namespace
442     {
443         //============================================================
444 	    //= StringBagCollector
445 	    //============================================================
446         /** an STL-compatible structure which collects strings from a CachedInspectorUI instances
447         */
448         struct StringBagCollector : public ::std::unary_function< ImplMapHandlerToUI::value_type, void >
449         {
450         private:
451             StringBag&                      m_rBag;
452             CachedInspectorUI::FGetStringBag  m_pGetter;
453 
454         public:
455             StringBagCollector( StringBag& _rBag, CachedInspectorUI::FGetStringBag _pGetter ) :m_rBag( _rBag ), m_pGetter( _pGetter ) { }
456 
457             void operator()( const ImplMapHandlerToUI::value_type& _rUI )
458             {
459                 StringBag& rBag( ((_rUI.second.get())->*m_pGetter)() );
460                 m_rBag.insert( rBag.begin(), rBag.end() );
461             }
462 
463             static void collectAll( StringBag& _rAll, const ImplMapHandlerToUI& _rMap, CachedInspectorUI::FGetStringBag _pGetter )
464             {
465                 ::std::for_each( _rMap.begin(), _rMap.end(), StringBagCollector( _rAll, _pGetter ) );
466             }
467         };
468 
469         //============================================================
470 	    //= StringBagClearer
471 	    //============================================================
472         /** an STL-compatible structure which cleans a certain string bag in a CachedInspectorUI instances
473         */
474         struct StringBagClearer : public ::std::unary_function< ImplMapHandlerToUI::value_type, void >
475         {
476         private:
477             CachedInspectorUI::FGetStringBag  m_pGetter;
478 
479         public:
480             StringBagClearer( CachedInspectorUI::FGetStringBag _pGetter ) :m_pGetter( _pGetter ) { }
481 
482             void operator()( const ImplMapHandlerToUI::value_type& _rUI )
483             {
484                 clearContainer( ((_rUI.second.get())->*m_pGetter)() );
485             }
486 
487             static void clearAll( const ImplMapHandlerToUI& _rMap, CachedInspectorUI::FGetStringBag _pGetter )
488             {
489                 ::std::for_each( _rMap.begin(), _rMap.end(), StringBagClearer( _pGetter ) );
490             }
491         };
492 
493         //============================================================
494 	    //= FPropertyUISetter
495 	    //============================================================
496         /** a typedef for a ->XObjectInspectorUI member function taking a string
497         */
498         typedef void ( SAL_CALL XObjectInspectorUI::*FPropertyUISetter )( const ::rtl::OUString& );
499 
500         //============================================================
501 	    //= PropertyUIOperator
502 	    //============================================================
503         /** an STL-compatible struct which calls a certain member method (taking a string) at a
504             given ->XObjectInspectorUI instance
505         */
506         struct PropertyUIOperator : public ::std::unary_function< ::rtl::OUString, void >
507         {
508         private:
509             Reference< XObjectInspectorUI > m_xUpdater;
510             FPropertyUISetter               m_pSetter;
511 
512         public:
513             PropertyUIOperator( const Reference< XObjectInspectorUI >& _rxInspectorUI, FPropertyUISetter _pSetter )
514                 :m_xUpdater( _rxInspectorUI )
515                 ,m_pSetter( _pSetter )
516             {
517             }
518 
519             void operator()( const ::rtl::OUString& _rPropertyName )
520             {
521                 ((m_xUpdater.get())->*m_pSetter)( _rPropertyName );
522             }
523 
524             static void forEach( const StringBag& _rProperties, const Reference< XObjectInspectorUI >& _rxDelegatorUI, FPropertyUISetter _pSetter )
525             {
526                 ::std::for_each( _rProperties.begin(), _rProperties.end(), PropertyUIOperator( _rxDelegatorUI, _pSetter ) );
527             }
528         };
529 
530         //============================================================
531 	    //= IStringKeyBooleanUIUpdate
532 	    //============================================================
533         /** an interface which encapsulates access to a single aspect of the ->XObjectInspectorUI,
534             where this aspect is given by a string key, and has a boolean value.
535         */
536         class IStringKeyBooleanUIUpdate
537         {
538         public:
539             virtual void updateUIForKey( const ::rtl::OUString& _rKey, sal_Bool _bFlag ) const = 0;
540 
541             virtual ~IStringKeyBooleanUIUpdate() { }
542         };
543 
544         //============================================================
545 	    //= FPropertyUIFlagSetter
546 	    //============================================================
547         /** an implementation of the ->IStringKeyBooleanUIUpdate interface which,
548             for a fixed ->XObjectInspectorUI instance and a fixed UI element (->PropertyLineElement),
549             updates this element for a given property with a given boolean flag
550             (->XObjectInspectorUI::enablePropertyUIElements)
551         */
552         class EnablePropertyUIElement : public IStringKeyBooleanUIUpdate
553         {
554         private:
555             Reference< XObjectInspectorUI > m_xUIUpdate;
556             sal_Int16                       m_nElement;
557 
558         public:
559             EnablePropertyUIElement( const Reference< XObjectInspectorUI >& _rxUIUpdate, sal_Int16 _nElement )
560                 :m_xUIUpdate( _rxUIUpdate )
561                 ,m_nElement( _nElement )
562             {
563             }
564             // IStringKeyBooleanUIUpdate
565             virtual void updateUIForKey( const ::rtl::OUString& _rKey, sal_Bool _bFlag ) const;
566         };
567 
568         //............................................................
569         void EnablePropertyUIElement::updateUIForKey( const ::rtl::OUString& _rKey, sal_Bool _bFlag ) const
570         {
571             m_xUIUpdate->enablePropertyUIElements( _rKey, m_nElement, _bFlag );
572         }
573 
574         //============================================================
575 	    //= FPropertyUIFlagSetter
576 	    //============================================================
577         /** a ->XObjectInspectorUI method taking a string and a boolean
578         */
579         typedef void ( SAL_CALL XObjectInspectorUI::*FPropertyUIFlagSetter )( const ::rtl::OUString&, sal_Bool );
580 
581         //============================================================
582 	    //= DefaultStringKeyBooleanUIUpdate
583 	    //============================================================
584         /** an implementaiton of the ->IStringKeyBooleanUIUpdate interface which calls
585             am arbitrary ->XObjectInspectorUI method taking a string and a boolean flag
586         */
587         class DefaultStringKeyBooleanUIUpdate : public IStringKeyBooleanUIUpdate
588         {
589         private:
590             Reference< XObjectInspectorUI > m_xUIUpdate;
591             FPropertyUIFlagSetter           m_pSetter;
592 
593         public:
594             DefaultStringKeyBooleanUIUpdate( const Reference< XObjectInspectorUI >& _rxUIUpdate, FPropertyUIFlagSetter _pSetter );
595             // IStringKeyBooleanUIUpdate
596             virtual void updateUIForKey( const ::rtl::OUString& _rKey, sal_Bool _bFlag ) const;
597         };
598 
599         //............................................................
600         DefaultStringKeyBooleanUIUpdate::DefaultStringKeyBooleanUIUpdate( const Reference< XObjectInspectorUI >& _rxUIUpdate, FPropertyUIFlagSetter _pSetter )
601             :m_xUIUpdate( _rxUIUpdate )
602             ,m_pSetter( _pSetter )
603         {
604         }
605 
606         //............................................................
607         void DefaultStringKeyBooleanUIUpdate::updateUIForKey( const ::rtl::OUString& _rKey, sal_Bool _bFlag ) const
608         {
609             ((m_xUIUpdate.get())->*m_pSetter)( _rKey, _bFlag );
610         }
611 
612         //============================================================
613 	    //= BooleanUIAspectUpdate
614 	    //============================================================
615         /** an STL-compatible structure which applies a ->IStringKeyBooleanUIUpdate::updateUIForKey
616             operation with a fixed boolean value, for a given string value
617         */
618         struct BooleanUIAspectUpdate : public ::std::unary_function< ::rtl::OUString, void >
619         {
620         private:
621             const IStringKeyBooleanUIUpdate&    m_rUpdater;
622             sal_Bool                            m_bFlag;
623 
624         public:
625             BooleanUIAspectUpdate( const IStringKeyBooleanUIUpdate& _rUpdater, sal_Bool _bFlag )
626                 :m_rUpdater( _rUpdater )
627                 ,m_bFlag( _bFlag )
628             {
629             }
630 
631             void operator()( const ::rtl::OUString& _rPropertyName )
632             {
633                 m_rUpdater.updateUIForKey( _rPropertyName, m_bFlag );
634             }
635 
636             static void forEach( const StringBag& _rProperties, const IStringKeyBooleanUIUpdate& _rUpdater, sal_Bool _bFlag )
637             {
638                 ::std::for_each( _rProperties.begin(), _rProperties.end(), BooleanUIAspectUpdate( _rUpdater, _bFlag ) );
639             }
640         };
641 
642         //============================================================
643 	    //= BooleanUIAspectUpdate
644 	    //============================================================
645         /** an STL-compatible structure subtracting a given string from a fixed ->StringBag
646         */
647         struct StringBagComplement : public ::std::unary_function< ::rtl::OUString, void >
648         {
649         private:
650             StringBag&  m_rMinuend;
651 
652         public:
653             StringBagComplement( StringBag& _rMinuend ) :m_rMinuend( _rMinuend ) { }
654 
655             void operator()( const ::rtl::OUString& _rPropertyToSubtract )
656             {
657                 m_rMinuend.erase( _rPropertyToSubtract );
658             }
659 
660             static void subtract( StringBag& _rMinuend, const StringBag& _rSubtrahend )
661             {
662                 ::std::for_each( _rSubtrahend.begin(), _rSubtrahend.end(), StringBagComplement( _rMinuend ) );
663             }
664         };
665 
666         //============================================================
667 	    //= BooleanUIAspectUpdate
668 	    //============================================================
669         void lcl_fireUIStateFlag(
670                 const IStringKeyBooleanUIUpdate& _rUIUpdate,
671                 const ImplMapHandlerToUI& _rHandlerUIs,
672                 CachedInspectorUI::FGetStringBag _pGetPositives,
673                 CachedInspectorUI::FGetStringBag _pGetNegatives
674             )
675         {
676             // all strings which are in the "positive" list of one handler
677             StringBag aAllPositives;
678             StringBagCollector::collectAll( aAllPositives, _rHandlerUIs, _pGetPositives );
679 
680             // all strings which are in the "negative" list of one handler
681             StringBag aAllNegatives;
682             StringBagCollector::collectAll( aAllNegatives, _rHandlerUIs, _pGetNegatives );
683 
684             // propagate the "negative" flags to the delegator UI
685             BooleanUIAspectUpdate::forEach( aAllNegatives, _rUIUpdate, sal_False );
686 
687             // propagate the "positive" flags to the delegator UI, for all elements where _no_
688             // "negative" flag exists
689             StringBagComplement::subtract( aAllPositives, aAllNegatives );
690             BooleanUIAspectUpdate::forEach( aAllPositives, _rUIUpdate, sal_True );
691 
692             // the "positive" request can be cleared no, only negative requests
693             // (such as "disable a property" or "hide a category") need to be preserved for the next round
694             StringBagClearer::clearAll( _rHandlerUIs, _pGetPositives );
695         }
696     }
697 
698 	//----------------------------------------------------------------
699     void ComposedPropertyUIUpdate::impl_fireEnablePropertyUI_throw()
700     {
701         lcl_fireUIStateFlag(
702             DefaultStringKeyBooleanUIUpdate( m_xDelegatorUI, &XObjectInspectorUI::enablePropertyUI ),
703             m_pCollectedUIs->aHandlers,
704             &CachedInspectorUI::getEnabledProperties,
705             &CachedInspectorUI::getDisabledProperties
706         );
707     }
708 
709 	//----------------------------------------------------------------
710     void ComposedPropertyUIUpdate::impl_fireRebuildPropertyUI_throw()
711     {
712         // collect all properties for which a rebuild request has been made
713         StringBag aAllRebuilt;
714         StringBagCollector::collectAll( aAllRebuilt, m_pCollectedUIs->aHandlers, &CachedInspectorUI::getRebuiltProperties );
715 
716         // rebuild all those properties
717         PropertyUIOperator::forEach( aAllRebuilt, m_xDelegatorUI, &XObjectInspectorUI::rebuildPropertyUI );
718 
719         // clear the "properties to rebuild" at all handlers, since the request has been fulfilled now.
720         StringBagClearer::clearAll( m_pCollectedUIs->aHandlers, &CachedInspectorUI::getRebuiltProperties );
721     }
722 
723 	//----------------------------------------------------------------
724     void ComposedPropertyUIUpdate::impl_fireShowHidePropertyUI_throw()
725     {
726         // all properties which have been shown by at least one handler
727         StringBag aAllShown;
728         StringBagCollector::collectAll( aAllShown, m_pCollectedUIs->aHandlers, &CachedInspectorUI::getShownProperties );
729         // all properties which have been hidden by at least one handler
730         StringBag aAllHidden;
731         StringBagCollector::collectAll( aAllHidden, m_pCollectedUIs->aHandlers, &CachedInspectorUI::getHiddenProperties );
732 
733         // hide properties as necessary
734         PropertyUIOperator::forEach( aAllHidden, m_xDelegatorUI, &XObjectInspectorUI::hidePropertyUI );
735 
736         // for those properties which are hidden, ignore all "show" requests which other handlers might have had
737         StringBagComplement::subtract( aAllShown, aAllHidden );
738 
739         // show properties
740         PropertyUIOperator::forEach( aAllShown, m_xDelegatorUI, &XObjectInspectorUI::showPropertyUI );
741     }
742 
743 	//----------------------------------------------------------------
744     void ComposedPropertyUIUpdate::impl_fireShowCategory_throw()
745     {
746         lcl_fireUIStateFlag(
747             DefaultStringKeyBooleanUIUpdate( m_xDelegatorUI, &XObjectInspectorUI::showCategory ),
748             m_pCollectedUIs->aHandlers,
749             &CachedInspectorUI::getShownCategories,
750             &CachedInspectorUI::getHiddenCategories
751         );
752     }
753 
754 	//----------------------------------------------------------------
755     void ComposedPropertyUIUpdate::impl_fireEnablePropertyUIElements_throw()
756     {
757         lcl_fireUIStateFlag(
758             EnablePropertyUIElement( m_xDelegatorUI, PropertyLineElement::InputControl ),
759             m_pCollectedUIs->aHandlers,
760             &CachedInspectorUI::getEnabledInputControls,
761             &CachedInspectorUI::getDisabledInputControls
762         );
763 
764         lcl_fireUIStateFlag(
765             EnablePropertyUIElement( m_xDelegatorUI, PropertyLineElement::PrimaryButton ),
766             m_pCollectedUIs->aHandlers,
767             &CachedInspectorUI::getEnabledPrimaryButtons,
768             &CachedInspectorUI::getDisabledPrimaryButtons
769         );
770 
771         lcl_fireUIStateFlag(
772             EnablePropertyUIElement( m_xDelegatorUI, PropertyLineElement::SecondaryButton ),
773             m_pCollectedUIs->aHandlers,
774             &CachedInspectorUI::getEnabledSecondaryButtons,
775             &CachedInspectorUI::getDisabledSecondaryButtons
776         );
777     }
778 
779     //--------------------------------------------------------------------
780     void ComposedPropertyUIUpdate::impl_fireAll_throw()
781     {
782         OSL_PRECOND( !impl_isDisposed(), "ComposedPropertyUIUpdate::impl_fireAll_throw: already disposed, this will crash!" );
783 
784         impl_fireEnablePropertyUI_throw();
785         impl_fireShowHidePropertyUI_throw();
786         impl_fireRebuildPropertyUI_throw();
787         impl_fireShowCategory_throw();
788         impl_fireEnablePropertyUIElements_throw();
789     }
790 
791     //--------------------------------------------------------------------
792     void SAL_CALL ComposedPropertyUIUpdate::suspendAutoFire()
793     {
794         impl_checkDisposed();
795         osl_incrementInterlockedCount( &m_nSuspendCounter );
796     }
797 
798     //--------------------------------------------------------------------
799     void SAL_CALL ComposedPropertyUIUpdate::resumeAutoFire()
800     {
801         impl_checkDisposed();
802         if ( 0 == osl_decrementInterlockedCount( &m_nSuspendCounter ) )
803             impl_fireAll_throw();
804     }
805 
806 	//----------------------------------------------------------------
807     void ComposedPropertyUIUpdate::impl_checkDisposed() const
808     {
809         if ( impl_isDisposed() )
810             throw DisposedException();
811     }
812 
813 	//----------------------------------------------------------------
814     void ComposedPropertyUIUpdate::callback_inspectorUIChanged_throw()
815     {
816         if ( 0 == m_nSuspendCounter )
817             impl_fireAll_throw();
818     }
819 
820 	//----------------------------------------------------------------
821     Reference< XObjectInspectorUI > ComposedPropertyUIUpdate::getDelegatorUI() const
822     {
823         impl_checkDisposed();
824         return m_xDelegatorUI;
825     }
826 
827     //----------------------------------------------------------------
828     void SAL_CALL ComposedPropertyUIUpdate::dispose()
829     {
830         if ( impl_isDisposed() )
831             return;
832 
833         OSL_ENSURE( m_nSuspendCounter == 0, "ComposedPropertyUIUpdate::dispose: still suspended, the changes will be lost!" );
834 
835         for ( ImplMapHandlerToUI::const_iterator singleUI = m_pCollectedUIs->aHandlers.begin();
836               singleUI != m_pCollectedUIs->aHandlers.end();
837               ++singleUI
838             )
839         {
840             singleUI->second->dispose();
841         }
842         m_pCollectedUIs.reset( NULL );
843         m_xDelegatorUI.set( NULL );
844     }
845 
846     //----------------------------------------------------------------
847     bool ComposedPropertyUIUpdate::shouldContinuePropertyHandling( const ::rtl::OUString& _rName ) const
848     {
849         if ( !m_pPropertyCheck )
850             return true;
851         if ( m_pPropertyCheck->hasPropertyByName( _rName ) )
852             return true;
853         return false;
854     }
855 
856 //........................................................................
857 } // namespace pcr
858 //........................................................................
859 
860