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