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