1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sdext.hxx" 26 27 // The body of this file is only used when PresenterWindowManager defines 28 // the preprocessor symbol ENABLE_PANE_RESIZING, which by default is not the 29 // case. 30 #ifdef ENABLE_PANE_RESIZING 31 32 #include "PresenterPaneBorderManager.hxx" 33 #include "PresenterController.hxx" 34 #include "PresenterPaintManager.hxx" 35 #include <com/sun/star/awt/PosSize.hpp> 36 #include <com/sun/star/awt/SystemPointer.hpp> 37 #include <com/sun/star/awt/WindowAttribute.hpp> 38 #include <com/sun/star/awt/WindowDescriptor.hpp> 39 #include <com/sun/star/awt/WindowClass.hpp> 40 #include <com/sun/star/awt/XWindow2.hpp> 41 #include <com/sun/star/awt/XWindowPeer.hpp> 42 #include <com/sun/star/lang/XMultiComponentFactory.hpp> 43 #include <cppuhelper/compbase1.hxx> 44 #include <osl/mutex.hxx> 45 #include <boost/weak_ptr.hpp> 46 47 using namespace ::com::sun::star; 48 using namespace ::com::sun::star::uno; 49 using ::rtl::OUString; 50 51 namespace sdext { namespace presenter { 52 53 //===== Service =============================================================== 54 55 56 OUString PresenterPaneBorderManager::getImplementationName_static (void) 57 { 58 return OUString::createFromAscii("com.sun.star.comp.Draw.PresenterPaneBorderManager"); 59 } 60 61 62 63 64 Sequence<OUString> PresenterPaneBorderManager::getSupportedServiceNames_static (void) 65 { 66 static const ::rtl::OUString sServiceName( 67 ::rtl::OUString::createFromAscii("com.sun.star.drawing.PresenterPaneBorderManager")); 68 return Sequence<rtl::OUString>(&sServiceName, 1); 69 } 70 71 72 73 74 Reference<XInterface> PresenterPaneBorderManager::Create (const Reference<uno::XComponentContext>& rxContext) 75 { 76 return Reference<XInterface>(static_cast<XWeak*>( 77 new PresenterPaneBorderManager(rxContext, NULL))); 78 } 79 80 81 82 83 //===== PresenterPaneBorderManager ============================================ 84 85 PresenterPaneBorderManager::PresenterPaneBorderManager ( 86 const Reference<XComponentContext>& rxContext, 87 const ::rtl::Reference<PresenterController>& rpPresenterController) 88 : PresenterPaneBorderManagerInterfaceBase(m_aMutex), 89 mpPresenterController(rpPresenterController), 90 mxComponentContext(rxContext), 91 mxPresenterHelper(), 92 maWindowList(), 93 mnPointerType(), 94 maDragAnchor(), 95 meDragType(Outside), 96 mxOuterDragWindow(), 97 mxInnerDragWindow(), 98 mxPointer() 99 { 100 Reference<lang::XMultiComponentFactory> xFactory (rxContext->getServiceManager()); 101 if (xFactory.is()) 102 { 103 mxPointer = Reference<awt::XPointer>( 104 xFactory->createInstanceWithContext( 105 OUString::createFromAscii("com.sun.star.awt.Pointer"), 106 rxContext), 107 UNO_QUERY_THROW); 108 109 mxPresenterHelper = Reference<drawing::XPresenterHelper>( 110 xFactory->createInstanceWithContext( 111 OUString::createFromAscii("com.sun.star.comp.Draw.PresenterHelper"), 112 rxContext), 113 UNO_QUERY_THROW); 114 } 115 } 116 117 118 119 120 PresenterPaneBorderManager::~PresenterPaneBorderManager (void) 121 { 122 } 123 124 125 126 127 void PresenterPaneBorderManager::disposing (void) 128 { 129 WindowList::const_iterator iDescriptor; 130 for (iDescriptor=maWindowList.begin(); iDescriptor!=maWindowList.end(); ++iDescriptor) 131 { 132 iDescriptor->first->removeMouseListener(this); 133 iDescriptor->first->removeMouseMotionListener(this); 134 } 135 maWindowList.clear(); 136 } 137 138 139 140 141 namespace { 142 const static sal_Int32 mnOutside = 0; 143 const static sal_Int32 mnLeft = 0x01; 144 const static sal_Int32 mnHorizontalCenter = 0x02; 145 const static sal_Int32 mnRight = 0x04; 146 const static sal_Int32 mnTop = 0x10; 147 const static sal_Int32 mnVerticalCenter = 0x20; 148 const static sal_Int32 mnBottom = 0x40; 149 } 150 151 PresenterPaneBorderManager::BorderElement 152 PresenterPaneBorderManager::ClassifyBorderElementUnderMouse ( 153 const Reference<awt::XWindow>& rxOuterWindow, 154 const Reference<awt::XWindow>& rxInnerWindow, 155 const awt::Point aPosition) const 156 { 157 OSL_ASSERT(rxOuterWindow.is()); 158 OSL_ASSERT(rxInnerWindow.is()); 159 160 awt::Rectangle aOuterBox (rxOuterWindow->getPosSize()); 161 const awt::Rectangle aInnerBox (rxInnerWindow->getPosSize()); 162 163 // Coordinates of the pointer position are given in the window 164 // coordinate system. Therefore the upper left corner of the outer box 165 // is the origin. 166 aOuterBox.X = 0; 167 aOuterBox.Y = 0; 168 169 sal_Int32 nCode = 0; 170 171 // Add horizontal classification to nCode. 172 if (aPosition.X < aInnerBox.X) 173 if (aPosition.X < aOuterBox.X) 174 nCode = mnOutside; 175 else 176 nCode = mnLeft; 177 else if (aPosition.X >= aInnerBox.X+aInnerBox.Width) 178 if (aPosition.X >= aOuterBox.X+aOuterBox.Width) 179 nCode = mnOutside; 180 else 181 nCode = mnRight; 182 else 183 nCode = mnHorizontalCenter; 184 185 // Add vertical classification to nCode. 186 if (aPosition.Y < aInnerBox.Y) 187 if (aPosition.Y < aOuterBox.Y) 188 nCode |= mnOutside; 189 else 190 nCode |= mnTop; 191 else if (aPosition.Y >= aInnerBox.Y+aInnerBox.Height) 192 if (aPosition.Y >= aOuterBox.Y+aOuterBox.Height) 193 nCode |= mnOutside; 194 else 195 nCode |= mnBottom; 196 else 197 nCode |= mnVerticalCenter; 198 199 // Translate bits in nCode into BorderElement value. 200 switch (nCode) 201 { 202 case mnOutside | mnOutside: 203 case mnOutside | mnLeft: 204 case mnOutside | mnRight: 205 case mnOutside | mnHorizontalCenter: 206 case mnTop | mnOutside: 207 case mnBottom | mnOutside: 208 case mnVerticalCenter | mnOutside: 209 default: 210 return Outside; 211 212 case mnVerticalCenter | mnHorizontalCenter: 213 return Content; 214 215 case mnTop | mnLeft: 216 return TopLeft; 217 218 case mnTop | mnRight: 219 return TopRight; 220 221 case mnTop | mnHorizontalCenter: 222 return Top; 223 224 case mnBottom | mnLeft: 225 return BottomLeft; 226 227 case mnBottom | mnRight: 228 return BottomRight; 229 230 case mnBottom | mnHorizontalCenter: 231 return Bottom; 232 233 case mnVerticalCenter | mnLeft: 234 return Left; 235 236 case mnVerticalCenter | mnRight: 237 return Right; 238 } 239 } 240 241 242 243 244 //----- XInitialization ------------------------------------------------------- 245 246 void SAL_CALL PresenterPaneBorderManager::initialize (const Sequence<Any>& rArguments) 247 { 248 ThrowIfDisposed(); 249 250 if (rArguments.getLength()%2 == 1 && mxComponentContext.is()) 251 { 252 try 253 { 254 mxParentWindow = Reference<awt::XWindow>(rArguments[0], UNO_QUERY_THROW); 255 256 // Get the outer and inner windows from the argument list and 257 // build a window list of it. 258 for (sal_Int32 nIndex=1; nIndex<rArguments.getLength(); nIndex+=2) 259 { 260 Reference<awt::XWindow> xOuterWindow (rArguments[nIndex], UNO_QUERY_THROW); 261 Reference<awt::XWindow> xInnerWindow (rArguments[nIndex+1], UNO_QUERY_THROW); 262 263 maWindowList.push_back(WindowDescriptor(xOuterWindow,xInnerWindow)); 264 265 xOuterWindow->addMouseListener(this); 266 xOuterWindow->addMouseMotionListener(this); 267 } 268 } 269 catch (RuntimeException&) 270 { 271 PresenterPaneBorderManager::disposing(); 272 throw; 273 } 274 } 275 else 276 { 277 throw RuntimeException( 278 OUString::createFromAscii("PresenterPane: invalid number of arguments"), 279 static_cast<XWeak*>(this)); 280 } 281 } 282 283 284 285 286 //----- XMouseListener -------------------------------------------------------- 287 288 void SAL_CALL PresenterPaneBorderManager::mousePressed (const css::awt::MouseEvent& rEvent) 289 { 290 ThrowIfDisposed(); 291 ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex()); 292 293 // Find window descriptor of the window that has been clicked. 294 WindowList::const_iterator iDescriptor; 295 for (iDescriptor=maWindowList.begin(); iDescriptor!=maWindowList.end(); ++iDescriptor) 296 if (iDescriptor->first == rEvent.Source) 297 break; 298 299 if (iDescriptor != maWindowList.end()) 300 { 301 // Prepare dragging. 302 mxOuterDragWindow = iDescriptor->first; 303 mxInnerDragWindow = iDescriptor->second; 304 OSL_ASSERT(mxOuterDragWindow.is() && mxInnerDragWindow.is()); 305 const awt::Rectangle aOuterBox (mxOuterDragWindow->getPosSize()); 306 maDragAnchor.X = rEvent.X + aOuterBox.X; 307 maDragAnchor.Y = rEvent.Y + aOuterBox.Y; 308 meDragType = ClassifyBorderElementUnderMouse( 309 mxOuterDragWindow, 310 mxInnerDragWindow, 311 awt::Point(rEvent.X, rEvent.Y)); 312 } 313 } 314 315 316 317 318 void SAL_CALL PresenterPaneBorderManager::mouseReleased (const css::awt::MouseEvent& rEvent) 319 { 320 (void)rEvent; 321 ThrowIfDisposed(); 322 ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex()); 323 324 ReleaseMouse(mxOuterDragWindow); 325 meDragType = PresenterPaneBorderManager::Outside; 326 mxOuterDragWindow = NULL; 327 mxInnerDragWindow = NULL; 328 } 329 330 331 332 333 void SAL_CALL PresenterPaneBorderManager::mouseEntered (const css::awt::MouseEvent& rEvent) 334 { 335 (void)rEvent; 336 } 337 338 339 340 341 void SAL_CALL PresenterPaneBorderManager::mouseExited (const css::awt::MouseEvent& rEvent) 342 { 343 (void)rEvent; 344 ThrowIfDisposed(); 345 ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex()); 346 347 ReleaseMouse(mxOuterDragWindow); 348 meDragType = PresenterPaneBorderManager::Outside; 349 mxOuterDragWindow = NULL; 350 mxInnerDragWindow = NULL; 351 } 352 353 354 355 356 //----- XMouseMotionListener -------------------------------------------------- 357 358 void SAL_CALL PresenterPaneBorderManager::mouseMoved (const css::awt::MouseEvent& rEvent) 359 { 360 ThrowIfDisposed(); 361 ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex()); 362 363 WindowList::const_iterator iDescriptor; 364 for (iDescriptor=maWindowList.begin(); iDescriptor!=maWindowList.end(); ++iDescriptor) 365 if (iDescriptor->first == rEvent.Source) 366 break; 367 if (iDescriptor != maWindowList.end()) 368 { 369 // Choose pointer shape according to position in the window border. 370 switch (ClassifyBorderElementUnderMouse( 371 iDescriptor->first, 372 iDescriptor->second, 373 awt::Point(rEvent.X,rEvent.Y))) 374 { 375 case PresenterPaneBorderManager::Top: 376 mnPointerType = awt::SystemPointer::MOVE; 377 break; 378 case PresenterPaneBorderManager::TopLeft: 379 mnPointerType = awt::SystemPointer::WINDOW_NWSIZE; 380 break; 381 case PresenterPaneBorderManager::TopRight: 382 mnPointerType = awt::SystemPointer::WINDOW_NESIZE; 383 break; 384 case PresenterPaneBorderManager::Left: 385 mnPointerType = awt::SystemPointer::WINDOW_WSIZE; 386 break; 387 case PresenterPaneBorderManager::Right: 388 mnPointerType = awt::SystemPointer::WINDOW_ESIZE; 389 break; 390 case PresenterPaneBorderManager::BottomLeft: 391 mnPointerType = awt::SystemPointer::WINDOW_SWSIZE; 392 break; 393 case PresenterPaneBorderManager::BottomRight: 394 mnPointerType = awt::SystemPointer::WINDOW_SESIZE; 395 break; 396 case PresenterPaneBorderManager::Bottom: 397 mnPointerType = awt::SystemPointer::WINDOW_SSIZE; 398 break; 399 400 case PresenterPaneBorderManager::Content: 401 case PresenterPaneBorderManager::Outside: 402 default: 403 mnPointerType = awt::SystemPointer::ARROW; 404 break; 405 } 406 407 // Make the pointer shape visible. 408 Reference<awt::XWindowPeer> xPeer (iDescriptor->first, UNO_QUERY); 409 if (xPeer.is()) 410 { 411 if (mxPointer.is()) 412 mxPointer->setType(mnPointerType); 413 xPeer->setPointer(mxPointer); 414 } 415 } 416 } 417 418 419 420 421 void SAL_CALL PresenterPaneBorderManager::mouseDragged (const css::awt::MouseEvent& rEvent) 422 { 423 ThrowIfDisposed(); 424 ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex()); 425 426 if ( ! mxOuterDragWindow.is()) 427 return; 428 429 CaptureMouse(mxOuterDragWindow); 430 431 const awt::Rectangle aOldBox (mxOuterDragWindow->getPosSize()); 432 const sal_Int32 nX = rEvent.X + aOldBox.X; 433 const sal_Int32 nY = rEvent.Y + aOldBox.Y; 434 const sal_Int32 nDiffX = nX - maDragAnchor.X; 435 const sal_Int32 nDiffY = nY - maDragAnchor.Y; 436 maDragAnchor.X = nX; 437 maDragAnchor.Y = nY; 438 439 const sal_Int32 nOldRight = aOldBox.X + aOldBox.Width; 440 const sal_Int32 nOldBottom = aOldBox.Y + aOldBox.Height; 441 442 awt::Rectangle aBox (aOldBox); 443 sal_Int32 nRight = aBox.X + aBox.Width; 444 sal_Int32 nBottom = aBox.Y + aBox.Height; 445 446 // Update position and/or size according to initial pointer position 447 // inside the window border. 448 switch (meDragType) 449 { 450 case PresenterPaneBorderManager::Top: 451 aBox.X += nDiffX; aBox.Y += nDiffY; 452 nRight += nDiffX; nBottom += nDiffY; 453 break; 454 case PresenterPaneBorderManager::TopLeft: 455 aBox.X += nDiffX; aBox.Y += nDiffY; 456 break; 457 case PresenterPaneBorderManager::TopRight: 458 nRight += nDiffX; aBox.Y += nDiffY; 459 break; 460 case PresenterPaneBorderManager::Left: 461 aBox.X += nDiffX; 462 break; 463 case PresenterPaneBorderManager::Right: 464 nRight += nDiffX; 465 break; 466 case PresenterPaneBorderManager::BottomLeft: 467 aBox.X += nDiffX; nBottom += nDiffY; 468 break; 469 case PresenterPaneBorderManager::BottomRight: 470 nRight += nDiffX; nBottom += nDiffY; 471 break; 472 case PresenterPaneBorderManager::Bottom: 473 nBottom += nDiffY; 474 break; 475 default: break; 476 } 477 478 aBox.Width = nRight - aBox.X; 479 aBox.Height = nBottom - aBox.Y; 480 if (aBox.Width > 20 481 && aBox.Height > 20) 482 { 483 // Set position and/or size of the border window to the new values. 484 sal_Int16 nFlags (0); 485 if (aBox.X != aOldBox.X) 486 nFlags |= awt::PosSize::X; 487 if (aBox.Y != aOldBox.Y) 488 nFlags |= awt::PosSize::Y; 489 if (aBox.Width != aOldBox.Width) 490 nFlags |= awt::PosSize::WIDTH; 491 if (aBox.Height != aOldBox.Height) 492 nFlags |= awt::PosSize::HEIGHT; 493 mxOuterDragWindow->setPosSize(aBox.X, aBox.Y, aBox.Width, aBox.Height, nFlags); 494 495 // Invalidate that is or was covered by the border window before and 496 // after the move/resize. 497 if (mpPresenterController.get() != NULL) 498 { 499 const sal_Int32 nLeft = ::std::min(aOldBox.X,aBox.X); 500 const sal_Int32 nTop = ::std::min(aOldBox.Y,aBox.Y); 501 const sal_Int32 nWidth = ::std::max(nOldRight,nRight) - nLeft; 502 const sal_Int32 nHeight = ::std::max(nOldBottom,nBottom) - nTop; 503 504 OSL_ASSERT(mpPresenterController->GetPaintManager().get()!=NULL); 505 mpPresenterController->GetPaintManager()->Invalidate( 506 mxParentWindow, 507 ::awt::Rectangle(nLeft,nTop,nWidth-1,nHeight-1)); 508 } 509 } 510 } 511 512 513 514 515 //----- lang::XEventListener -------------------------------------------------- 516 517 void SAL_CALL PresenterPaneBorderManager::disposing (const lang::EventObject& rEvent) 518 { 519 WindowList::iterator iDescriptor; 520 for (iDescriptor=maWindowList.begin(); iDescriptor!=maWindowList.end(); ++iDescriptor) 521 if (iDescriptor->first == rEvent.Source) 522 { 523 maWindowList.erase(iDescriptor); 524 break; 525 } 526 } 527 528 529 530 531 //----------------------------------------------------------------------------- 532 533 534 void PresenterPaneBorderManager::CaptureMouse (const Reference<awt::XWindow>& rxWindow) 535 { 536 if (mxPresenterHelper.is()) 537 mxPresenterHelper->captureMouse(rxWindow); 538 } 539 540 541 542 543 void PresenterPaneBorderManager::ReleaseMouse (const Reference<awt::XWindow>& rxWindow) 544 { 545 if (mxPresenterHelper.is()) 546 mxPresenterHelper->releaseMouse(rxWindow); 547 } 548 549 550 551 552 void PresenterPaneBorderManager::ThrowIfDisposed (void) 553 { 554 if (rBHelper.bDisposed || rBHelper.bInDispose) 555 { 556 throw lang::DisposedException ( 557 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 558 "PresenterPaneBorderManager object has already been disposed")), 559 static_cast<uno::XWeak*>(this)); 560 } 561 } 562 563 564 565 566 } } // end of namespace ::sd::presenter 567 568 #endif // ENABLE_PANE_RESIZING 569