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_svx.hxx"
26 
27 #include <svx/sdr/contact/viewobjectcontactofunocontrol.hxx>
28 #include <svx/sdr/contact/viewcontactofunocontrol.hxx>
29 #include <svx/sdr/contact/displayinfo.hxx>
30 #include <svx/sdr/properties/properties.hxx>
31 #include <svx/sdr/contact/objectcontactofpageview.hxx>
32 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
33 #include <svx/svdouno.hxx>
34 #include <svx/svdpagv.hxx>
35 #include <svx/svdview.hxx>
36 #include <svx/sdrpagewindow.hxx>
37 #include "svx/sdrpaintwindow.hxx"
38 
39 /** === begin UNO includes === **/
40 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
41 #include <com/sun/star/awt/XControl.hpp>
42 #include <com/sun/star/awt/XControlModel.hpp>
43 #include <com/sun/star/awt/XControlContainer.hpp>
44 #include <com/sun/star/awt/XWindow2.hpp>
45 #include <com/sun/star/awt/PosSize.hpp>
46 #include <com/sun/star/awt/XView.hpp>
47 #include <com/sun/star/beans/XPropertySet.hpp>
48 #include <com/sun/star/lang/XComponent.hpp>
49 #include <com/sun/star/awt/InvalidateStyle.hpp>
50 #include <com/sun/star/util/XModeChangeListener.hpp>
51 #include <com/sun/star/util/XModeChangeBroadcaster.hpp>
52 #include <com/sun/star/container/XContainerListener.hpp>
53 #include <com/sun/star/container/XContainer.hpp>
54 /** === end UNO includes === **/
55 
56 #include <vcl/svapp.hxx>
57 #include <vos/mutex.hxx>
58 #include <comphelper/processfactory.hxx>
59 #include <comphelper/scopeguard.hxx>
60 #include <cppuhelper/implbase4.hxx>
61 #include <toolkit/helper/vclunohelper.hxx>
62 #include <tools/diagnose_ex.h>
63 #include <basegfx/matrix/b2dhommatrix.hxx>
64 #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
65 
66 #include <boost/bind.hpp>
67 
68 /*
69 
70 Form controls (more precise: UNO Controls) in the drawing layer are ... prone to breakage, since they have some
71 specialities which the drawing layer currently doesn't capture too well. In particular, having a living VCL
72 window as child of the document window, and coupling this Window to a drawing layer object, makes things
73 difficult sometimes.
74 
75 Below is a list of issues which existed in the past. Whenever you change code here, you're encouraged to
76 verify those issues are still fixed. (Whenever you have some additional time, you're encouraged to write
77 an automatic test for one or more of those issues for which this is possible :)
78 
79 http://www.openoffice.org/issues/show_bug.cgi?id=105992
80 zooming documents containg (alive) form controls improperly positions the controls
81 
82 http://www.openoffice.org/issues/show_bug.cgi?id=104362
83 crash when copy a control
84 
85 http://www.openoffice.org/issues/show_bug.cgi?id=104544
86 Gridcontrol duplicated after design view on/off
87 
88 http://www.openoffice.org/issues/show_bug.cgi?id=102089
89 print preview shows control elements with property printable=false
90 
91 http://www.openoffice.org/issues/show_bug.cgi?id=102090
92 problem with setVisible on TextControl
93 
94 http://www.openoffice.org/issues/show_bug.cgi?id=103138
95 loop when insert a control in draw
96 
97 http://www.openoffice.org/issues/show_bug.cgi?id=101398
98 initially-displaying a document with many controls is very slow
99 
100 http://www.openoffice.org/issues/show_bug.cgi?id=72429
101 repaint error in form wizard in bugdoc database
102 
103 http://www.openoffice.org/issues/show_bug.cgi?id=72694
104 form control artifacts when scrolling a text fast
105 
106 
107 issues in the old (Sun-internal) bug tracking system:
108 
109 #110592#
110 form controls being in redlining or in hidden section are visible in alive-mode
111 
112 */
113 
114 //........................................................................
115 namespace sdr { namespace contact {
116 //........................................................................
117 
118     /** === begin UNO using === **/
119     using namespace ::com::sun::star::awt::InvalidateStyle;
120     using ::com::sun::star::uno::Reference;
121     using ::com::sun::star::uno::XInterface;
122     using ::com::sun::star::uno::UNO_QUERY;
123     using ::com::sun::star::uno::UNO_QUERY_THROW;
124     using ::com::sun::star::uno::UNO_SET_THROW;
125     using ::com::sun::star::uno::Exception;
126     using ::com::sun::star::uno::RuntimeException;
127     using ::com::sun::star::awt::XControl;
128     using ::com::sun::star::lang::XMultiServiceFactory;
129     using ::com::sun::star::awt::XControlModel;
130     using ::com::sun::star::awt::XControlContainer;
131     using ::com::sun::star::awt::XWindow;
132     using ::com::sun::star::awt::XWindow2;
133     using ::com::sun::star::awt::XWindowListener;
134     using ::com::sun::star::awt::PosSize::POSSIZE;
135     using ::com::sun::star::awt::XView;
136     using ::com::sun::star::awt::XGraphics;
137     using ::com::sun::star::awt::WindowEvent;
138     using ::com::sun::star::beans::XPropertySet;
139     using ::com::sun::star::beans::XPropertySetInfo;
140     using ::com::sun::star::lang::XComponent;
141     using ::com::sun::star::awt::XWindowPeer;
142     using ::com::sun::star::beans::XPropertyChangeListener;
143     using ::com::sun::star::util::XModeChangeListener;
144     using ::com::sun::star::util::XModeChangeBroadcaster;
145     using ::com::sun::star::util::ModeChangeEvent;
146     using ::com::sun::star::lang::EventObject;
147     using ::com::sun::star::beans::PropertyChangeEvent;
148     using ::com::sun::star::lang::XComponent;
149     using ::com::sun::star::container::XContainerListener;
150     using ::com::sun::star::container::XContainer;
151     using ::com::sun::star::container::ContainerEvent;
152     using ::com::sun::star::uno::Any;
153     /** === end UNO using === **/
154 
155     //====================================================================
156     //= ControlHolder
157     //====================================================================
158     class ControlHolder
159     {
160     private:
161         Reference< XControl >   m_xControl;
162         Reference< XWindow2 >   m_xControlWindow;
163         Reference< XView    >   m_xControlView;
164 
165     public:
ControlHolder()166         ControlHolder()
167             :m_xControl()
168             ,m_xControlWindow()
169             ,m_xControlView()
170         {
171         }
172 
ControlHolder(const Reference<XControl> & _rxControl)173         explicit ControlHolder( const Reference< XControl >& _rxControl )
174             :m_xControl()
175             ,m_xControlWindow()
176             ,m_xControlView()
177         {
178             *this = _rxControl;
179         }
180 
operator =(const Reference<XControl> & _rxControl)181         ControlHolder& operator=( const Reference< XControl >& _rxControl )
182         {
183             clear();
184 
185             m_xControl = _rxControl;
186             if ( m_xControl.is() )
187             {
188                 m_xControlWindow.set( m_xControl, UNO_QUERY );
189                 m_xControlView.set( m_xControl, UNO_QUERY );
190                 if ( !m_xControlWindow.is() || !m_xControlView.is() )
191                 {
192                     OSL_ENSURE( false, "ControlHolder::operator=: invalid XControl, missing required interfaces!" );
193                     clear();
194                 }
195             }
196 
197             return *this;
198         }
199 
200     public:
is() const201         inline  bool    is() const { return m_xControl.is() && m_xControlWindow.is() && m_xControlView.is(); }
clear()202         inline  void    clear() { m_xControl.clear(); m_xControlWindow.clear(); m_xControlView.clear(); }
203 
204         // delegators for the methods of the UNO interfaces
205         // Note all those will crash if called for a NULL object.
isDesignMode() const206         inline bool     isDesignMode() const                        { return m_xControl->isDesignMode();         }
setDesignMode(const bool _bDesign) const207         inline void     setDesignMode( const bool _bDesign ) const  { m_xControl->setDesignMode( _bDesign );     }
isVisible() const208         inline bool     isVisible() const                           { return m_xControlWindow->isVisible();      }
setVisible(const bool _bVisible) const209         inline void     setVisible( const bool _bVisible ) const    { m_xControlWindow->setVisible( _bVisible ); }
210         inline Reference< XControlModel >
getModel() const211                         getModel() const { return m_xControl->getModel(); }
setModel(const Reference<XControlModel> & _m) const212         inline void     setModel( const Reference< XControlModel >& _m ) const { m_xControl->setModel( _m ); }
isTransparent() const213         inline bool     isTransparent() const { return m_xControl->isTransparent(); }
214         inline Reference< XWindowPeer >
getPeer() const215                         getPeer() const { return m_xControl->getPeer(); }
216 
addWindowListener(const Reference<XWindowListener> & _l) const217         inline void     addWindowListener( const Reference< XWindowListener >& _l ) const    { m_xControlWindow->addWindowListener( _l );    }
removeWindowListener(const Reference<XWindowListener> & _l) const218         inline void     removeWindowListener( const Reference< XWindowListener >& _l ) const { m_xControlWindow->removeWindowListener( _l ); }
219                void     setPosSize( const Rectangle& _rPosSize ) const;
220                Rectangle
221                         getPosSize() const;
222                void     setZoom( const ::basegfx::B2DVector& _rScale ) const;
223                ::basegfx::B2DVector
224                         getZoom() const;
225 
setGraphics(const Reference<XGraphics> & _g) const226         inline void     setGraphics( const Reference< XGraphics >& _g ) const { m_xControlView->setGraphics( _g ); }
227         inline Reference< XGraphics >
getGraphics() const228                         getGraphics() const { return m_xControlView->getGraphics(); }
draw(const Point & _rTopLeft) const229         inline void     draw( const Point& _rTopLeft ) const { m_xControlView->draw( _rTopLeft.X(), _rTopLeft.Y() ); }
230 
231                void     invalidate() const;
232 
233     public:
getControl() const234         inline  const Reference< XControl >&    getControl() const  { return m_xControl; }
235     };
236 
237     //--------------------------------------------------------------------
operator ==(const ControlHolder & _rControl,const Reference<XInterface> & _rxCompare)238     bool operator==( const ControlHolder& _rControl, const Reference< XInterface >& _rxCompare )
239     {
240         return _rControl.getControl() == _rxCompare;
241     }
242 
243     //--------------------------------------------------------------------
operator ==(const Reference<XInterface> & _rxCompare,const ControlHolder & _rControl)244     bool operator==( const Reference< XInterface >& _rxCompare, const ControlHolder& _rControl )
245     {
246         return _rxCompare == _rControl.getControl();
247     }
248 
249     //--------------------------------------------------------------------
operator ==(const ControlHolder & _rControl,const Any & _rxCompare)250     bool operator==( const ControlHolder& _rControl, const Any& _rxCompare )
251     {
252         return _rControl == Reference< XInterface >( _rxCompare, UNO_QUERY );
253     }
254 
255     //--------------------------------------------------------------------
operator ==(const Any & _rxCompare,const ControlHolder & _rControl)256     bool operator==( const Any& _rxCompare, const ControlHolder& _rControl )
257     {
258         return Reference< XInterface >( _rxCompare, UNO_QUERY ) == _rControl;
259     }
260 
261     //--------------------------------------------------------------------
setPosSize(const Rectangle & _rPosSize) const262     void ControlHolder::setPosSize( const Rectangle& _rPosSize ) const
263     {
264         // no check whether we're valid, this is the responsibility of the caller
265 
266         // don't call setPosSize when pos/size did not change
267         // #i104181# / 2009-08-18 / frank.schoenheit@sun.com
268         ::Rectangle aCurrentRect( getPosSize() );
269         if ( aCurrentRect != _rPosSize )
270         {
271             m_xControlWindow->setPosSize(
272                 _rPosSize.Left(), _rPosSize.Top(), _rPosSize.GetWidth(), _rPosSize.GetHeight(),
273                 POSSIZE
274             );
275         }
276     }
277 
278     //--------------------------------------------------------------------
getPosSize() const279     ::Rectangle ControlHolder::getPosSize() const
280     {
281         // no check whether we're valid, this is the responsibility of the caller
282         return VCLUnoHelper::ConvertToVCLRect( m_xControlWindow->getPosSize() );
283     }
284 
285     //--------------------------------------------------------------------
setZoom(const::basegfx::B2DVector & _rScale) const286     void ControlHolder::setZoom( const ::basegfx::B2DVector& _rScale ) const
287     {
288         // no check whether we're valid, this is the responsibility of the caller
289         m_xControlView->setZoom( (float)_rScale.getX(), (float)_rScale.getY() );
290     }
291 
292     //--------------------------------------------------------------------
invalidate() const293     void ControlHolder::invalidate() const
294     {
295         Reference< XWindowPeer > xPeer( m_xControl->getPeer() );
296         if ( xPeer.is() )
297         {
298             Window* pWindow = VCLUnoHelper::GetWindow( xPeer );
299             OSL_ENSURE( pWindow, "ControlHolder::invalidate: no implementation access!" );
300             if ( pWindow )
301                 pWindow->Invalidate();
302         }
303     }
304 
305     //--------------------------------------------------------------------
getZoom() const306     ::basegfx::B2DVector ControlHolder::getZoom() const
307     {
308         // no check whether we're valid, this is the responsibility of the caller
309 
310         // Argh. Why does XView have a setZoom only, but not a getZoom?
311         Window* pWindow = VCLUnoHelper::GetWindow( m_xControl->getPeer() );
312         OSL_ENSURE( pWindow, "ControlHolder::getZoom: no implementation access!" );
313 
314         ::basegfx::B2DVector aZoom( 1, 1 );
315         if ( pWindow )
316         {
317             const Fraction& rZoom( pWindow->GetZoom() );
318             aZoom.setX( (double)rZoom );
319             aZoom.setY( (double)rZoom );
320         }
321         return aZoom;
322     }
323 
324     //====================================================================
325     //= UnoControlContactHelper
326     //====================================================================
327     class UnoControlContactHelper
328     {
329     public:
330         /** positions a control, and sets its zoom mode, using a given transformation and output device
331         */
332         static void adjustControlGeometry_throw(
333                 const ControlHolder& _rControl,
334                 const Rectangle& _rLogicBoundingRect,
335                 const ::basegfx::B2DHomMatrix& _rViewTransformation,
336                 const ::basegfx::B2DHomMatrix& _rZoomLevelNormalization
337             );
338 
339         /** disposes the given control
340         */
341         static void disposeAndClearControl_nothrow(
342                 ControlHolder& _rControl
343             );
344 
345     private:
346         UnoControlContactHelper();                                              // never implemented
347         UnoControlContactHelper( const UnoControlContactHelper& );              // never implemented
348         UnoControlContactHelper& operator=( const UnoControlContactHelper& );   // never implemented
349     };
350 
351     //--------------------------------------------------------------------
adjustControlGeometry_throw(const ControlHolder & _rControl,const Rectangle & _rLogicBoundingRect,const basegfx::B2DHomMatrix & _rViewTransformation,const::basegfx::B2DHomMatrix & _rZoomLevelNormalization)352     void UnoControlContactHelper::adjustControlGeometry_throw( const ControlHolder& _rControl, const Rectangle& _rLogicBoundingRect,
353         const basegfx::B2DHomMatrix& _rViewTransformation, const ::basegfx::B2DHomMatrix& _rZoomLevelNormalization )
354     {
355         OSL_PRECOND( _rControl.is(), "UnoControlContactHelper::adjustControlGeometry_throw: illegal control!" );
356         if ( !_rControl.is() )
357             return;
358 
359     #if OSL_DEBUG_LEVEL > 0
360         ::basegfx::B2DTuple aViewScale, aViewTranslate;
361         double nViewRotate(0), nViewShearX(0);
362         _rViewTransformation.decompose( aViewScale, aViewTranslate, nViewRotate, nViewShearX );
363 
364         ::basegfx::B2DTuple aZoomScale, aZoomTranslate;
365         double nZoomRotate(0), nZoomShearX(0);
366         _rZoomLevelNormalization.decompose( aZoomScale, aZoomTranslate, nZoomRotate, nZoomShearX );
367     #endif
368 
369         // transform the logic bound rect, using the view transformation, to pixel coordinates
370         ::basegfx::B2DPoint aTopLeft( _rLogicBoundingRect.Left(), _rLogicBoundingRect.Top() );
371         aTopLeft *= _rViewTransformation;
372         ::basegfx::B2DPoint aBottomRight( _rLogicBoundingRect.Right(), _rLogicBoundingRect.Bottom() );
373         aBottomRight *= _rViewTransformation;
374 
375         const Rectangle aPaintRectPixel( (long)aTopLeft.getX(), (long)aTopLeft.getY(), (long)aBottomRight.getX(), (long)aBottomRight.getY() );
376         _rControl.setPosSize( aPaintRectPixel );
377 
378         // determine the scale from the current view transformation, and the normalization matrix
379         ::basegfx::B2DHomMatrix aObtainResolutionDependentScale( _rViewTransformation * _rZoomLevelNormalization );
380         ::basegfx::B2DVector aScale, aTranslate;
381 		double fRotate, fShearX;
382 		aObtainResolutionDependentScale.decompose( aScale, aTranslate, fRotate, fShearX );
383         _rControl.setZoom( aScale );
384     }
385 
386     //--------------------------------------------------------------------
disposeAndClearControl_nothrow(ControlHolder & _rControl)387     void UnoControlContactHelper::disposeAndClearControl_nothrow( ControlHolder& _rControl )
388     {
389         try
390         {
391             Reference< XComponent > xControlComp( _rControl.getControl(), UNO_QUERY );
392             if ( xControlComp.is() )
393                 xControlComp->dispose();
394         }
395         catch( const Exception& )
396         {
397             DBG_UNHANDLED_EXCEPTION();
398         }
399         _rControl.clear();
400     }
401 
402     //====================================================================
403     //= IPageViewAccess
404     //====================================================================
405     /** interface encapsulating access to an SdrPageView, stripped down to the methods we really need
406      */
407     class IPageViewAccess
408     {
409     public:
410         /** determines whether the view is currently in design mode
411          */
412         virtual bool    isDesignMode() const = 0;
413 
414         /** retrieves the control container for a given output device
415          */
416         virtual Reference< XControlContainer >
417                         getControlContainer( const OutputDevice& _rDevice ) const = 0;
418 
419         /** determines whether a given layer is visible
420          */
421         virtual bool    isLayerVisible( SdrLayerID _nLayerID ) const = 0;
422     };
423 
424     //====================================================================
425     //= SdrPageViewAccess
426     //====================================================================
427     /** is a ->IPageViewAccess implementation based on a real ->SdrPageView instance
428      */
429     class SdrPageViewAccess : public IPageViewAccess
430     {
431         const SdrPageView&  m_rPageView;
432     public:
SdrPageViewAccess(const SdrPageView & _rPageView)433         SdrPageViewAccess( const SdrPageView& _rPageView ) : m_rPageView( _rPageView ) { }
434 
435         virtual bool    isDesignMode() const;
436         virtual Reference< XControlContainer >
437                         getControlContainer( const OutputDevice& _rDevice ) const;
438         virtual bool    isLayerVisible( SdrLayerID _nLayerID ) const;
439     };
440 
441     //--------------------------------------------------------------------
isDesignMode() const442     bool SdrPageViewAccess::isDesignMode() const
443     {
444         return m_rPageView.GetView().IsDesignMode();
445     }
446 
447     //--------------------------------------------------------------------
getControlContainer(const OutputDevice & _rDevice) const448     Reference< XControlContainer > SdrPageViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
449     {
450         Reference< XControlContainer > xControlContainer = m_rPageView.GetControlContainer( _rDevice );
451         DBG_ASSERT( xControlContainer.is() || NULL == m_rPageView.FindPageWindow( ( const_cast< OutputDevice& >( _rDevice ) ) ),
452             "SdrPageViewAccess::getControlContainer: the output device is known, but there is no control container for it?" );
453         return xControlContainer;
454     }
455 
456     //--------------------------------------------------------------------
isLayerVisible(SdrLayerID _nLayerID) const457     bool SdrPageViewAccess::isLayerVisible( SdrLayerID _nLayerID ) const
458     {
459         return m_rPageView.GetVisibleLayers().IsSet( _nLayerID );
460     }
461 
462     //====================================================================
463     //= InvisibleControlViewAccess
464     //====================================================================
465     /** is a ->IPageViewAccess implementation which can be used to create an invisble control for
466         an arbitrary window
467      */
468     class InvisibleControlViewAccess : public IPageViewAccess
469     {
470     private:
471         Reference< XControlContainer >& m_rControlContainer;
472     public:
InvisibleControlViewAccess(Reference<XControlContainer> & _inout_ControlContainer)473         InvisibleControlViewAccess( Reference< XControlContainer >& _inout_ControlContainer )
474             :m_rControlContainer( _inout_ControlContainer )
475         {
476         }
477 
478         virtual bool    isDesignMode() const;
479         virtual Reference< XControlContainer >
480                         getControlContainer( const OutputDevice& _rDevice ) const;
481         virtual bool    isLayerVisible( SdrLayerID _nLayerID ) const;
482     };
483 
484     //--------------------------------------------------------------------
isDesignMode() const485     bool InvisibleControlViewAccess::isDesignMode() const
486     {
487         return true;
488     }
489 
490     //--------------------------------------------------------------------
getControlContainer(const OutputDevice & _rDevice) const491     Reference< XControlContainer > InvisibleControlViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
492     {
493         if ( !m_rControlContainer.is() )
494         {
495             const Window* pWindow = dynamic_cast< const Window* >( &_rDevice );
496             OSL_ENSURE( pWindow, "InvisibleControlViewAccess::getControlContainer: expected to be called for a window only!" );
497             if ( pWindow )
498                 m_rControlContainer = VCLUnoHelper::CreateControlContainer( const_cast< Window* >( pWindow ) );
499         }
500         return m_rControlContainer;
501     }
502 
503     //--------------------------------------------------------------------
isLayerVisible(SdrLayerID) const504     bool InvisibleControlViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
505     {
506         return false;
507     }
508 
509     //====================================================================
510     //= DummyPageViewAccess
511     //====================================================================
512     /** is a ->IPageViewAccess implementation which can be used to create a control for an arbitrary
513         non-Window device
514 
515         The implementation will report the "PageView" as being in design mode, all layers to be visible,
516         and will not return any ControlContainer, so all control container related features (notifications etc)
517         are not available.
518      */
519     class DummyPageViewAccess : public IPageViewAccess
520     {
521     public:
DummyPageViewAccess()522         DummyPageViewAccess()
523         {
524         }
525 
526         virtual bool    isDesignMode() const;
527         virtual Reference< XControlContainer >
528                         getControlContainer( const OutputDevice& _rDevice ) const;
529         virtual bool    isLayerVisible( SdrLayerID _nLayerID ) const;
530     };
531 
532     //--------------------------------------------------------------------
isDesignMode() const533     bool DummyPageViewAccess::isDesignMode() const
534     {
535         return true;
536     }
537 
538     //--------------------------------------------------------------------
getControlContainer(const OutputDevice &) const539     Reference< XControlContainer > DummyPageViewAccess::getControlContainer( const OutputDevice& /*_rDevice*/ ) const
540     {
541         return NULL;
542     }
543 
544     //--------------------------------------------------------------------
isLayerVisible(SdrLayerID) const545     bool DummyPageViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
546     {
547         return true;
548     }
549 
550     //====================================================================
551     //= ViewObjectContactOfUnoControl_Impl
552     //====================================================================
553     typedef     ::cppu::WeakImplHelper4 <   XWindowListener
554                                         ,   XPropertyChangeListener
555                                         ,   XContainerListener
556                                         ,   XModeChangeListener
557                                         >   ViewObjectContactOfUnoControl_Impl_Base;
558 
559     class SVX_DLLPRIVATE ViewObjectContactOfUnoControl_Impl : public ViewObjectContactOfUnoControl_Impl_Base
560     {
561     private:
562         /// the instance whose IMPL we are
563         ViewObjectContactOfUnoControl*  m_pAntiImpl;
564 
565         /// are we currently inside impl_ensureControl_nothrow?
566         bool                            m_bCreatingControl;
567 
568         /** thread safety
569 
570             (not really. ATM only our X* implementations are guarded with this, but not
571             the object as a whole.)
572         */
573         mutable ::osl::Mutex            m_aMutex;
574 
575         /// the control we're responsible for
576         ControlHolder                   m_aControl;
577 
578         /// the ControlContainer where we inserted our control
579         Reference< XContainer >         m_xContainer;
580 
581         /// the output device for which the control was created
582         const OutputDevice*             m_pOutputDeviceForWindow;
583 
584         /// flag indicating whether the control is currently visible
585         bool                            m_bControlIsVisible;
586 
587         /// are we currently listening at a design mode control?
588         bool                            m_bIsDesignModeListening;
589 
590         enum ViewControlMode
591         {
592             eDesign,
593             eAlive,
594             eUnknown
595         };
596         /// is the control currently in design mode?
597         mutable ViewControlMode         m_eControlDesignMode;
598 
599         ::basegfx::B2DHomMatrix         m_aZoomLevelNormalization;
600 
601     public:
602         ViewObjectContactOfUnoControl_Impl( ViewObjectContactOfUnoControl* _pAntiImpl );
603 
604         /** disposes the instance, which is nonfunctional afterwards
605         */
606         void dispose();
607 
608         /** determines whether the instance is disposed
609         */
isDisposed() const610         bool isDisposed() const { return impl_isDisposed_nofail(); }
611 
612         /** determines whether the instance is alive
613         */
isAlive() const614         bool isAlive() const { return !isDisposed(); }
615 
616         /** returns the SdrUnoObject associated with the ViewContact
617 
618             @precond
619                 We're not disposed.
620         */
621         bool    getUnoObject( SdrUnoObj*& _out_rpObject ) const;
622 
623         /** ensures that we have an ->XControl
624 
625             Must only be called if a control is needed when no DisplayInfo is present, yet.
626 
627             For creating a control, an ->OutputDevice is needed, and an ->SdrPageView. Both will be obtained
628             from a ->ObjectContactOfPageView. So, if our (anti-impl's) object contact is not a ->ObjectContactOfPageView,
629             this method fill fail.
630 
631             Failure of this method will be reported via an assertion in a non-product version.
632         */
633         bool    ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL );
634 
635         /** returns our XControl, if it already has been created
636 
637             If you want to ensure that the control exists before accessing it, use ->ensureControl
638         */
639         inline const ControlHolder&
getExistentControl() const640                 getExistentControl() const { return m_aControl; }
641 
642         inline bool
hasControl() const643                 hasControl() const { return m_aControl.is(); }
644 
645         /** positions our XControl according to the geometry settings in the SdrUnoObj, modified by the given
646             transformation, and sets proper zoom settings according to our device
647 
648             @precond
649                 ->m_pOutputDeviceForWindow and ->m_aControl are not <NULL/>
650         */
651         void    positionAndZoomControl( const basegfx::B2DHomMatrix& _rViewTransformation ) const;
652 
653         /** determines whether or not our control is printable
654 
655             Effectively, this method returns the value of the "Printable" property
656             of the control's model. If we have no control, <FALSE/> is returned.
657         */
658         bool    isPrintableControl() const;
659 
660         /** sets the design mode on the control, or at least remembers the flag for the
661             time the control is created
662         */
663         void    setControlDesignMode( bool _bDesignMode ) const;
664 
665         /** determines whether our control is currently visible
666             @nofail
667         */
isControlVisible() const668         bool    isControlVisible() const { return impl_isControlVisible_nofail(); }
669 
670         /// creates an XControl for the given device and SdrUnoObj
671         static bool
672                 createControlForDevice(
673                     IPageViewAccess& _rPageView,
674                     const OutputDevice& _rDevice,
675                     const SdrUnoObj& _rUnoObject,
676                     const basegfx::B2DHomMatrix& _rInitialViewTransformation,
677                     const basegfx::B2DHomMatrix& _rInitialZoomNormalization,
678                     ControlHolder& _out_rControl
679                 );
680 
GuardAccesssdr::contact::ViewObjectContactOfUnoControl_Impl::GuardAccess681         struct GuardAccess { friend class VOCGuard; private: GuardAccess() { } };
getMutex(GuardAccess) const682         ::osl::Mutex&   getMutex( GuardAccess ) const { return m_aMutex; }
683 
684         const ViewContactOfUnoControl&
getViewContact() const685                 getViewContact() const
686         {
687             ENSURE_OR_THROW( !impl_isDisposed_nofail(), "already disposed" );
688             return static_cast< const ViewContactOfUnoControl& >( m_pAntiImpl->GetViewContact() );
689         }
690 
691     protected:
692         ~ViewObjectContactOfUnoControl_Impl();
693 
694         // XEventListener
695         virtual void SAL_CALL disposing( const EventObject& Source ) throw(RuntimeException);
696 
697         // XWindowListener
698         virtual void SAL_CALL windowResized( const WindowEvent& e ) throw(RuntimeException);
699         virtual void SAL_CALL windowMoved( const WindowEvent& e ) throw(RuntimeException);
700         virtual void SAL_CALL windowShown( const EventObject& e ) throw(RuntimeException);
701         virtual void SAL_CALL windowHidden( const EventObject& e ) throw(RuntimeException);
702 
703         // XPropertyChangeListener
704         virtual void SAL_CALL propertyChange( const PropertyChangeEvent& evt ) throw(RuntimeException);
705 
706         // XModeChangeListener
707         virtual void SAL_CALL modeChanged( const ModeChangeEvent& _rSource ) throw (RuntimeException);
708 
709         // XContainerListener
710         virtual void SAL_CALL elementInserted( const ::com::sun::star::container::ContainerEvent& Event ) throw (::com::sun::star::uno::RuntimeException);
711         virtual void SAL_CALL elementRemoved( const ::com::sun::star::container::ContainerEvent& Event ) throw (::com::sun::star::uno::RuntimeException);
712         virtual void SAL_CALL elementReplaced( const ::com::sun::star::container::ContainerEvent& Event ) throw (::com::sun::star::uno::RuntimeException);
713 
714     private:
715         /** retrieves the SdrPageView which our associated SdrPageViewWindow belongs to
716 
717             @param out_rpPageView
718                 a reference to a pointer holding, upon return, the desired SdrPageView
719 
720             @return
721                 <TRUE/> if and only if a ->SdrPageView could be obtained
722 
723             @precond
724                 We really belong to an SdrPageViewWindow. Perhaps (I'm not sure ATM :)
725                 there are instance for which this might not be true, but those instances
726                 should never have a need to call this method.
727 
728             @precond
729                 We're not disposed.
730 
731             @postcond
732                 The method expects success, if it returns with <FALSE/>, this will have been
733                 asserted.
734 
735             @nothrow
736         */
737         bool    impl_getPageView_nothrow( SdrPageView*& _out_rpPageView );
738 
739         /** adjusts the control visibility so it respects its layer's visibility
740 
741             @param _bForce
742                 set to <TRUE/> if you want to force a ->XWindow::setVisible call,
743                 no matter if the control visibility is already correct
744 
745             @precond
746                 ->m_aControl is not <NULL/>
747 
748             @precond
749                 We're not disposed.
750 
751             @precond
752                 We really belong to an SdrPageViewWindow. There are instance for which this
753                 might not be true, but those instances should never have a need to call
754                 this method.
755         */
756         void impl_adjustControlVisibilityToLayerVisibility_throw( bool _bForce );
757 
758         /** adjusts the control visibility so it respects its layer's visibility
759 
760             The control must never be visibile if it's in design mode.
761             In alive mode, it must be visibility if and only it's on a visible layer.
762 
763             @param _rxControl
764                 the control whose visibility is to be adjusted
765 
766             @param _rPageView
767                 provides access to the attributes of the SdrPageView which the control finally belongs to
768 
769             @param _rUnoObject
770                 our SdrUnoObj
771 
772             @param _bIsCurrentlyVisible
773                 determines whether the control is currently visible. Note that this is only a shortcut for
774                 querying _rxControl for the XWindow2 interface, and calling isVisible at this interface.
775                 This shortcut has been chosen since the caller usually already has this information.
776                 If _bForce is <TRUE/>, _bIsCurrentlyVisible is ignored.
777 
778             @param _bForce
779                 set to <TRUE/> if you want to force a ->XWindow::setVisible call,
780                 no matter if the control visibility is already correct
781 
782             @precond
783                 We're not disposed.
784         */
785         static void impl_adjustControlVisibilityToLayerVisibility_throw( const ControlHolder& _rxControl, const SdrUnoObj& _rUnoObject,
786             IPageViewAccess& _rPageView, bool _bIsCurrentlyVisible, bool _bForce );
787 
788         /** starts or stops listening at various aspects of our control
789 
790             @precond
791                 ->m_aControl is not <NULL/>
792         */
793         void impl_switchControlListening_nothrow( bool _bStart );
794 
795         /** starts or stops listening at our control container
796 
797             @precond
798                 ->m_xContainer is not <NULL/>
799         */
800         void impl_switchContainerListening_nothrow( bool _bStart );
801 
802         /** starts or stops listening at the control for design-mode relevant facets
803         */
804         void impl_switchDesignModeListening_nothrow( bool _bStart );
805 
806         /** starts or stops listening for all properties at our control
807 
808             @param _bStart
809                 determines whether to start or to stop listening
810 
811             @precond
812                 ->m_aControl is not <NULL/>
813         */
814         void impl_switchPropertyListening_nothrow( bool _bStart );
815 
816         /** disposes the instance
817             @param _bAlsoDisposeControl
818                 determines whether the XControl should be disposed, too
819         */
820         void impl_dispose_nothrow( bool _bAlsoDisposeControl );
821 
822         /** determines whether the instance is disposed
823             @nofail
824         */
impl_isDisposed_nofail() const825         bool    impl_isDisposed_nofail() const { return m_pAntiImpl == NULL; }
826 
827         /** determines whether our control is currently visible
828             @nofail
829         */
impl_isControlVisible_nofail() const830         bool    impl_isControlVisible_nofail() const { return m_bControlIsVisible; }
831 
832         /** determines whether we are currently a listener at the control for desgin-mode relevant facets
833             @nofail
834         */
impl_isDesignModeListening_nofail() const835         bool    impl_isDesignModeListening_nofail() const { return m_bIsDesignModeListening; }
836 
837         /** determines whether the control currently is in design mode
838 
839             @precond
840                 The design mode must already be known. It is known when we first had access to
841                 an SdrPageView (which carries this flag), or somebody explicitly set it from
842                 outside.
843         */
impl_isControlDesignMode_nothrow() const844         inline bool impl_isControlDesignMode_nothrow() const
845         {
846             DBG_ASSERT( m_eControlDesignMode != eUnknown, "ViewObjectContactOfUnoControl_Impl::impl_isControlDesignMode_nothrow: mode is still unknown!" );
847             return m_eControlDesignMode == eDesign;
848         }
849 
850         /** ensures that we have a control for the given PageView/OutputDevice
851         */
852         bool impl_ensureControl_nothrow(
853                 IPageViewAccess& _rPageView,
854                 const OutputDevice& _rDevice,
855                 const basegfx::B2DHomMatrix& _rInitialViewTransformation
856              );
857 
858         /** retrieves the device which a PageView belongs to, starting from its ObjectContactOfPageView
859 
860             Since #i72752#, the PaintWindow (and thus the OutputDevice) associated with a PageView is not
861             constant over its lifetime. Instead, during some paint operations, the PaintWindow/OutputDevice
862             might be temporarily patched.
863 
864             This method cares for this, by retrieving the very original OutputDevice.
865         */
866         static const OutputDevice& impl_getPageViewOutputDevice_nothrow( const ObjectContactOfPageView& _rObjectContact );
867 
868         const OutputDevice& impl_getOutputDevice_throw() const;
869 
870     private:
871         ViewObjectContactOfUnoControl_Impl();                                                       // never implemented
872         ViewObjectContactOfUnoControl_Impl( const ViewObjectContactOfUnoControl_Impl& );            // never implemented
873         ViewObjectContactOfUnoControl_Impl& operator=( const ViewObjectContactOfUnoControl_Impl& ); // never implemented
874     };
875 
876     //====================================================================
877     //= VOCGuard
878     //====================================================================
879     /** class for guarding a ViewObjectContactOfUnoControl_Impl method
880      */
881     class VOCGuard
882     {
883     private:
884         ::osl::MutexGuard   m_aMutexGuard;
885 
886     public:
VOCGuard(const ViewObjectContactOfUnoControl_Impl & _rImpl)887         VOCGuard( const ViewObjectContactOfUnoControl_Impl& _rImpl )
888             :m_aMutexGuard( _rImpl.getMutex( ViewObjectContactOfUnoControl_Impl::GuardAccess() ) )
889         {
890         }
891     };
892 
893     //====================================================================
894     //= LazyControlCreationPrimitive2D
895     //====================================================================
896     class LazyControlCreationPrimitive2D : public ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D
897     {
898     private:
899         typedef ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D  BufferedDecompositionPrimitive2D;
900 
901     protected:
902         virtual ::drawinglayer::primitive2d::Primitive2DSequence
903             get2DDecomposition(
904                 const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
905             ) const;
906 
907         virtual ::drawinglayer::primitive2d::Primitive2DSequence
908             create2DDecomposition(
909                 const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
910             ) const;
911 
912         virtual ::basegfx::B2DRange
913             getB2DRange(
914                 const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
915             ) const;
916 
917     public:
LazyControlCreationPrimitive2D(const::rtl::Reference<ViewObjectContactOfUnoControl_Impl> & _pVOCImpl)918         LazyControlCreationPrimitive2D( const ::rtl::Reference< ViewObjectContactOfUnoControl_Impl >& _pVOCImpl )
919             :m_pVOCImpl( _pVOCImpl )
920         {
921             ENSURE_OR_THROW( m_pVOCImpl.is(), "Illegal argument." );
922             getTransformation( m_pVOCImpl->getViewContact(), m_aTransformation );
923         }
924 
925         virtual bool operator==(const BasePrimitive2D& rPrimitive) const;
926 
927         // declare unique ID for this primitive class
928         DeclPrimitrive2DIDBlock()
929 
930         static void getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation );
931 
932     private:
impl_positionAndZoomControl(const::drawinglayer::geometry::ViewInformation2D & _rViewInformation) const933         void impl_positionAndZoomControl( const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
934         {
935             if ( !_rViewInformation.getViewport().isEmpty() )
936                 m_pVOCImpl->positionAndZoomControl( _rViewInformation.getObjectToViewTransformation() );
937         }
938 
939     private:
940         ::rtl::Reference< ViewObjectContactOfUnoControl_Impl >  m_pVOCImpl;
941         /** The geometry is part of the identity of an primitive, so we cannot calculate it on demand
942             (since the data the calculation is based on might have changed then), but need to calc
943             it at construction time, and remember it.
944         */
945         ::basegfx::B2DHomMatrix                                 m_aTransformation;
946     };
947 
948     //====================================================================
949     //= ViewObjectContactOfUnoControl_Impl
950     //====================================================================
DBG_NAME(ViewObjectContactOfUnoControl_Impl)951     DBG_NAME( ViewObjectContactOfUnoControl_Impl )
952     //--------------------------------------------------------------------
953     ViewObjectContactOfUnoControl_Impl::ViewObjectContactOfUnoControl_Impl( ViewObjectContactOfUnoControl* _pAntiImpl )
954         :m_pAntiImpl( _pAntiImpl )
955         ,m_bCreatingControl( false )
956         ,m_pOutputDeviceForWindow( NULL )
957         ,m_bControlIsVisible( false )
958         ,m_bIsDesignModeListening( false )
959         ,m_eControlDesignMode( eUnknown )
960         ,m_aZoomLevelNormalization()
961     {
962         DBG_CTOR( ViewObjectContactOfUnoControl_Impl, NULL );
963         DBG_ASSERT( m_pAntiImpl, "ViewObjectContactOfUnoControl_Impl::ViewObjectContactOfUnoControl_Impl: invalid AntiImpl!" );
964 
965         const OutputDevice& rPageViewDevice( impl_getOutputDevice_throw() );
966         m_aZoomLevelNormalization = rPageViewDevice.GetInverseViewTransformation();
967 
968     #if OSL_DEBUG_LEVEL > 1
969         ::basegfx::B2DVector aScale, aTranslate;
970         double fRotate, fShearX;
971         m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
972     #endif
973 
974         ::basegfx::B2DHomMatrix aScaleNormalization;
975         MapMode aCurrentDeviceMapMode( rPageViewDevice.GetMapMode() );
976         aScaleNormalization.set( 0, 0, (double)aCurrentDeviceMapMode.GetScaleX() );
977         aScaleNormalization.set( 1, 1, (double)aCurrentDeviceMapMode.GetScaleY() );
978         m_aZoomLevelNormalization *= aScaleNormalization;
979 
980     #if OSL_DEBUG_LEVEL > 1
981         m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
982     #endif
983    }
984 
985     //--------------------------------------------------------------------
~ViewObjectContactOfUnoControl_Impl()986     ViewObjectContactOfUnoControl_Impl::~ViewObjectContactOfUnoControl_Impl()
987     {
988         if ( !impl_isDisposed_nofail() )
989         {
990             acquire();
991             dispose();
992         }
993 
994         DBG_DTOR( ViewObjectContactOfUnoControl_Impl, NULL );
995     }
996 
997     //--------------------------------------------------------------------
impl_dispose_nothrow(bool _bAlsoDisposeControl)998     void ViewObjectContactOfUnoControl_Impl::impl_dispose_nothrow( bool _bAlsoDisposeControl )
999     {
1000         if ( impl_isDisposed_nofail() )
1001             return;
1002 
1003         if ( m_aControl.is() )
1004             impl_switchControlListening_nothrow( false );
1005 
1006         if ( m_xContainer.is() )
1007             impl_switchContainerListening_nothrow( false );
1008 
1009         // dispose the control
1010         if ( _bAlsoDisposeControl )
1011             UnoControlContactHelper::disposeAndClearControl_nothrow( m_aControl );
1012 
1013         m_aControl.clear();
1014         m_xContainer.clear();
1015         m_pOutputDeviceForWindow = NULL;
1016         m_bControlIsVisible = false;
1017 
1018         m_pAntiImpl = NULL;
1019     }
1020 
1021     //--------------------------------------------------------------------
dispose()1022     void ViewObjectContactOfUnoControl_Impl::dispose()
1023     {
1024         VOCGuard aGuard( *this );
1025         impl_dispose_nothrow( true );
1026     }
1027 
1028     //--------------------------------------------------------------------
getUnoObject(SdrUnoObj * & _out_rpObject) const1029     bool ViewObjectContactOfUnoControl_Impl::getUnoObject( SdrUnoObj*& _out_rpObject ) const
1030     {
1031         OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::getUnoObject: already disposed()" );
1032         if ( impl_isDisposed_nofail() )
1033             _out_rpObject = NULL;
1034         else
1035         {
1036             _out_rpObject = dynamic_cast< SdrUnoObj* >( m_pAntiImpl->GetViewContact().TryToGetSdrObject() );
1037             DBG_ASSERT( _out_rpObject || !m_pAntiImpl->GetViewContact().TryToGetSdrObject(),
1038                 "ViewObjectContactOfUnoControl_Impl::getUnoObject: invalid SdrObject!" );
1039         }
1040         return ( _out_rpObject != NULL );
1041     }
1042 
1043     //--------------------------------------------------------------------
positionAndZoomControl(const basegfx::B2DHomMatrix & _rViewTransformation) const1044     void ViewObjectContactOfUnoControl_Impl::positionAndZoomControl( const basegfx::B2DHomMatrix& _rViewTransformation ) const
1045     {
1046         OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no output device or no control!" );
1047         if ( !m_aControl.is() )
1048             return;
1049 
1050         try
1051         {
1052             SdrUnoObj* pUnoObject( NULL );
1053             if ( getUnoObject( pUnoObject ) )
1054             {
1055                 UnoControlContactHelper::adjustControlGeometry_throw( m_aControl, pUnoObject->GetLogicRect(), _rViewTransformation, m_aZoomLevelNormalization );
1056             }
1057             else
1058                 OSL_ENSURE( false, "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no SdrUnoObj!" );
1059         }
1060         catch( const Exception& )
1061         {
1062             DBG_UNHANDLED_EXCEPTION();
1063         }
1064     }
1065 
1066     //--------------------------------------------------------------------
ensureControl(const basegfx::B2DHomMatrix * _pInitialViewTransformationOrNULL)1067     bool ViewObjectContactOfUnoControl_Impl::ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL )
1068     {
1069         OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::ensureControl: already disposed()" );
1070         if ( impl_isDisposed_nofail() )
1071             return false;
1072 
1073         ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
1074         if ( pPageViewContact )
1075         {
1076             SdrPageViewAccess aPVAccess( pPageViewContact->GetPageWindow().GetPageView() );
1077             const OutputDevice& rDevice( impl_getPageViewOutputDevice_nothrow( *pPageViewContact ) );
1078             return impl_ensureControl_nothrow(
1079                 aPVAccess,
1080                 rDevice,
1081                 _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
1082             );
1083         }
1084 
1085         DummyPageViewAccess aNoPageView;
1086         const OutputDevice& rDevice( impl_getOutputDevice_throw() );
1087         return impl_ensureControl_nothrow(
1088             aNoPageView,
1089             rDevice,
1090             _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
1091         );
1092     }
1093 
1094     //--------------------------------------------------------------------
impl_getOutputDevice_throw() const1095     const OutputDevice& ViewObjectContactOfUnoControl_Impl::impl_getOutputDevice_throw() const
1096     {
1097         ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
1098         if ( pPageViewContact )
1099         {
1100             // do not use ObjectContact::TryToGetOutputDevice here, it would not care for the PageWindow's
1101             // OriginalPaintWindow
1102             return impl_getPageViewOutputDevice_nothrow( *pPageViewContact );
1103         }
1104 
1105         const OutputDevice* pDevice = m_pAntiImpl->GetObjectContact().TryToGetOutputDevice();
1106         ENSURE_OR_THROW( pDevice, "no output device -> no control" );
1107         return *pDevice;
1108     }
1109 
1110     //--------------------------------------------------------------------
impl_getPageViewOutputDevice_nothrow(const ObjectContactOfPageView & _rObjectContact)1111     const OutputDevice& ViewObjectContactOfUnoControl_Impl::impl_getPageViewOutputDevice_nothrow( const ObjectContactOfPageView& _rObjectContact )
1112     {
1113         // if the PageWindow has a patched PaintWindow, use the original PaintWindow
1114         // this ensures that our control is _not_ re-created just because somebody
1115         // (temporarily) changed the window to paint onto.
1116         // #i72429# / 2007-02-20 / frank.schoenheit@sun.com
1117         SdrPageWindow& rPageWindow( _rObjectContact.GetPageWindow() );
1118         if ( rPageWindow.GetOriginalPaintWindow() )
1119             return rPageWindow.GetOriginalPaintWindow()->GetOutputDevice();
1120 
1121         return rPageWindow.GetPaintWindow().GetOutputDevice();
1122     }
1123 
1124     namespace
1125     {
lcl_resetFlag(bool & rbFlag)1126         static void lcl_resetFlag( bool& rbFlag )
1127         {
1128             rbFlag = false;
1129         }
1130     }
1131 
1132     //--------------------------------------------------------------------
impl_ensureControl_nothrow(IPageViewAccess & _rPageView,const OutputDevice & _rDevice,const basegfx::B2DHomMatrix & _rInitialViewTransformation)1133     bool ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow( IPageViewAccess& _rPageView, const OutputDevice& _rDevice,
1134         const basegfx::B2DHomMatrix& _rInitialViewTransformation )
1135     {
1136         if ( m_bCreatingControl )
1137         {
1138             OSL_ENSURE( false, "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: reentrance is not really good here!" );
1139             // We once had a situation where this was called reentrantly, which lead to all kind of strange effects. All
1140             // those affected the grid control, which is the only control so far which is visible in design mode (and
1141             // not only in alive mode).
1142             // Creating the control triggered an Window::Update on some of its child windows, which triggered a
1143             // Paint on parent of the grid control (e.g. the SwEditWin), which triggered a reentrant call to this method,
1144             // which it is not really prepared for.
1145             //
1146             // /me thinks that re-entrance should be caught on a higher level, i.e. the Drawing Layer should not allow
1147             // reentrant paint requests. For the moment, until /me can discuss this with AW, catch it here.
1148             // 2009-08-27 / #i104544# frank.schoenheit@sun.com
1149             return false;
1150         }
1151 
1152         m_bCreatingControl = true;
1153         ::comphelper::ScopeGuard aGuard( ::boost::bind( lcl_resetFlag, ::boost::ref( m_bCreatingControl ) ) );
1154 
1155         if ( m_aControl.is() )
1156         {
1157             if ( m_pOutputDeviceForWindow == &_rDevice )
1158                 return true;
1159 
1160             // Somebody requested a control for a new device, which means either of
1161             // - our PageView's paint window changed since we were last here
1162             // - we don't belong to a page view, and are simply painted onto different devices
1163             // The first sounds strange (doens't it?), the second means we could perhaps
1164             // optimize this in the future - there is no need to re-create the control every time,
1165             // is it?
1166             // #i74523# / 2007-02-15 / frank.schoenheit@sun.com
1167             if ( m_xContainer.is() )
1168                 impl_switchContainerListening_nothrow( false );
1169             impl_switchControlListening_nothrow( false );
1170             UnoControlContactHelper::disposeAndClearControl_nothrow( m_aControl );
1171         }
1172 
1173         SdrUnoObj* pUnoObject( NULL );
1174         if ( !getUnoObject( pUnoObject ) )
1175             return false;
1176 
1177         ControlHolder aControl;
1178         if ( !createControlForDevice( _rPageView, _rDevice, *pUnoObject, _rInitialViewTransformation, m_aZoomLevelNormalization, aControl ) )
1179             return false;
1180 
1181         m_pOutputDeviceForWindow = &_rDevice;
1182         m_aControl = aControl;
1183         m_xContainer = m_xContainer.query( _rPageView.getControlContainer( _rDevice ) );
1184         DBG_ASSERT( (   m_xContainer.is()                                           // either have a XControlContainer
1185                     ||  (   ( !_rPageView.getControlContainer( _rDevice ).is() )    // or don't have any container,
1186                         &&  ( dynamic_cast< const Window* >( &_rDevice ) == NULL )  // which is allowed for non-Window instances only
1187                         )
1188                     ),
1189             "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: no XContainer at the ControlContainer!" );
1190 
1191         try
1192         {
1193             m_eControlDesignMode = m_aControl.isDesignMode() ? eDesign : eAlive;
1194             m_bControlIsVisible = m_aControl.isVisible();
1195         }
1196         catch( const Exception& )
1197         {
1198             DBG_UNHANDLED_EXCEPTION();
1199         }
1200 
1201         // start listening at all aspects of the control which are interesting to us ...
1202         impl_switchControlListening_nothrow( true );
1203 
1204         // start listening at the control container, in case somebody tampers with our control
1205         if ( m_xContainer.is() )
1206             impl_switchContainerListening_nothrow( true );
1207 
1208         return m_aControl.is();
1209     }
1210 
1211     //--------------------------------------------------------------------
createControlForDevice(IPageViewAccess & _rPageView,const OutputDevice & _rDevice,const SdrUnoObj & _rUnoObject,const basegfx::B2DHomMatrix & _rInitialViewTransformation,const basegfx::B2DHomMatrix & _rInitialZoomNormalization,ControlHolder & _out_rControl)1212     bool ViewObjectContactOfUnoControl_Impl::createControlForDevice( IPageViewAccess& _rPageView,
1213         const OutputDevice& _rDevice, const SdrUnoObj& _rUnoObject, const basegfx::B2DHomMatrix& _rInitialViewTransformation,
1214         const basegfx::B2DHomMatrix& _rInitialZoomNormalization, ControlHolder& _out_rControl )
1215     {
1216         _out_rControl.clear();
1217 
1218         Reference< XControlModel > xControlModel( _rUnoObject.GetUnoControlModel() );
1219         DBG_ASSERT( xControlModel.is(), "ViewObjectContactOfUnoControl_Impl::createControlForDevice: no control model at the SdrUnoObject!?" );
1220         if ( !xControlModel.is() )
1221             return false;
1222 
1223         bool bSuccess = false;
1224         try
1225         {
1226             const ::rtl::OUString sControlServiceName( _rUnoObject.GetUnoControlTypeName() );
1227 
1228             Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory(), UNO_SET_THROW );
1229             _out_rControl = Reference< XControl >( xFactory->createInstance( sControlServiceName ), UNO_QUERY_THROW );
1230 
1231             // knit the model and the control
1232             _out_rControl.setModel( xControlModel );
1233 
1234             // proper geometry
1235             UnoControlContactHelper::adjustControlGeometry_throw(
1236                 _out_rControl,
1237                 _rUnoObject.GetLogicRect(),
1238                 _rInitialViewTransformation,
1239                 _rInitialZoomNormalization
1240             );
1241 
1242             // #107049# set design mode before peer is created,
1243             // this is also needed for accessibility
1244             _out_rControl.setDesignMode( _rPageView.isDesignMode() );
1245 
1246             // adjust the initial visibility according to the visibility of the layer
1247             // 2003-06-03 - #110592# - fs@openoffice.org
1248             impl_adjustControlVisibilityToLayerVisibility_throw( _out_rControl, _rUnoObject, _rPageView, false, true );
1249 
1250             // add the control to the respective control container
1251             // #108327# do this last
1252             Reference< XControlContainer > xControlContainer( _rPageView.getControlContainer( _rDevice ) );
1253             if ( xControlContainer.is() )
1254                 xControlContainer->addControl( sControlServiceName, _out_rControl.getControl() );
1255 
1256             bSuccess = true;
1257         }
1258         catch( const Exception& )
1259         {
1260             DBG_UNHANDLED_EXCEPTION();
1261         }
1262 
1263         if ( !bSuccess )
1264         {
1265             // delete the control which might have been created already
1266             UnoControlContactHelper::disposeAndClearControl_nothrow( _out_rControl );
1267         }
1268 
1269         return _out_rControl.is();
1270     }
1271 
1272     //--------------------------------------------------------------------
impl_getPageView_nothrow(SdrPageView * & _out_rpPageView)1273     bool ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow( SdrPageView*& _out_rpPageView )
1274     {
1275         OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: already disposed!" );
1276 
1277         _out_rpPageView = NULL;
1278         if ( impl_isDisposed_nofail() )
1279             return false;
1280 
1281         ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
1282         if ( pPageViewContact )
1283             _out_rpPageView = &pPageViewContact->GetPageWindow().GetPageView();
1284 
1285         DBG_ASSERT( _out_rpPageView != NULL, "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: this method is expected to always have success!" );
1286         return ( _out_rpPageView != NULL );
1287     }
1288 
1289     //--------------------------------------------------------------------
impl_adjustControlVisibilityToLayerVisibility_throw(bool _bForce)1290     void ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw( bool _bForce )
1291     {
1292         OSL_PRECOND( m_aControl.is(),
1293             "ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw: only valid if we have a control!" );
1294 
1295         SdrPageView* pPageView( NULL );
1296         if ( !impl_getPageView_nothrow( pPageView ) )
1297             return;
1298 
1299         SdrUnoObj* pUnoObject( NULL );
1300         if ( !getUnoObject( pUnoObject ) )
1301             return;
1302 
1303         SdrPageViewAccess aPVAccess( *pPageView );
1304         impl_adjustControlVisibilityToLayerVisibility_throw( m_aControl, *pUnoObject, aPVAccess, impl_isControlVisible_nofail(), _bForce );
1305     }
1306 
1307     //--------------------------------------------------------------------
impl_adjustControlVisibilityToLayerVisibility_throw(const ControlHolder & _rControl,const SdrUnoObj & _rUnoObject,IPageViewAccess & _rPageView,bool _bIsCurrentlyVisible,bool _bForce)1308     void ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw( const ControlHolder& _rControl,
1309         const SdrUnoObj& _rUnoObject, IPageViewAccess& _rPageView, bool _bIsCurrentlyVisible, bool _bForce )
1310     {
1311         // in design mode, there is no problem with the visibility: The XControl is hidden by
1312         // default, and the Drawing Layer will simply not call our paint routine, if we're in
1313         // a hidden layer. So, only alive mode matters.
1314         if ( !_rControl.isDesignMode() )
1315         {
1316             // the layer of our object
1317             SdrLayerID nObjectLayer = _rUnoObject.GetLayer();
1318             // is the object we're residing in visible in this view?
1319             bool bIsObjectVisible = _rUnoObject.IsVisible() && _rPageView.isLayerVisible( nObjectLayer );
1320 
1321             if ( _bForce || ( bIsObjectVisible != _bIsCurrentlyVisible ) )
1322             {
1323                 _rControl.setVisible( bIsObjectVisible );
1324             }
1325         }
1326     }
1327 
1328     //--------------------------------------------------------------------
impl_switchContainerListening_nothrow(bool _bStart)1329     void ViewObjectContactOfUnoControl_Impl::impl_switchContainerListening_nothrow( bool _bStart )
1330     {
1331         OSL_PRECOND( m_xContainer.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchContainerListening_nothrow: no control container!" );
1332         if ( !m_xContainer.is() )
1333             return;
1334 
1335         try
1336         {
1337             if ( _bStart )
1338                 m_xContainer->addContainerListener( this );
1339             else
1340                 m_xContainer->removeContainerListener( this );
1341         }
1342         catch( const Exception& )
1343         {
1344             DBG_UNHANDLED_EXCEPTION();
1345         }
1346     }
1347 
1348     //--------------------------------------------------------------------
impl_switchControlListening_nothrow(bool _bStart)1349     void ViewObjectContactOfUnoControl_Impl::impl_switchControlListening_nothrow( bool _bStart )
1350     {
1351         OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchControlListening_nothrow: invalid control!" );
1352         if ( !m_aControl.is() )
1353             return;
1354 
1355         try
1356         {
1357             // listen for visibility changes
1358             if ( _bStart )
1359                 m_aControl.addWindowListener( this );
1360             else
1361                 m_aControl.removeWindowListener( this );
1362 
1363             // in design mode, listen for some more aspects
1364             impl_switchDesignModeListening_nothrow( impl_isControlDesignMode_nothrow() && _bStart );
1365 
1366             // listen for design mode changes
1367             Reference< XModeChangeBroadcaster > xDesignModeChanges( m_aControl.getControl(), UNO_QUERY_THROW );
1368             if ( _bStart )
1369                 xDesignModeChanges->addModeChangeListener( this );
1370             else
1371                 xDesignModeChanges->removeModeChangeListener( this );
1372         }
1373         catch( const Exception& )
1374         {
1375             DBG_UNHANDLED_EXCEPTION();
1376         }
1377     }
1378 
1379     //--------------------------------------------------------------------
impl_switchDesignModeListening_nothrow(bool _bStart)1380     void ViewObjectContactOfUnoControl_Impl::impl_switchDesignModeListening_nothrow( bool _bStart )
1381     {
1382         if ( impl_isDesignModeListening_nofail() != _bStart )
1383         {
1384             m_bIsDesignModeListening = _bStart;
1385             impl_switchPropertyListening_nothrow( _bStart );
1386         }
1387     }
1388 
1389     //------------------------------------------------------------------------------
impl_switchPropertyListening_nothrow(bool _bStart)1390     void ViewObjectContactOfUnoControl_Impl::impl_switchPropertyListening_nothrow( bool _bStart )
1391     {
1392         OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchPropertyListening_nothrow: no control!" );
1393         if ( !m_aControl.is() )
1394             return;
1395 
1396         try
1397         {
1398             Reference< XPropertySet > xModelProperties( m_aControl.getModel(), UNO_QUERY_THROW );
1399             if ( _bStart )
1400                 xModelProperties->addPropertyChangeListener( ::rtl::OUString(), this );
1401             else
1402                 xModelProperties->removePropertyChangeListener( ::rtl::OUString(), this );
1403         }
1404         catch( const Exception& )
1405         {
1406             DBG_UNHANDLED_EXCEPTION();
1407         }
1408     }
1409 
1410     //--------------------------------------------------------------------
isPrintableControl() const1411     bool ViewObjectContactOfUnoControl_Impl::isPrintableControl() const
1412     {
1413         SdrUnoObj* pUnoObject( NULL );
1414         if ( !getUnoObject( pUnoObject ) )
1415             return false;
1416 
1417         bool bIsPrintable = false;
1418         try
1419         {
1420             Reference< XPropertySet > xModelProperties( pUnoObject->GetUnoControlModel(), UNO_QUERY_THROW );
1421             static const ::rtl::OUString s_sPrintablePropertyName( RTL_CONSTASCII_USTRINGPARAM( "Printable" ) );
1422             OSL_VERIFY( xModelProperties->getPropertyValue( s_sPrintablePropertyName ) >>= bIsPrintable );
1423         }
1424         catch( const Exception& )
1425         {
1426             DBG_UNHANDLED_EXCEPTION();
1427         }
1428         return bIsPrintable;
1429     }
1430 
1431     //--------------------------------------------------------------------
disposing(const EventObject & Source)1432     void SAL_CALL ViewObjectContactOfUnoControl_Impl::disposing( const EventObject& Source ) throw(RuntimeException)
1433     {
1434         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
1435             // some code below - in particular our disposal - might trigger actions which require the
1436             // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
1437             // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
1438             // is the real bug. Toolkit really is infested with solar mutex usage ... :(
1439             // #i82169# / 2007-11-14 / frank.schoenheit@sun.com
1440         VOCGuard aGuard( *this );
1441 
1442         if ( !m_aControl.is() )
1443             return;
1444 
1445         if  (   ( m_aControl            == Source.Source )
1446             ||  ( m_aControl.getModel() == Source.Source )
1447             )
1448         {
1449             // the model or the control is dying ... hmm, not much sense in that we ourself continue
1450             // living
1451             impl_dispose_nothrow( false );
1452             return;
1453         }
1454 
1455         DBG_ASSERT( Source.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::disposing: Who's this?" );
1456     }
1457 
1458     //--------------------------------------------------------------------
windowResized(const WindowEvent &)1459     void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowResized( const WindowEvent& /*e*/ ) throw(RuntimeException)
1460     {
1461         // not interested in
1462     }
1463 
1464     //--------------------------------------------------------------------
windowMoved(const WindowEvent &)1465     void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowMoved( const WindowEvent& /*e*/ ) throw(RuntimeException)
1466     {
1467         // not interested in
1468     }
1469 
1470     //--------------------------------------------------------------------
windowShown(const EventObject &)1471     void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowShown( const EventObject& /*e*/ ) throw(RuntimeException)
1472     {
1473         VOCGuard aGuard( *this );
1474         m_bControlIsVisible = true;
1475     }
1476 
1477     //--------------------------------------------------------------------
windowHidden(const EventObject &)1478     void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowHidden( const EventObject& /*e*/ ) throw(RuntimeException)
1479     {
1480         VOCGuard aGuard( *this );
1481         m_bControlIsVisible = false;
1482     }
1483 
1484     //--------------------------------------------------------------------
propertyChange(const PropertyChangeEvent &)1485     void SAL_CALL ViewObjectContactOfUnoControl_Impl::propertyChange( const PropertyChangeEvent& /*_rEvent*/ ) throw(RuntimeException)
1486     {
1487         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
1488             // (re)painting might require VCL operations, which need the SolarMutex
1489 
1490         OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::propertyChange: already disposed()" );
1491         if ( impl_isDisposed_nofail() )
1492             return;
1493 
1494         VOCGuard aGuard( *this );
1495         DBG_ASSERT( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::propertyChange: " );
1496         if ( !m_aControl.is() )
1497             return;
1498 
1499         // a generic property changed. If we're in design mode, we need to repaint the control
1500         if ( impl_isControlDesignMode_nothrow() )
1501         {
1502             m_pAntiImpl->propertyChange();
1503         }
1504     }
1505 
1506     //--------------------------------------------------------------------
modeChanged(const ModeChangeEvent & _rSource)1507     void SAL_CALL ViewObjectContactOfUnoControl_Impl::modeChanged( const ModeChangeEvent& _rSource ) throw (RuntimeException)
1508     {
1509         VOCGuard aGuard( *this );
1510 
1511         DBG_ASSERT( _rSource.NewMode.equalsAscii( "design" ) || _rSource.NewMode.equalsAscii( "alive" ),
1512             "ViewObjectContactOfUnoControl_Impl::modeChanged: unexpected mode!" );
1513 
1514         m_eControlDesignMode = _rSource.NewMode.equalsAscii( "design" ) ? eDesign : eAlive;
1515 
1516         impl_switchDesignModeListening_nothrow( impl_isControlDesignMode_nothrow() );
1517 
1518         try
1519         {
1520             // if the control is part of a invisible layer, we need to explicitly hide it in alive mode
1521             // 2003-06-03 - #110592# - fs@openoffice.org
1522             impl_adjustControlVisibilityToLayerVisibility_throw( false );
1523         }
1524         catch( const Exception& )
1525         {
1526             DBG_UNHANDLED_EXCEPTION();
1527         }
1528     }
1529 
1530     //--------------------------------------------------------------------
elementInserted(const ContainerEvent &)1531     void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementInserted( const ContainerEvent& /*_Event*/ ) throw (RuntimeException)
1532     {
1533         // not interested in
1534     }
1535 
1536     //--------------------------------------------------------------------
elementRemoved(const ContainerEvent & Event)1537     void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementRemoved( const ContainerEvent& Event ) throw (RuntimeException)
1538     {
1539         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
1540             // some code below - in particular our disposal - might trigger actions which require the
1541             // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
1542             // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
1543             // is the real bug. Toolkit really is infested with solar mutex usage ... :(
1544             // #i82169# / 2007-11-14 / frank.schoenheit@sun.com
1545         VOCGuard aGuard( *this );
1546         DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementRemoved: where did this come from?" );
1547 
1548         if ( m_aControl == Event.Element )
1549             impl_dispose_nothrow( false );
1550     }
1551 
1552     //--------------------------------------------------------------------
elementReplaced(const ContainerEvent & Event)1553     void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementReplaced( const ContainerEvent& Event ) throw (RuntimeException)
1554     {
1555         VOCGuard aGuard( *this );
1556         DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementReplaced: where did this come from?" );
1557 
1558         if ( ! ( m_aControl == Event.ReplacedElement ) )
1559             return;
1560 
1561         Reference< XControl > xNewControl( Event.Element, UNO_QUERY );
1562         DBG_ASSERT( xNewControl.is(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: invalid new control!" );
1563         if ( !xNewControl.is() )
1564             return;
1565 
1566         ENSURE_OR_THROW( m_pOutputDeviceForWindow, "calling this without /me having an output device should be impossible." );
1567 
1568         DBG_ASSERT( xNewControl->getModel() == m_aControl.getModel(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: another model at the new control?" );
1569         // another model should - in the drawing layer - also imply another SdrUnoObj, which
1570         // should also result in new ViewContact, and thus in new ViewObjectContacts
1571 
1572         impl_switchControlListening_nothrow( false );
1573 
1574         ControlHolder aNewControl( xNewControl );
1575         aNewControl.setZoom( m_aControl.getZoom() );
1576         aNewControl.setPosSize( m_aControl.getPosSize() );
1577         aNewControl.setDesignMode( impl_isControlDesignMode_nothrow() );
1578 
1579         m_aControl = xNewControl;
1580         m_bControlIsVisible = m_aControl.isVisible();
1581 
1582         impl_switchControlListening_nothrow( true );
1583 
1584         m_pAntiImpl->onControlChangedOrModified( ViewObjectContactOfUnoControl::ImplAccess() );
1585     }
1586 
1587     //--------------------------------------------------------------------
setControlDesignMode(bool _bDesignMode) const1588     void ViewObjectContactOfUnoControl_Impl::setControlDesignMode( bool _bDesignMode ) const
1589     {
1590         if ( ( m_eControlDesignMode != eUnknown ) && ( _bDesignMode == impl_isControlDesignMode_nothrow() ) )
1591             // nothing to do
1592             return;
1593         m_eControlDesignMode = _bDesignMode ? eDesign : eAlive;
1594 
1595         if ( !m_aControl.is() )
1596             // nothing to do, the setting will be respected as soon as the control
1597             // is created
1598             return;
1599 
1600         try
1601         {
1602             m_aControl.setDesignMode( _bDesignMode );
1603         }
1604         catch( const Exception& )
1605         {
1606             DBG_UNHANDLED_EXCEPTION();
1607         }
1608     }
1609 
1610     //====================================================================
1611     //= LazyControlCreationPrimitive2D
1612     //====================================================================
1613     //--------------------------------------------------------------------
operator ==(const BasePrimitive2D & rPrimitive) const1614     bool LazyControlCreationPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
1615     {
1616         if ( !BufferedDecompositionPrimitive2D::operator==( rPrimitive ) )
1617             return false;
1618 
1619         const LazyControlCreationPrimitive2D* pRHS = dynamic_cast< const LazyControlCreationPrimitive2D* >( &rPrimitive );
1620         if ( !pRHS )
1621             return false;
1622 
1623         if ( m_pVOCImpl != pRHS->m_pVOCImpl )
1624             return false;
1625 
1626         if ( m_aTransformation != pRHS->m_aTransformation )
1627             return false;
1628 
1629         return true;
1630     }
1631 
1632     //--------------------------------------------------------------------
getTransformation(const ViewContactOfUnoControl & _rVOC,::basegfx::B2DHomMatrix & _out_Transformation)1633     void LazyControlCreationPrimitive2D::getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation )
1634     {
1635         // Do use model data directly to create the correct geometry. Do NOT
1636         // use getBoundRect()/getSnapRect() here; tese will use the sequence of
1637         // primitives themselves in the long run.
1638         const Rectangle aSdrGeoData( _rVOC.GetSdrUnoObj().GetGeoRect() );
1639         const basegfx::B2DRange aRange(
1640             aSdrGeoData.Left(),
1641             aSdrGeoData.Top(),
1642             aSdrGeoData.Right(),
1643             aSdrGeoData.Bottom()
1644         );
1645 
1646         _out_Transformation.identity();
1647         _out_Transformation.set( 0, 0, aRange.getWidth() );
1648         _out_Transformation.set( 1, 1, aRange.getHeight() );
1649         _out_Transformation.set( 0, 2, aRange.getMinX() );
1650         _out_Transformation.set( 1, 2, aRange.getMinY() );
1651     }
1652 
1653     //--------------------------------------------------------------------
getB2DRange(const::drawinglayer::geometry::ViewInformation2D &) const1654     ::basegfx::B2DRange LazyControlCreationPrimitive2D::getB2DRange( const ::drawinglayer::geometry::ViewInformation2D& /*rViewInformation*/ ) const
1655     {
1656         ::basegfx::B2DRange aRange( 0.0, 0.0, 1.0, 1.0 );
1657         aRange.transform( m_aTransformation );
1658         return aRange;
1659     }
1660 
1661     //--------------------------------------------------------------------
get2DDecomposition(const::drawinglayer::geometry::ViewInformation2D & _rViewInformation) const1662 	::drawinglayer::primitive2d::Primitive2DSequence LazyControlCreationPrimitive2D::get2DDecomposition( const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
1663     {
1664     #if OSL_DEBUG_LEVEL > 1
1665         ::basegfx::B2DVector aScale, aTranslate;
1666         double fRotate, fShearX;
1667         _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1668     #endif
1669         if ( m_pVOCImpl->hasControl() )
1670             impl_positionAndZoomControl( _rViewInformation );
1671         return BufferedDecompositionPrimitive2D::get2DDecomposition( _rViewInformation );
1672     }
1673 
1674     //--------------------------------------------------------------------
create2DDecomposition(const::drawinglayer::geometry::ViewInformation2D & _rViewInformation) const1675     ::drawinglayer::primitive2d::Primitive2DSequence LazyControlCreationPrimitive2D::create2DDecomposition( const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
1676     {
1677     #if OSL_DEBUG_LEVEL > 1
1678         ::basegfx::B2DVector aScale, aTranslate;
1679 	    double fRotate, fShearX;
1680 	    _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1681     #endif
1682         const bool bHadControl = m_pVOCImpl->getExistentControl().is();
1683 
1684         // force control here to make it a VCL ChildWindow. Will be fetched
1685         // and used below by getExistentControl()
1686         m_pVOCImpl->ensureControl( &_rViewInformation.getObjectToViewTransformation() );
1687         impl_positionAndZoomControl( _rViewInformation );
1688 
1689         // get needed data
1690         const ViewContactOfUnoControl& rViewContactOfUnoControl( m_pVOCImpl->getViewContact() );
1691         Reference< XControlModel > xControlModel( rViewContactOfUnoControl.GetSdrUnoObj().GetUnoControlModel() );
1692         const ControlHolder& rControl( m_pVOCImpl->getExistentControl() );
1693 
1694         if ( !bHadControl && rControl.is() && rControl.isVisible() )
1695             rControl.invalidate();
1696 
1697         if ( !bHadControl && rControl.is() && rControl.isVisible() )
1698             rControl.invalidate();
1699 
1700         // check if we already have an XControl.
1701         if ( !xControlModel.is() || !rControl.is() )
1702             // use the default mechanism. This will create a ControlPrimitive2D without
1703             // handing over a XControl. If not even a XControlModel exists, it will
1704             // create the SdrObject fallback visualisation
1705             return rViewContactOfUnoControl.getViewIndependentPrimitive2DSequence();
1706 
1707         // create a primitive and hand over the existing xControl. This will
1708         // allow the primitive to not need to create another one on demand.
1709         const drawinglayer::primitive2d::Primitive2DReference xRetval( new ::drawinglayer::primitive2d::ControlPrimitive2D(
1710             m_aTransformation, xControlModel, rControl.getControl() ) );
1711 
1712         return drawinglayer::primitive2d::Primitive2DSequence(&xRetval, 1);
1713     }
1714 
1715     //--------------------------------------------------------------------
ImplPrimitrive2DIDBlock(LazyControlCreationPrimitive2D,PRIMITIVE2D_ID_SDRCONTROLPRIMITIVE2D)1716     ImplPrimitrive2DIDBlock( LazyControlCreationPrimitive2D, PRIMITIVE2D_ID_SDRCONTROLPRIMITIVE2D )
1717 
1718     //====================================================================
1719     //= ViewObjectContactOfUnoControl
1720     //====================================================================
1721     DBG_NAME( ViewObjectContactOfUnoControl )
1722     //--------------------------------------------------------------------
1723     ViewObjectContactOfUnoControl::ViewObjectContactOfUnoControl( ObjectContact& _rObjectContact, ViewContactOfUnoControl& _rViewContact )
1724         :ViewObjectContactOfSdrObj( _rObjectContact, _rViewContact )
1725         ,m_pImpl( new ViewObjectContactOfUnoControl_Impl( this ) )
1726     {
1727         DBG_CTOR( ViewObjectContactOfUnoControl, NULL );
1728     }
1729 
1730     //--------------------------------------------------------------------
~ViewObjectContactOfUnoControl()1731     ViewObjectContactOfUnoControl::~ViewObjectContactOfUnoControl()
1732     {
1733         m_pImpl->dispose();
1734         m_pImpl = NULL;
1735 
1736         DBG_DTOR( ViewObjectContactOfUnoControl, NULL );
1737     }
1738 
1739     //--------------------------------------------------------------------
isControlVisible() const1740     bool ViewObjectContactOfUnoControl::isControlVisible() const
1741     {
1742         VOCGuard aGuard( *m_pImpl );
1743         const ControlHolder& rControl( m_pImpl->getExistentControl() );
1744         return rControl.is() && rControl.isVisible();
1745     }
1746 
1747     //--------------------------------------------------------------------
getControl()1748     Reference< XControl > ViewObjectContactOfUnoControl::getControl()
1749     {
1750         VOCGuard aGuard( *m_pImpl );
1751         m_pImpl->ensureControl( NULL );
1752         return m_pImpl->getExistentControl().getControl();
1753     }
1754 
1755     //--------------------------------------------------------------------
getTemporaryControlForWindow(const Window & _rWindow,Reference<XControlContainer> & _inout_ControlContainer,const SdrUnoObj & _rUnoObject)1756     Reference< XControl > ViewObjectContactOfUnoControl::getTemporaryControlForWindow(
1757         const Window& _rWindow, Reference< XControlContainer >& _inout_ControlContainer, const SdrUnoObj& _rUnoObject )
1758     {
1759         ControlHolder aControl;
1760 
1761         InvisibleControlViewAccess aSimulatePageView( _inout_ControlContainer );
1762         OSL_VERIFY( ViewObjectContactOfUnoControl_Impl::createControlForDevice( aSimulatePageView, _rWindow, _rUnoObject,
1763             _rWindow.GetViewTransformation(), _rWindow.GetInverseViewTransformation(), aControl ) );
1764         return aControl.getControl();
1765     }
1766 
1767     //--------------------------------------------------------------------
ensureControlVisibility(bool _bVisible) const1768     void ViewObjectContactOfUnoControl::ensureControlVisibility( bool _bVisible ) const
1769     {
1770         VOCGuard aGuard( *m_pImpl );
1771 
1772         try
1773         {
1774             const ControlHolder& rControl( m_pImpl->getExistentControl() );
1775             if ( !rControl.is() )
1776                 return;
1777 
1778             // only need to care for alive mode
1779             if ( rControl.isDesignMode() )
1780                 return;
1781 
1782             // is the visibility correct?
1783             if ( m_pImpl->isControlVisible() == _bVisible )
1784                 return;
1785 
1786             // no -> adjust it
1787             rControl.setVisible( _bVisible );
1788             DBG_ASSERT( m_pImpl->isControlVisible() == _bVisible, "ViewObjectContactOfUnoControl::ensureControlVisibility: this didn't work!" );
1789                 // now this would mean that either isControlVisible is not reliable,
1790                 // or that showing/hiding the window did not work as intended.
1791         }
1792         catch( const Exception& )
1793         {
1794             DBG_UNHANDLED_EXCEPTION();
1795         }
1796     }
1797 
1798     //--------------------------------------------------------------------
setControlDesignMode(bool _bDesignMode) const1799     void ViewObjectContactOfUnoControl::setControlDesignMode( bool _bDesignMode ) const
1800     {
1801         VOCGuard aGuard( *m_pImpl );
1802         m_pImpl->setControlDesignMode( _bDesignMode );
1803 
1804         if(!_bDesignMode)
1805         {
1806             // when live mode is switched on, a refresh is needed. The edit mode visualisation
1807             // needs to be repainted and the now used VCL-Window needs to be positioned and
1808             // sized. Both is done from the repant refresh.
1809             const_cast< ViewObjectContactOfUnoControl* >(this)->ActionChanged();
1810         }
1811     }
1812 
1813     //--------------------------------------------------------------------
createPrimitive2DSequence(const DisplayInfo &) const1814     drawinglayer::primitive2d::Primitive2DSequence ViewObjectContactOfUnoControl::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/) const
1815     {
1816         if ( m_pImpl->isDisposed() )
1817             // our control already died.
1818             // TODO: Is it worth re-creating the control? Finally, this is a pathological situation, it means some instance
1819             // disposed the control though it doesn't own it. So, /me thinks we should not bother here.
1820             return drawinglayer::primitive2d::Primitive2DSequence();
1821 
1822         if ( GetObjectContact().getViewInformation2D().getViewTransformation().isIdentity() )
1823             // remove this when #i115754# is fixed
1824             return drawinglayer::primitive2d::Primitive2DSequence();
1825 
1826         // ignore existing controls which are in alive mode and manually switched to "invisible"
1827         // #102090# / 2009-06-05 / frank.schoenheit@sun.com
1828         const ControlHolder& rControl( m_pImpl->getExistentControl() );
1829         if ( rControl.is() && !rControl.isDesignMode() && !rControl.isVisible() )
1830             return drawinglayer::primitive2d::Primitive2DSequence();
1831 
1832         ::drawinglayer::primitive2d::Primitive2DReference xPrimitive( new LazyControlCreationPrimitive2D( m_pImpl ) );
1833         return ::drawinglayer::primitive2d::Primitive2DSequence( &xPrimitive, 1 );
1834     }
1835 
1836     //--------------------------------------------------------------------
isPrimitiveVisible(const DisplayInfo & _rDisplayInfo) const1837 	bool ViewObjectContactOfUnoControl::isPrimitiveVisible( const DisplayInfo& _rDisplayInfo ) const
1838 	{
1839         VOCGuard aGuard( *m_pImpl );
1840 
1841         if ( m_pImpl->hasControl() )
1842         {
1843             const ::drawinglayer::geometry::ViewInformation2D& rViewInformation( GetObjectContact().getViewInformation2D() );
1844         #if OSL_DEBUG_LEVEL > 1
1845             ::basegfx::B2DVector aScale, aTranslate;
1846             double fRotate, fShearX;
1847             rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1848         #endif
1849 
1850             if ( !rViewInformation.getViewport().isEmpty() )
1851                 m_pImpl->positionAndZoomControl( rViewInformation.getObjectToViewTransformation() );
1852         }
1853 
1854         return ViewObjectContactOfSdrObj::isPrimitiveVisible( _rDisplayInfo );
1855 	}
1856 
1857     //--------------------------------------------------------------------
propertyChange()1858     void ViewObjectContactOfUnoControl::propertyChange()
1859     {
1860         impl_onControlChangedOrModified();
1861     }
1862 
1863     //--------------------------------------------------------------------
ActionChanged()1864     void ViewObjectContactOfUnoControl::ActionChanged()
1865     {
1866         // call parent
1867         ViewObjectContactOfSdrObj::ActionChanged();
1868         const ControlHolder& rControl(m_pImpl->getExistentControl());
1869 
1870         if(rControl.is() && !rControl.isDesignMode())
1871         {
1872             // #i93180# if layer visibility has changed and control is in live mode, it is necessary
1873             // to correct visibility to make those control vanish on SdrObject LayerID changes
1874             const SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
1875 
1876             if(pSdrPageView)
1877             {
1878 				const SdrObject& rObject = getSdrObject();
1879                 const bool bIsLayerVisible( rObject.IsVisible() && pSdrPageView->GetVisibleLayers().IsSet(rObject.GetLayer()));
1880 
1881                 if(rControl.isVisible() != bIsLayerVisible)
1882                 {
1883                     rControl.setVisible(bIsLayerVisible);
1884                 }
1885             }
1886         }
1887     }
1888 
1889     //--------------------------------------------------------------------
impl_onControlChangedOrModified()1890     void ViewObjectContactOfUnoControl::impl_onControlChangedOrModified()
1891     {
1892         // graphical invalidate at all views
1893         ActionChanged();
1894 
1895         // #i93318# flush Primitive2DSequence to force recreation with updated XControlModel
1896         // since e.g. background color has changed and existing decompositions are possibly no
1897         // longer valid. Unfortunately this is not detected from ControlPrimitive2D::operator==
1898         // since it only has a uno reference to the XControlModel
1899         flushPrimitive2DSequence();
1900     }
1901 
1902     //====================================================================
1903     //= UnoControlPrintOrPreviewContact
1904     //====================================================================
DBG_NAME(UnoControlPrintOrPreviewContact)1905     DBG_NAME( UnoControlPrintOrPreviewContact )
1906     //--------------------------------------------------------------------
1907     UnoControlPrintOrPreviewContact::UnoControlPrintOrPreviewContact( ObjectContactOfPageView& _rObjectContact, ViewContactOfUnoControl& _rViewContact )
1908         :ViewObjectContactOfUnoControl( _rObjectContact, _rViewContact )
1909     {
1910         DBG_CTOR( UnoControlPrintOrPreviewContact, NULL );
1911     }
1912 
1913     //--------------------------------------------------------------------
~UnoControlPrintOrPreviewContact()1914     UnoControlPrintOrPreviewContact::~UnoControlPrintOrPreviewContact()
1915     {
1916         DBG_DTOR( UnoControlPrintOrPreviewContact, NULL );
1917     }
1918 
1919     //--------------------------------------------------------------------
createPrimitive2DSequence(const DisplayInfo & rDisplayInfo) const1920     drawinglayer::primitive2d::Primitive2DSequence UnoControlPrintOrPreviewContact::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo ) const
1921     {
1922         if ( !m_pImpl->isPrintableControl() )
1923             return drawinglayer::primitive2d::Primitive2DSequence();
1924         return ViewObjectContactOfUnoControl::createPrimitive2DSequence( rDisplayInfo );
1925     }
1926 
1927 //........................................................................
1928 } } // namespace sdr::contact
1929 //........................................................................
1930 
1931