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