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