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