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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_reportdesign.hxx"
26 
27 #include <ReportControllerObserver.hxx>
28 #include <ReportController.hxx>
29 #include <svl/smplhint.hxx>
30 #include <vos/mutex.hxx>
31 #include <vcl/svapp.hxx>
32 #include <com/sun/star/report/XFormattedField.hpp>
33 #include <com/sun/star/awt/FontSlant.hpp>
34 #include <FormattedFieldBeautifier.hxx>
35 
36 #include <svx/unopage.hxx>
37 
38 // DBG_*
39 #include <tools/debug.hxx>
40 // DBG_UNHANDLED_EXCEPTION
41 #include <tools/diagnose_ex.h>
42 
43 namespace rptui
44 {
45 
46 	using namespace ::com::sun::star;
47 
48     // const OReportController *& m_pReportController;
49 
50 DECLARE_STL_USTRINGACCESS_MAP(bool, AllProperties);
51 DECLARE_STL_STDKEY_MAP(uno::Reference< beans::XPropertySet >, AllProperties, PropertySetInfoCache);
52 
53 class OXReportControllerObserverImpl
54 {
55     OXReportControllerObserverImpl(OXReportControllerObserverImpl&);
56     void operator =(OXReportControllerObserverImpl&);
57 public:
58     const OReportController&                            m_rReportController;
59 	::std::vector< uno::Reference< container::XChild> > m_aSections;
60     ::osl::Mutex                                        m_aMutex;
61     oslInterlockedCount                                 m_nLocks;
62 	sal_Bool                                            m_bReadOnly;
63 
64     OXReportControllerObserverImpl(const OReportController& _rController);
65     ~OXReportControllerObserverImpl();
66 };
67 
68 // -----------------------------------------------------------------------------
69 
OXReportControllerObserverImpl(const OReportController & _rController)70     OXReportControllerObserverImpl::OXReportControllerObserverImpl(const OReportController& _rController)
71             :m_rReportController(_rController)
72             ,m_nLocks(0)
73             ,m_bReadOnly(sal_False)
74     {
75     }
76 
~OXReportControllerObserverImpl()77     OXReportControllerObserverImpl::~OXReportControllerObserverImpl()
78     {
79     }
80 
81     // -----------------------------------------------------------------------------
82     // -----------------------------------------------------------------------------
83     // -----------------------------------------------------------------------------
84 
DBG_NAME(rpt_OXReportControllerObserver)85     DBG_NAME(rpt_OXReportControllerObserver)
86 
87     OXReportControllerObserver::OXReportControllerObserver(const OReportController& _rController)
88             :m_pImpl(new OXReportControllerObserverImpl(_rController) )
89             ,m_aFormattedFieldBeautifier(_rController)
90             ,m_aFixedTextColor(_rController)
91     {
92         DBG_CTOR( rpt_OXReportControllerObserver,NULL);
93 
94         Application::AddEventListener(LINK( this, OXReportControllerObserver, SettingsChanged ) );
95     }
96 
~OXReportControllerObserver()97     OXReportControllerObserver::~OXReportControllerObserver()
98     {
99         DBG_CTOR( rpt_OXReportControllerObserver,NULL);
100         Application::RemoveEventListener(LINK( this, OXReportControllerObserver, SettingsChanged ) );
101     }
102 
103     // -----------------------------------------------------------------------------
IMPL_LINK(OXReportControllerObserver,SettingsChanged,VclWindowEvent *,_pEvt)104 	IMPL_LINK(OXReportControllerObserver, SettingsChanged, VclWindowEvent*, _pEvt)
105 	{
106 		if ( _pEvt )
107         {
108             sal_Int32 nEvent = _pEvt->GetId();
109             /*
110               // just for debug
111             if (nEvent == VCLEVENT_WINDOW_CHILDCREATED ||
112                 nEvent == VCLEVENT_WINDOW_PAINT ||
113                 nEvent == VCLEVENT_WINDOW_MOVE ||
114                 nEvent == VCLEVENT_WINDOW_RESIZE ||
115                 nEvent == VCLEVENT_WINDOW_SHOW ||
116                 nEvent == VCLEVENT_WINDOW_MOUSEMOVE ||
117                 nEvent == VCLEVENT_WINDOW_FRAMETITLECHANGED ||
118                 nEvent == VCLEVENT_WINDOW_HIDE ||
119                 nEvent == VCLEVENT_EDIT_MODIFY ||
120                 nEvent == VCLEVENT_SCROLLBAR_ENDSCROLL ||
121                 nEvent == VCLEVENT_EDIT_SELECTIONCHANGED ||
122                 nEvent == VCLEVENT_TABPAGE_INSERTED ||
123                 nEvent == VCLEVENT_TABPAGE_REMOVED ||
124                 nEvent == VCLEVENT_TOOLBOX_FORMATCHANGED ||
125                 nEvent == VCLEVENT_TOOLBOX_ITEMADDED ||
126                 nEvent == VCLEVENT_TOOLBOX_ALLITEMCHANGED ||
127                 nEvent == VCLEVENT_MENUBARADDED ||
128                 nEvent == 1
129                 )
130             {
131                 return 0L;
132             }
133             */
134 
135             if (nEvent == VCLEVENT_APPLICATION_DATACHANGED )
136             {
137                 DataChangedEvent* pData = reinterpret_cast<DataChangedEvent*>(_pEvt->GetData());
138                 if ( pData && ((( pData->GetType() == DATACHANGED_SETTINGS	)	||
139                                 ( pData->GetType() == DATACHANGED_DISPLAY	))	&&
140                                ( pData->GetFlags() & SETTINGS_STYLE		)))
141                 {
142                     OEnvLock aLock(*this);
143 
144                     // sal_uInt32 nCount = m_pImpl->m_aSections.size();
145 
146                     // send all Section Objects a 'tingle'
147                     // maybe they need a change in format, color, etc
148                     ::std::vector< uno::Reference< container::XChild > >::const_iterator aIter = m_pImpl->m_aSections.begin();
149                     ::std::vector< uno::Reference< container::XChild > >::const_iterator aEnd = m_pImpl->m_aSections.end();
150                     for (;aIter != aEnd; aIter++)
151                     {
152                         const uno::Reference<container::XChild> xChild (*aIter);
153                         if (xChild.is())
154                         {
155                             uno::Reference<report::XSection> xSection(xChild, uno::UNO_QUERY);
156                             if (xSection.is())
157                             {
158                                 const sal_Int32 nCount = xSection->getCount();
159                                 for (sal_Int32 i = 0; i < nCount; ++i)
160                                 {
161                                     const uno::Any aObj = xSection->getByIndex(i);
162                                     uno::Reference < report::XReportComponent > xReportComponent(aObj, uno::UNO_QUERY);
163                                     if (xReportComponent.is())
164                                     {
165                                         m_aFormattedFieldBeautifier.handle(xReportComponent);
166                                         m_aFixedTextColor.handle(xReportComponent);
167                                     }
168                                 }
169                             }
170                         }
171                     }
172                 }
173             }
174         }
175 
176         return 0L;
177     }
178 
179     // XEventListener
disposing(const lang::EventObject & e)180     void SAL_CALL OXReportControllerObserver::disposing(const lang::EventObject& e) throw( uno::RuntimeException )
181     {
182         (void) e;
183 	    // check if it's an object we have cached informations about
184         uno::Reference< beans::XPropertySet > xSourceSet(e.Source, uno::UNO_QUERY);
185         if ( xSourceSet.is() )
186         {
187             uno::Reference< report::XSection> xSection(xSourceSet,uno::UNO_QUERY);
188             if ( xSection.is() )
189                 RemoveSection(xSection);
190             else
191                 RemoveElement(xSourceSet);
192 	    }
193     }
194 
Clear()195     void OXReportControllerObserver::Clear()
196     {
197         OEnvLock aLock(*this);
198         // sal_uInt32 nDebugValue = m_pImpl->m_aSections.size();
199         m_pImpl->m_aSections.clear();
200     }
201 
202     // XPropertyChangeListener
propertyChange(const beans::PropertyChangeEvent & _rEvent)203     void SAL_CALL OXReportControllerObserver::propertyChange(const beans::PropertyChangeEvent& _rEvent) throw(uno::RuntimeException)
204     {
205         (void) _rEvent;
206         ::osl::ClearableMutexGuard aGuard( m_pImpl->m_aMutex );
207 
208     	if ( IsLocked() )
209             return;
210 
211         m_aFormattedFieldBeautifier.notifyPropertyChange(_rEvent);
212         m_aFixedTextColor.notifyPropertyChange(_rEvent);
213     }
214 
215 // -----------------------------------------------------------------------------
Lock()216 void OXReportControllerObserver::Lock()
217 {
218     OSL_ENSURE(m_refCount,"Illegal call to dead object!");
219     osl_incrementInterlockedCount( &m_pImpl->m_nLocks );
220 }
UnLock()221 void OXReportControllerObserver::UnLock()
222 {
223     OSL_ENSURE(m_refCount,"Illegal call to dead object!");
224 
225     osl_decrementInterlockedCount( &m_pImpl->m_nLocks );
226 }
IsLocked() const227 sal_Bool OXReportControllerObserver::IsLocked() const { return m_pImpl->m_nLocks != 0; }
228 
229 //------------------------------------------------------------------------------
AddSection(const uno::Reference<report::XSection> & _xSection)230 void OXReportControllerObserver::AddSection(const uno::Reference< report::XSection > & _xSection)
231 {
232     OEnvLock aLock(*this);
233     try
234     {
235 	    uno::Reference<container::XChild> xChild = _xSection.get();
236 	    m_pImpl->m_aSections.push_back(xChild);
237 	    uno::Reference< uno::XInterface >  xInt(_xSection);
238 	    AddElement(xInt);
239     }
240     catch(const uno::Exception&)
241     {
242         DBG_UNHANDLED_EXCEPTION();
243     }
244 }
245 
246 //------------------------------------------------------------------------------
RemoveSection(const uno::Reference<report::XSection> & _xSection)247 void OXReportControllerObserver::RemoveSection(const uno::Reference< report::XSection > & _xSection)
248 {
249 	OEnvLock aLock(*this);
250     try
251     {
252 	    uno::Reference<container::XChild> xChild(_xSection.get());
253 	    m_pImpl->m_aSections.erase(::std::remove(m_pImpl->m_aSections.begin(),m_pImpl->m_aSections.end(),
254 		    xChild), m_pImpl->m_aSections.end());
255 	    uno::Reference< uno::XInterface >  xInt(_xSection);
256 	    RemoveElement(xInt);
257     }
258     catch(uno::Exception&)
259     {
260         DBG_UNHANDLED_EXCEPTION();
261     }
262 }
263 
264 //------------------------------------------------------------------------------
TogglePropertyListening(const uno::Reference<uno::XInterface> & Element)265 void OXReportControllerObserver::TogglePropertyListening(const uno::Reference< uno::XInterface > & Element)
266 {
267 	// listen at Container
268 	uno::Reference< container::XIndexAccess >  xContainer(Element, uno::UNO_QUERY);
269 	if (xContainer.is())
270 	{
271 		uno::Reference< uno::XInterface > xInterface;
272 		sal_Int32 nCount = xContainer->getCount();
273 		for(sal_Int32 i = 0;i != nCount;++i)
274 		{
275 			xInterface.set(xContainer->getByIndex( i ),uno::UNO_QUERY);
276 			TogglePropertyListening(xInterface);
277 		}
278 	}
279 
280 	uno::Reference< beans::XPropertySet >  xSet(Element, uno::UNO_QUERY);
281 	if (xSet.is())
282 	{
283 		if (!m_pImpl->m_bReadOnly)
284 			xSet->addPropertyChangeListener( ::rtl::OUString(), this );
285 		else
286 			xSet->removePropertyChangeListener( ::rtl::OUString(), this );
287 	}
288 }
289 
290 
291 //------------------------------------------------------------------------------
switchListening(const uno::Reference<container::XIndexAccess> & _rxContainer,bool _bStartListening)292 void OXReportControllerObserver::switchListening( const uno::Reference< container::XIndexAccess >& _rxContainer, bool _bStartListening ) SAL_THROW(())
293 {
294     OSL_PRECOND( _rxContainer.is(), "OXReportControllerObserver::switchListening: invalid container!" );
295     if ( !_rxContainer.is() )
296         return;
297 
298     try
299     {
300         // also handle all children of this element
301 		uno::Reference< uno::XInterface > xInterface;
302         sal_Int32 nCount = _rxContainer->getCount();
303 		for(sal_Int32 i = 0;i != nCount;++i)
304 		{
305 			xInterface.set(_rxContainer->getByIndex( i ),uno::UNO_QUERY);
306             if ( _bStartListening )
307 		        AddElement( xInterface );
308             else
309 		        RemoveElement( xInterface );
310 	    }
311 
312         // be notified of any changes in the container elements
313 	    uno::Reference< container::XContainer > xSimpleContainer( _rxContainer, uno::UNO_QUERY );
314         // OSL_ENSURE( xSimpleContainer.is(), "OXReportControllerObserver::switchListening: how are we expected to be notified of changes in the container?" );
315 	    if ( xSimpleContainer.is() )
316         {
317             if ( _bStartListening )
318 		        xSimpleContainer->addContainerListener( this );
319             else
320 		        xSimpleContainer->removeContainerListener( this );
321         }
322     }
323     catch( const uno::Exception& )
324     {
325     	DBG_UNHANDLED_EXCEPTION();
326     }
327 }
328 
329 //------------------------------------------------------------------------------
switchListening(const uno::Reference<uno::XInterface> & _rxObject,bool _bStartListening)330 void OXReportControllerObserver::switchListening( const uno::Reference< uno::XInterface >& _rxObject, bool _bStartListening ) SAL_THROW(())
331 {
332     OSL_PRECOND( _rxObject.is(), "OXReportControllerObserver::switchListening: how should I listen at a NULL object?" );
333 
334     try
335     {
336         if ( !m_pImpl->m_bReadOnly )
337         {
338             uno::Reference< beans::XPropertySet > xProps( _rxObject, uno::UNO_QUERY );
339 	        if ( xProps.is() )
340             {
341                 if ( _bStartListening )
342     		        xProps->addPropertyChangeListener( ::rtl::OUString(), this );
343                 else
344     	    	    xProps->removePropertyChangeListener( ::rtl::OUString(), this );
345             }
346         }
347 
348         uno::Reference< util::XModifyBroadcaster > xBroadcaster( _rxObject, uno::UNO_QUERY );
349         if ( xBroadcaster.is() )
350         {
351             if ( _bStartListening )
352                 xBroadcaster->addModifyListener( this );
353             else
354                 xBroadcaster->removeModifyListener( this );
355         }
356     }
357     catch( const uno::Exception& )
358     {
359         DBG_UNHANDLED_EXCEPTION();
360     }
361 }
362 
363 //------------------------------------------------------------------------------
modified(const lang::EventObject &)364 void SAL_CALL OXReportControllerObserver::modified( const lang::EventObject& /*aEvent*/ ) throw (uno::RuntimeException)
365 {
366     // implSetModified();
367 }
368 
369 //------------------------------------------------------------------------------
AddElement(const uno::Reference<uno::XInterface> & _rxElement)370 void OXReportControllerObserver::AddElement(const uno::Reference< uno::XInterface >& _rxElement )
371 {
372     // if ( !IsLocked() )
373     // {
374     m_aFormattedFieldBeautifier.notifyElementInserted(_rxElement);
375     m_aFixedTextColor.notifyElementInserted(_rxElement);
376     // }
377 
378     // if it's a container, start listening at all elements
379     uno::Reference< container::XIndexAccess > xContainer( _rxElement, uno::UNO_QUERY );
380 	if ( xContainer.is() )
381         switchListening( xContainer, true );
382 
383     switchListening( _rxElement, true );
384 }
385 
386 //------------------------------------------------------------------------------
RemoveElement(const uno::Reference<uno::XInterface> & _rxElement)387 void OXReportControllerObserver::RemoveElement(const uno::Reference< uno::XInterface >& _rxElement)
388 {
389     switchListening( _rxElement, false );
390 
391 	uno::Reference< container::XIndexAccess > xContainer( _rxElement, uno::UNO_QUERY );
392     if ( xContainer.is() )
393         switchListening( xContainer, false );
394 }
395 
396 // -----------------------------------------------------------------------------
getSection(const uno::Reference<container::XChild> & _xContainer) const397 ::std::vector< uno::Reference< container::XChild> >::const_iterator OXReportControllerObserver::getSection(const uno::Reference<container::XChild>& _xContainer) const
398 {
399     ::std::vector< uno::Reference< container::XChild> >::const_iterator aFind = m_pImpl->m_aSections.end();
400     if ( _xContainer.is() )
401     {
402         aFind = ::std::find(m_pImpl->m_aSections.begin(),m_pImpl->m_aSections.end(),_xContainer);
403 
404 	    if ( aFind == m_pImpl->m_aSections.end() )
405 	    {
406             uno::Reference<container::XChild> xParent(_xContainer->getParent(),uno::UNO_QUERY);
407             aFind = getSection(xParent);
408         }
409     }
410     return aFind;
411 }
412 // XContainerListener
413 //------------------------------------------------------------------------------
elementInserted(const container::ContainerEvent & evt)414 void SAL_CALL OXReportControllerObserver::elementInserted(const container::ContainerEvent& evt) throw(uno::RuntimeException)
415 {
416 	::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() );
417     ::osl::MutexGuard aGuard( m_pImpl->m_aMutex );
418 
419 	// neues Object zum lauschen
420 	uno::Reference< uno::XInterface >  xIface( evt.Element, uno::UNO_QUERY );
421 	if ( xIface.is() )
422     {
423         AddElement(xIface);
424     }
425 }
426 
427 //------------------------------------------------------------------------------
elementReplaced(const container::ContainerEvent & evt)428 void SAL_CALL OXReportControllerObserver::elementReplaced(const container::ContainerEvent& evt) throw(uno::RuntimeException)
429 {
430 	::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() );
431     ::osl::MutexGuard aGuard( m_pImpl->m_aMutex );
432 
433     uno::Reference< uno::XInterface >  xIface(evt.ReplacedElement,uno::UNO_QUERY);
434 	OSL_ENSURE(xIface.is(), "OXReportControllerObserver::elementReplaced: invalid container notification!");
435 	RemoveElement(xIface);
436 
437     xIface.set(evt.Element,uno::UNO_QUERY);
438 	AddElement(xIface);
439 }
440 
441 //------------------------------------------------------------------------------
elementRemoved(const container::ContainerEvent & evt)442 void SAL_CALL OXReportControllerObserver::elementRemoved(const container::ContainerEvent& evt) throw(uno::RuntimeException)
443 {
444 	::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() );
445     ::osl::MutexGuard aGuard( m_pImpl->m_aMutex );
446 
447     uno::Reference< uno::XInterface >  xIface( evt.Element, uno::UNO_QUERY );
448 	if ( xIface.is() )
449 	{
450         RemoveElement(xIface);
451     }
452 }
453 
454 
455 } // namespace rptui
456 
457 
458 
459