xref: /trunk/main/sdext/source/presenter/PresenterPaneBorderManager.cxx (revision 45c5a00162811bd03b87fcb4fe9996782f2b59ec)
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