bump product version to 5.0.4.1
[LibreOffice.git] / sfx2 / source / dialog / dockwin.cxx
blobf376e52761ad7402fe2e4cb76cda7538e7b5f72e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <svl/eitem.hxx>
21 #include <vcl/decoview.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/timer.hxx>
25 #include <vcl/idle.hxx>
26 #include <rtl/instance.hxx>
27 #include <toolkit/helper/vclunohelper.hxx>
28 #include <comphelper/processfactory.hxx>
30 #include <sfx2/dockwin.hxx>
31 #include <sfx2/bindings.hxx>
32 #include <sfx2/viewfrm.hxx>
33 #include <sfx2/dispatch.hxx>
34 #include "workwin.hxx"
35 #include "splitwin.hxx"
36 #include <sfx2/viewsh.hxx>
37 #include <sfx2/sfxhelp.hxx>
38 #include <sfx2/objsh.hxx>
39 #include <sfx2/msgpool.hxx>
41 #include <com/sun/star/frame/XController.hpp>
42 #include <com/sun/star/lang/XUnoTunnel.hpp>
43 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
44 #include <com/sun/star/awt/XWindow.hpp>
45 #include <com/sun/star/uno/XComponentContext.hpp>
46 #include <com/sun/star/frame/ModuleManager.hpp>
47 #include <com/sun/star/container/XNameAccess.hpp>
48 #include <com/sun/star/ui/theWindowStateConfiguration.hpp>
49 #include <com/sun/star/ui/theWindowContentFactoryManager.hpp>
51 #define MAX_TOGGLEAREA_WIDTH 20
52 #define MAX_TOGGLEAREA_HEIGHT 20
54 using namespace ::com::sun::star;
56 // If you want to change the number you also have to:
57 // - Add new slot ids to sfxsids.hrc
58 // - Add new slots to frmslots.sdi
59 // - Add new slot definitions to sfx.sdi
60 static const int NUM_OF_DOCKINGWINDOWS = 10;
62 class SfxTitleDockingWindow : public SfxDockingWindow
64 VclPtr<vcl::Window> m_pWrappedWindow;
66 public:
67 SfxTitleDockingWindow(
68 SfxBindings* pBindings ,
69 SfxChildWindow* pChildWin ,
70 vcl::Window* pParent ,
71 WinBits nBits);
72 virtual ~SfxTitleDockingWindow();
73 virtual void dispose() SAL_OVERRIDE;
75 vcl::Window* GetWrappedWindow() const { return m_pWrappedWindow; }
76 void SetWrappedWindow(vcl::Window* const pWindow);
78 virtual void StateChanged( StateChangedType nType ) SAL_OVERRIDE;
79 virtual bool Notify( NotifyEvent& rNEvt ) SAL_OVERRIDE;
80 virtual void Resize() SAL_OVERRIDE;
81 virtual void Resizing( Size& rSize ) SAL_OVERRIDE;
82 virtual bool Close() SAL_OVERRIDE;
85 namespace
87 struct WindowState
89 OUString sTitle;
93 static bool lcl_getWindowState( const uno::Reference< container::XNameAccess >& xWindowStateMgr, const OUString& rResourceURL, WindowState& rWindowState )
95 bool bResult = false;
97 try
99 uno::Any a;
100 uno::Sequence< beans::PropertyValue > aWindowState;
101 a = xWindowStateMgr->getByName( rResourceURL );
102 if ( a >>= aWindowState )
104 for ( sal_Int32 n = 0; n < aWindowState.getLength(); n++ )
106 if ( aWindowState[n].Name == "UIName" )
108 aWindowState[n].Value >>= rWindowState.sTitle;
113 bResult = true;
115 catch ( container::NoSuchElementException& )
117 bResult = false;
120 return bResult;
123 SfxDockingWrapper::SfxDockingWrapper( vcl::Window* pParentWnd ,
124 sal_uInt16 nId ,
125 SfxBindings* pBindings ,
126 SfxChildWinInfo* pInfo )
127 : SfxChildWindow( pParentWnd , nId )
129 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
130 const OUString aDockWindowResourceURL( "private:resource/dockingwindow/" );
132 VclPtr<SfxTitleDockingWindow> pTitleDockWindow = VclPtr<SfxTitleDockingWindow>::Create( pBindings, this, pParentWnd,
133 WB_STDDOCKWIN | WB_CLIPCHILDREN | WB_SIZEABLE | WB_3DLOOK | WB_ROLLABLE);
134 pWindow = pTitleDockWindow;
135 eChildAlignment = SfxChildAlignment::NOALIGNMENT;
137 // Use factory manager to retrieve XWindow factory. That can be used to instantiate
138 // the real window factory.
139 uno::Reference< lang::XSingleComponentFactory > xFactoryMgr = ui::theWindowContentFactoryManager::get(xContext);
141 SfxDispatcher* pDispatcher = pBindings->GetDispatcher();
142 uno::Reference< frame::XFrame > xFrame( pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), uno::UNO_QUERY );
143 uno::Sequence< uno::Any > aArgs(2);
144 beans::PropertyValue aPropValue;
145 aPropValue.Name = "Frame";
146 aPropValue.Value = uno::makeAny( xFrame );
147 aArgs[0] <<= aPropValue;
148 aPropValue.Name = "ResourceURL";
150 // create a resource URL from the nId provided by the sfx2
151 OUString aResourceURL( aDockWindowResourceURL );
152 aResourceURL += OUString::number(nId);
153 aPropValue.Value = uno::makeAny( aResourceURL );
154 aArgs[1] <<= aPropValue;
156 uno::Reference< awt::XWindow > xWindow;
159 xWindow = uno::Reference< awt::XWindow>(
160 xFactoryMgr->createInstanceWithArgumentsAndContext( aArgs, xContext ),
161 uno::UNO_QUERY );
163 static uno::WeakReference< frame::XModuleManager2 > m_xModuleManager;
165 uno::Reference< frame::XModuleManager2 > xModuleManager( m_xModuleManager );
166 if ( !xModuleManager.is() )
168 xModuleManager = frame::ModuleManager::create(xContext);
169 m_xModuleManager = xModuleManager;
172 static uno::WeakReference< container::XNameAccess > m_xWindowStateConfiguration;
174 uno::Reference< container::XNameAccess > xWindowStateConfiguration( m_xWindowStateConfiguration );
175 if ( !xWindowStateConfiguration.is() )
177 xWindowStateConfiguration = ui::theWindowStateConfiguration::get( xContext );
178 m_xWindowStateConfiguration = xWindowStateConfiguration;
181 OUString sModuleIdentifier = xModuleManager->identify( xFrame );
183 uno::Reference< container::XNameAccess > xModuleWindowState(
184 xWindowStateConfiguration->getByName( sModuleIdentifier ),
185 uno::UNO_QUERY );
186 if ( xModuleWindowState.is() )
188 WindowState aDockWinState;
189 if ( lcl_getWindowState( xModuleWindowState, aResourceURL, aDockWinState ))
190 pTitleDockWindow->SetText( aDockWinState.sTitle );
193 catch ( beans::UnknownPropertyException& )
196 catch ( uno::RuntimeException& )
199 catch ( uno::Exception& )
203 vcl::Window* pContentWindow = VCLUnoHelper::GetWindow(xWindow);
204 if ( pContentWindow )
205 pContentWindow->SetStyle( pContentWindow->GetStyle() | WB_DIALOGCONTROL | WB_CHILDDLGCTRL );
206 pTitleDockWindow->SetWrappedWindow(pContentWindow);
208 pWindow->SetOutputSizePixel( Size( 270, 240 ) );
210 static_cast<SfxDockingWindow*>( pWindow.get() )->Initialize( pInfo );
211 SetHideNotDelete( true );
214 SfxChildWindow* SfxDockingWrapper::CreateImpl(vcl::Window *pParent, sal_uInt16 nId,
215 SfxBindings *pBindings, SfxChildWinInfo* pInfo)
217 SfxChildWindow *pWin = new SfxDockingWrapper(pParent, nId, pBindings, pInfo);
218 return pWin;
221 void SfxDockingWrapper::RegisterChildWindow (bool bVis, SfxModule *pMod, SfxChildWindowFlags nFlags)
223 // pre-register a couple of docking windows
224 for (int i=0; i < NUM_OF_DOCKINGWINDOWS; i++ )
226 sal_uInt16 nID = sal_uInt16(SID_DOCKWIN_START+i);
227 SfxChildWinFactory *pFact = new SfxChildWinFactory( SfxDockingWrapper::CreateImpl, nID, 0xffff );
228 pFact->aInfo.nFlags |= nFlags;
229 pFact->aInfo.bVisible = bVis;
230 SfxChildWindow::RegisterChildWindow(pMod, pFact);
234 SfxChildWinInfo SfxDockingWrapper::GetInfo() const
236 SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
237 static_cast<SfxDockingWindow*>(GetWindow())->FillInfo( aInfo );
238 return aInfo;
241 SfxTitleDockingWindow::SfxTitleDockingWindow(SfxBindings* pBind, SfxChildWindow* pChildWin,
242 vcl::Window* pParent, WinBits nBits)
243 : SfxDockingWindow(pBind, pChildWin, pParent, nBits)
244 , m_pWrappedWindow(nullptr)
248 SfxTitleDockingWindow::~SfxTitleDockingWindow()
250 disposeOnce();
253 void SfxTitleDockingWindow::dispose()
255 m_pWrappedWindow.disposeAndClear();
256 SfxDockingWindow::dispose();
259 void SfxTitleDockingWindow::SetWrappedWindow( vcl::Window* const pWindow )
261 m_pWrappedWindow = pWindow;
262 if (m_pWrappedWindow)
264 m_pWrappedWindow->SetParent(this);
265 m_pWrappedWindow->SetSizePixel( GetOutputSizePixel() );
266 m_pWrappedWindow->Show();
270 bool SfxTitleDockingWindow::Notify( NotifyEvent& rNEvt )
272 return SfxDockingWindow::Notify( rNEvt );
275 void SfxTitleDockingWindow::StateChanged( StateChangedType nType )
277 if ( nType == StateChangedType::InitShow )
279 vcl::Window* pWindow = GetWrappedWindow();
280 if ( pWindow )
282 pWindow->SetSizePixel( GetOutputSizePixel() );
283 pWindow->Show();
287 SfxDockingWindow::StateChanged(nType);
290 void SfxTitleDockingWindow::Resize()
292 SfxDockingWindow::Resize();
293 if (m_pWrappedWindow)
294 m_pWrappedWindow->SetSizePixel( GetOutputSizePixel() );
297 void SfxTitleDockingWindow::Resizing( Size &rSize )
299 SfxDockingWindow::Resizing( rSize );
300 if (m_pWrappedWindow)
301 m_pWrappedWindow->SetSizePixel( GetOutputSizePixel() );
304 bool SfxTitleDockingWindow::Close()
306 return SfxDockingWindow::Close();
309 namespace
311 struct ChildrenRegisteredMap : public rtl::Static< bool, ChildrenRegisteredMap > {};
314 static bool lcl_checkDockingWindowID( sal_uInt16 nID )
316 if (nID < SID_DOCKWIN_START || nID >= sal_uInt16(SID_DOCKWIN_START+NUM_OF_DOCKINGWINDOWS))
317 return false;
318 else
319 return true;
322 static SfxWorkWindow* lcl_getWorkWindowFromXFrame( const uno::Reference< frame::XFrame >& rFrame )
324 // We need to find the corresponding SfxFrame of our XFrame
325 SfxFrame* pFrame = SfxFrame::GetFirst();
326 SfxFrame* pXFrame = 0;
327 while ( pFrame )
329 uno::Reference< frame::XFrame > xViewShellFrame( pFrame->GetFrameInterface() );
330 if ( xViewShellFrame == rFrame )
332 pXFrame = pFrame;
333 break;
335 else
336 pFrame = SfxFrame::GetNext( *pFrame );
339 // If we have a SfxFrame we can retrieve the work window (Sfx layout manager for docking windows)
340 if ( pXFrame )
341 return pXFrame->GetWorkWindow_Impl();
342 else
343 return NULL;
346 /** Factory function used by the framework layout manager to "create" a docking window with a special name.
347 The string rDockingWindowName MUST BE a valid ID! The ID is pre-defined by a certain slot range located
348 in sfxsids.hrc (currently SID_DOCKWIN_START = 9800).
350 void SAL_CALL SfxDockingWindowFactory( const uno::Reference< frame::XFrame >& rFrame, const OUString& rDockingWindowName )
352 SolarMutexGuard aGuard;
353 sal_uInt16 nID = sal_uInt16(rDockingWindowName.toInt32());
355 // Check the range of the provided ID otherwise nothing will happen
356 if ( lcl_checkDockingWindowID( nID ))
358 SfxWorkWindow* pWorkWindow = lcl_getWorkWindowFromXFrame( rFrame );
359 if ( pWorkWindow )
361 SfxChildWindow* pChildWindow = pWorkWindow->GetChildWindow_Impl(nID);
362 if ( !pChildWindow )
364 // Register window at the workwindow child window list
365 pWorkWindow->SetChildWindow_Impl( nID, true, false );
371 /** Function used by the framework layout manager to determine the visibility state of a docking window with
372 a special name. The string rDockingWindowName MUST BE a valid ID! The ID is pre-defined by a certain slot
373 range located in sfxsids.hrc (currently SID_DOCKWIN_START = 9800).
375 bool SAL_CALL IsDockingWindowVisible( const uno::Reference< frame::XFrame >& rFrame, const OUString& rDockingWindowName )
377 SolarMutexGuard aGuard;
379 sal_uInt16 nID = sal_uInt16(rDockingWindowName.toInt32());
381 // Check the range of the provided ID otherwise nothing will happen
382 if ( lcl_checkDockingWindowID( nID ))
384 SfxWorkWindow* pWorkWindow = lcl_getWorkWindowFromXFrame( rFrame );
385 if ( pWorkWindow )
387 SfxChildWindow* pChildWindow = pWorkWindow->GetChildWindow_Impl(nID);
388 if ( pChildWindow )
389 return true;
393 return false;
396 class SfxDockingWindow_Impl
398 friend class SfxDockingWindow;
400 SfxChildAlignment eLastAlignment;
401 SfxChildAlignment eDockAlignment;
402 bool bConstructed;
403 Size aMinSize;
404 VclPtr<SfxSplitWindow> pSplitWin;
405 bool bSplitable;
406 Idle aMoveIdle;
408 // The following members are only valid in the time from startDocking to
409 // EndDocking:
410 bool bEndDocked;
411 Size aSplitSize;
412 long nHorizontalSize;
413 long nVerticalSize;
414 sal_uInt16 nLine;
415 sal_uInt16 nPos;
416 sal_uInt16 nDockLine;
417 sal_uInt16 nDockPos;
418 bool bNewLine;
419 bool bDockingPrevented;
420 OString aWinState;
422 SfxChildAlignment GetLastAlignment() const
423 { return eLastAlignment; }
424 void SetLastAlignment(SfxChildAlignment eAlign)
425 { eLastAlignment = eAlign; }
426 SfxChildAlignment GetDockAlignment() const
427 { return eDockAlignment; }
428 void SetDockAlignment(SfxChildAlignment eAlign)
429 { eDockAlignment = eAlign; }
432 /* [Description]
434 This virtual method of the class FloatingWindow keeps track of changes in
435 FloatingSize. If this method is overridden by a derived class,
436 then the SfxFloatingWindow: Resize() must also be called.
438 void SfxDockingWindow::Resize()
440 DockingWindow::Resize();
441 Invalidate();
442 if ( pImp && pImp->bConstructed && pMgr )
444 if ( IsFloatingMode() )
446 // start timer for saving window status information
447 pImp->aMoveIdle.Start();
449 else
451 Size aSize( GetSizePixel() );
452 switch ( pImp->GetDockAlignment() )
454 case SfxChildAlignment::LEFT:
455 case SfxChildAlignment::FIRSTLEFT:
456 case SfxChildAlignment::LASTLEFT:
457 case SfxChildAlignment::RIGHT:
458 case SfxChildAlignment::FIRSTRIGHT:
459 case SfxChildAlignment::LASTRIGHT:
460 pImp->nHorizontalSize = aSize.Width();
461 pImp->aSplitSize = aSize;
462 break;
463 case SfxChildAlignment::TOP:
464 case SfxChildAlignment::LOWESTTOP:
465 case SfxChildAlignment::HIGHESTTOP:
466 case SfxChildAlignment::BOTTOM:
467 case SfxChildAlignment::HIGHESTBOTTOM:
468 case SfxChildAlignment::LOWESTBOTTOM:
469 pImp->nVerticalSize = aSize.Height();
470 pImp->aSplitSize = aSize;
471 break;
472 default:
473 break;
479 /* [Description]
481 This virtual method of the class DockingWindow makes it possible to
482 intervene in the switching of the floating mode.
483 If this method is overridden by a derived class,
484 then the SfxDockingWindow::PrepareToggleFloatingMode() must be called
485 afterwards, if not FALSE is returned.
487 bool SfxDockingWindow::PrepareToggleFloatingMode()
489 if (!pImp || !pImp->bConstructed)
490 return true;
492 if ( (Application::IsInModalMode() && IsFloatingMode()) || !pMgr )
493 return false;
495 if ( pImp->bDockingPrevented )
496 return false;
498 if (!IsFloatingMode())
500 // Test, if FloatingMode is permitted.
501 if ( CheckAlignment(GetAlignment(),SfxChildAlignment::NOALIGNMENT) != SfxChildAlignment::NOALIGNMENT )
502 return false;
504 if ( pImp->pSplitWin )
506 // The DockingWindow is inside a SplitWindow and will be teared of.
507 pImp->pSplitWin->RemoveWindow(this/*, sal_False*/);
508 pImp->pSplitWin = 0;
511 else if ( pMgr )
513 pImp->aWinState = GetFloatingWindow()->GetWindowState();
515 // Test if it is allowed to dock,
516 if (CheckAlignment(GetAlignment(),pImp->GetLastAlignment()) == SfxChildAlignment::NOALIGNMENT)
517 return false;
519 // Test, if the Workwindow allows for docking at the moment.
520 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
521 if ( !pWorkWin->IsDockingAllowed() || !pWorkWin->IsInternalDockingAllowed() )
522 return false;
525 return true;
528 /* [Description]
530 This virtual method of the DockingWindow class sets the internal data of
531 the SfxDockingWindow and ensures the correct alignment on the parent window.
532 Through PrepareToggleFloatMode and Initialize it is ensured that
533 pImp-> GetLastAlignment() always delivers an allowed alignment. If this
534 method is overridden by a derived class, then first the
535 SfxDockingWindow::ToggleFloatingMode() must be called.
537 void SfxDockingWindow::ToggleFloatingMode()
539 if ( !pImp || !pImp->bConstructed || !pMgr )
540 return; // No Handler call
542 // Remember old alignment and then switch.
543 // SV has already switched, but the alignment SfxDockingWindow is still
544 // the old one. What I was before?
545 SfxChildAlignment eLastAlign = GetAlignment();
547 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
548 SfxChildIdentifier eIdent = SfxChildIdentifier::DOCKINGWINDOW;
549 if ( pImp->bSplitable )
550 eIdent = SfxChildIdentifier::SPLITWINDOW;
552 if (IsFloatingMode())
554 SetAlignment(SfxChildAlignment::NOALIGNMENT);
555 if ( !pImp->aWinState.isEmpty() )
556 GetFloatingWindow()->SetWindowState( pImp->aWinState );
557 else
558 GetFloatingWindow()->SetOutputSizePixel( GetFloatingSize() );
560 else
562 if (pImp->GetDockAlignment() == eLastAlign)
564 // If ToggleFloatingMode was called, but the DockAlignment still
565 // is unchanged, then this means that it must have been a toggling
566 // through DClick, so use last alignment
567 SetAlignment (pImp->GetLastAlignment());
568 if ( !pImp->bSplitable )
569 SetSizePixel( CalcDockingSize(GetAlignment()) );
571 else
574 // Toggling was triggered by dragging
575 pImp->nLine = pImp->nDockLine;
576 pImp->nPos = pImp->nDockPos;
577 SetAlignment (pImp->GetDockAlignment());
580 if ( pImp->bSplitable )
582 // The DockingWindow is now in a SplitWindow
583 pImp->pSplitWin = pWorkWin->GetSplitWindow_Impl(GetAlignment());
585 // The LastAlignment is still the last docked
586 SfxSplitWindow *pSplit = pWorkWin->GetSplitWindow_Impl(pImp->GetLastAlignment());
588 DBG_ASSERT( pSplit, "LastAlignment is not correct!" );
589 if ( pSplit && pSplit != pImp->pSplitWin )
590 pSplit->ReleaseWindow_Impl(this);
591 if ( pImp->GetDockAlignment() == eLastAlign )
592 pImp->pSplitWin->InsertWindow( this, pImp->aSplitSize );
593 else
594 pImp->pSplitWin->InsertWindow( this, pImp->aSplitSize, pImp->nLine, pImp->nPos, pImp->bNewLine );
595 if ( !pImp->pSplitWin->IsFadeIn() )
596 pImp->pSplitWin->FadeIn();
600 // Keep the old alignment for the next toggle; set it only now due to the
601 // unregister SplitWindow!
602 pImp->SetLastAlignment(eLastAlign);
604 // Reset DockAlignment, if EndDocking is still called
605 pImp->SetDockAlignment(GetAlignment());
607 // Dock or undock SfxChildWindow correctly.
608 pWorkWin->ConfigChild_Impl( eIdent, SfxDockingConfig::TOGGLEFLOATMODE, pMgr->GetType() );
611 /* [Description]
613 This virtual method of the DockingWindow class takes the inner and outer
614 docking rectangle from the parent window. If this method is overridden by
615 a derived class, then SfxDockingWindow:StartDocking() has to be called at
616 the end.
618 void SfxDockingWindow::StartDocking()
620 if ( !pImp || !pImp->bConstructed || !pMgr )
621 return;
622 SfxChildIdentifier eIdent = SfxChildIdentifier::DOCKINGWINDOW;
623 if ( pImp->bSplitable )
624 eIdent = SfxChildIdentifier::SPLITWINDOW;
625 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
626 pWorkWin->ConfigChild_Impl( eIdent, SfxDockingConfig::SETDOCKINGRECTS, pMgr->GetType() );
627 pImp->SetDockAlignment(GetAlignment());
629 if ( pImp->pSplitWin )
631 // Get the current docking data
632 pImp->pSplitWin->GetWindowPos(this, pImp->nLine, pImp->nPos);
633 pImp->nDockLine = pImp->nLine;
634 pImp->nDockPos = pImp->nPos;
635 pImp->bNewLine = false;
639 /* [Description]
641 This virtual method of the DockingWindow class calculates the current
642 tracking rectangle. For this purpose the method CalcAlignment(RPOs, rRect)
643 is used, the behavior can be influenced by the derived classes (see below).
644 This method should if possible not be overwritten.
646 bool SfxDockingWindow::Docking( const Point& rPos, Rectangle& rRect )
648 if ( Application::IsInModalMode() )
649 return true;
651 if ( !pImp || !pImp->bConstructed || !pMgr )
653 rRect.SetSize( Size() );
654 return IsFloatingMode();
657 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
658 if ( pImp->bDockingPrevented || !pWorkWin->IsInternalDockingAllowed() )
659 return false;
661 bool bFloatMode = false;
663 if ( GetOuterRect().IsInside( rPos ) && !IsDockingPrevented() )
665 // Mouse within OuterRect: calculate Alignment and Rectangle
666 SfxChildAlignment eAlign = CalcAlignment(rPos, rRect);
667 if (eAlign == SfxChildAlignment::NOALIGNMENT)
668 bFloatMode = true;
669 pImp->SetDockAlignment(eAlign);
671 else
673 // Mouse is not within OuterRect: must be FloatingWindow
674 // Is this allowed?
675 if (CheckAlignment(pImp->GetDockAlignment(),SfxChildAlignment::NOALIGNMENT) != SfxChildAlignment::NOALIGNMENT)
676 return false;
677 bFloatMode = true;
678 if ( SfxChildAlignment::NOALIGNMENT != pImp->GetDockAlignment() )
680 // Due to a bug the rRect may only be changed when the
681 // alignment is changed!
682 pImp->SetDockAlignment(SfxChildAlignment::NOALIGNMENT);
683 rRect.SetSize(CalcDockingSize(SfxChildAlignment::NOALIGNMENT));
687 if ( !pImp->bSplitable )
689 // For individually docked window the position is set through the
690 // alignment and the docking rectangle.
691 Size aSize = rRect.GetSize();
692 Point aPos;
694 switch ( pImp->GetDockAlignment() )
696 case SfxChildAlignment::LEFT:
697 case SfxChildAlignment::FIRSTLEFT:
698 case SfxChildAlignment::LASTLEFT:
699 aPos = aInnerRect.TopLeft();
700 if ( pImp->GetDockAlignment() == GetAlignment() )
701 aPos.X() -= aSize.Width();
702 break;
704 case SfxChildAlignment::TOP:
705 case SfxChildAlignment::LOWESTTOP:
706 case SfxChildAlignment::HIGHESTTOP:
707 aPos = Point(aOuterRect.Left(), aInnerRect.Top());
708 if ( pImp->GetDockAlignment() == GetAlignment() )
709 aPos.Y() -= aSize.Height();
710 break;
712 case SfxChildAlignment::RIGHT:
713 case SfxChildAlignment::FIRSTRIGHT:
714 case SfxChildAlignment::LASTRIGHT:
715 aPos = Point(aInnerRect.Right() - rRect.GetSize().Width(),
716 aInnerRect.Top());
717 if ( pImp->GetDockAlignment() == GetAlignment() )
718 aPos.X() += aSize.Width();
719 break;
721 case SfxChildAlignment::BOTTOM:
722 case SfxChildAlignment::HIGHESTBOTTOM:
723 case SfxChildAlignment::LOWESTBOTTOM:
724 aPos = Point(aOuterRect.Left(),
725 aInnerRect.Bottom() - rRect.GetSize().Height());
726 if ( pImp->GetDockAlignment() == GetAlignment() )
727 aPos.Y() += aSize.Height();
728 break;
729 default:
730 break;
733 rRect.SetPos(aPos);
736 return bFloatMode;
739 /** Virtual method of the DockingWindow class ensures the correct alignment on
740 the parent window. If this method is overridden by a derived class, then
741 SfxDockingWindow::EndDocking() must be called first.
743 void SfxDockingWindow::EndDocking( const Rectangle& rRect, bool bFloatMode )
745 if ( !pImp || !pImp->bConstructed || IsDockingCanceled() || !pMgr )
746 return;
748 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
749 bool bReArrange = false;
750 if ( pImp->bSplitable )
752 // If the alignment changes and the window is in a docked state in a
753 // SplitWindow, then it must be re-registered. If it is docked again,
754 // PrepareToggleFloatingMode() and ToggleFloatingMode() preform the
755 // re-registered
756 if ( !bFloatMode )
757 bReArrange = true;
760 if ( bReArrange )
762 if ( GetAlignment() != pImp->GetDockAlignment() )
764 // before Show() is called must the reassignment have been made,
765 // therefore the base class can not be called
766 if ( IsFloatingMode() || !pImp->bSplitable )
767 Show( false, SHOW_NOFOCUSCHANGE );
769 // Set the size for toggling.
770 pImp->aSplitSize = rRect.GetSize();
771 if ( IsFloatingMode() )
773 SetFloatingMode( bFloatMode );
774 if ( IsFloatingMode() || !pImp->bSplitable )
775 Show( true, SHOW_NOFOCUSCHANGE );
777 else
779 pImp->pSplitWin->RemoveWindow(this,false);
780 pImp->nLine = pImp->nDockLine;
781 pImp->nPos = pImp->nDockPos;
782 pImp->pSplitWin->ReleaseWindow_Impl(this);
783 pImp->pSplitWin = pWorkWin->GetSplitWindow_Impl(pImp->GetDockAlignment());
784 pImp->pSplitWin->InsertWindow( this, pImp->aSplitSize, pImp->nDockLine, pImp->nDockPos, pImp->bNewLine );
785 if ( !pImp->pSplitWin->IsFadeIn() )
786 pImp->pSplitWin->FadeIn();
789 else if ( pImp->nLine != pImp->nDockLine || pImp->nPos != pImp->nDockPos || pImp->bNewLine )
791 // Moved within Splitwindows
792 if ( pImp->nLine != pImp->nDockLine )
793 pImp->aSplitSize = rRect.GetSize();
794 pImp->pSplitWin->MoveWindow( this, pImp->aSplitSize, pImp->nDockLine, pImp->nDockPos, pImp->bNewLine );
797 else
799 pImp->bEndDocked = true;
800 DockingWindow::EndDocking(rRect, bFloatMode);
801 pImp->bEndDocked = false;
804 SetAlignment( IsFloatingMode() ? SfxChildAlignment::NOALIGNMENT : pImp->GetDockAlignment() );
807 /* [Description]
809 Virtual method of the DockingWindow class. Here, the interactive resize in
810 FloatingMode can be influenced, for example by only allowing for discrete
811 values for width and / or height. The base implementation prevents that the
812 output size is smaller than one set with SetMinOutputSizePixel().
814 void SfxDockingWindow::Resizing( Size& /*rSize*/ )
819 /* [Description]
821 Constructor for the SfxDockingWindow class. A SfxChildWindow will be
822 required because the docking is implemented in Sfx through SfxChildWindows.
824 SfxDockingWindow::SfxDockingWindow( SfxBindings *pBindinx, SfxChildWindow *pCW,
825 vcl::Window* pParent, WinBits nWinBits) :
826 DockingWindow (pParent, nWinBits),
827 pBindings(pBindinx),
828 pMgr(pCW),
829 pImp(NULL)
831 if ( !GetHelpId().isEmpty() )
833 SetUniqueId( GetHelpId() );
834 SetHelpId("");
836 else
838 SfxViewFrame* pViewFrame = pBindings->GetDispatcher()->GetFrame();
839 SfxSlotPool* pSlotPool = pViewFrame->GetObjectShell()->GetModule()->GetSlotPool();
840 const SfxSlot* pSlot = pCW ? pSlotPool->GetSlot( pCW->GetType() ) : NULL;
841 if ( pSlot )
843 OString aCmd("SFXDOCKINGWINDOW_");
844 aCmd += pSlot->GetUnoName();
845 SetUniqueId( aCmd );
849 pImp = new SfxDockingWindow_Impl;
850 pImp->bConstructed = false;
851 pImp->pSplitWin = 0;
852 pImp->bEndDocked = false;
853 pImp->bDockingPrevented = false;
855 pImp->bSplitable = true;
857 // Initially set to default, the alignment is set in the subclass
858 pImp->nLine = pImp->nDockLine = 0;
859 pImp->nPos = pImp->nDockPos = 0;
860 pImp->bNewLine = false;
861 pImp->SetLastAlignment(SfxChildAlignment::NOALIGNMENT);
862 pImp->aMoveIdle.SetPriority(SchedulerPriority::RESIZE);
863 pImp->aMoveIdle.SetIdleHdl(LINK(this,SfxDockingWindow,TimerHdl));
866 /** Constructor for the SfxDockingWindow class. A SfxChildWindow will be
867 required because the docking is implemented in Sfx through SfxChildWindows.
869 SfxDockingWindow::SfxDockingWindow( SfxBindings *pBindinx, SfxChildWindow *pCW,
870 vcl::Window* pParent, const ResId& rResId) :
871 DockingWindow(pParent, rResId),
872 pBindings(pBindinx),
873 pMgr(pCW),
874 pImp(NULL)
876 if ( !GetHelpId().isEmpty() )
878 SetUniqueId( GetHelpId() );
879 SetHelpId("");
881 else
883 SfxViewFrame* pViewFrame = pBindings->GetDispatcher()->GetFrame();
884 SfxSlotPool* pSlotPool = pViewFrame->GetObjectShell()->GetModule()->GetSlotPool();
885 const SfxSlot* pSlot = pCW ? pSlotPool->GetSlot( pCW->GetType() ) : NULL;
886 if ( pSlot )
888 OString aCmd("SFXDOCKINGWINDOW_");
889 aCmd += pSlot->GetUnoName();
890 SetUniqueId( aCmd );
894 pImp = new SfxDockingWindow_Impl;
895 pImp->bConstructed = false;
896 pImp->pSplitWin = 0;
897 pImp->bEndDocked = false;
898 pImp->bDockingPrevented = false;
900 pImp->bSplitable = true;
902 // Initially set to default, the alignment is set in the subclass
903 pImp->nLine = pImp->nDockLine = 0;
904 pImp->nPos = pImp->nDockPos = 0;
905 pImp->bNewLine = false;
906 pImp->SetLastAlignment(SfxChildAlignment::NOALIGNMENT);
907 pImp->aMoveIdle.SetPriority(SchedulerPriority::RESIZE);
908 pImp->aMoveIdle.SetIdleHdl(LINK(this,SfxDockingWindow,TimerHdl));
911 /** Constructor for the SfxDockingWindow class. A SfxChildWindow will be
912 required because the docking is implemented in Sfx through SfxChildWindows.
914 SfxDockingWindow::SfxDockingWindow( SfxBindings *pBindinx, SfxChildWindow *pCW,
915 vcl::Window* pParent, const OString& rID, const OUString& rUIXMLDescription)
916 : DockingWindow(pParent, rID, rUIXMLDescription)
917 , pBindings(pBindinx)
918 , pMgr(pCW)
919 , pImp(NULL)
921 if ( !GetHelpId().isEmpty() )
923 SetUniqueId( GetHelpId() );
924 SetHelpId("");
926 else
928 SfxViewFrame* pViewFrame = pBindings->GetDispatcher()->GetFrame();
929 SfxSlotPool* pSlotPool = pViewFrame->GetObjectShell()->GetModule()->GetSlotPool();
930 const SfxSlot* pSlot = pCW ? pSlotPool->GetSlot( pCW->GetType() ) : NULL;
931 if ( pSlot )
933 OString aCmd("SFXDOCKINGWINDOW_");
934 aCmd += pSlot->GetUnoName();
935 SetUniqueId( aCmd );
939 pImp = new SfxDockingWindow_Impl;
940 pImp->bConstructed = false;
941 pImp->pSplitWin = 0;
942 pImp->bEndDocked = false;
943 pImp->bDockingPrevented = false;
945 pImp->bSplitable = true;
947 // Initially set to default, the alignment is set in the subclass
948 pImp->nLine = pImp->nDockLine = 0;
949 pImp->nPos = pImp->nDockPos = 0;
950 pImp->bNewLine = false;
951 pImp->SetLastAlignment(SfxChildAlignment::NOALIGNMENT);
952 pImp->aMoveIdle.SetPriority(SchedulerPriority::RESIZE);
953 pImp->aMoveIdle.SetIdleHdl(LINK(this,SfxDockingWindow,TimerHdl));
956 /** Initialization of the SfxDockingDialog class via a SfxChildWinInfo.
957 The initialization is done only in a 2nd step after the constructor, this
958 constructor should be called from the derived class or from the
959 SfxChildWindows.
961 void SfxDockingWindow::Initialize(SfxChildWinInfo *pInfo)
963 if ( !pMgr )
965 pImp->SetDockAlignment( SfxChildAlignment::NOALIGNMENT );
966 pImp->bConstructed = true;
967 return;
970 if (pInfo && (pInfo->nFlags & SfxChildWindowFlags::FORCEDOCK))
971 pImp->bDockingPrevented = true;
973 pImp->aSplitSize = GetOutputSizePixel();
974 if ( !GetFloatingSize().Width() )
976 Size aMinSize( GetMinOutputSizePixel() );
977 SetFloatingSize( pImp->aSplitSize );
978 if ( pImp->aSplitSize.Width() < aMinSize.Width() )
979 pImp->aSplitSize.Width() = aMinSize.Width();
980 if ( pImp->aSplitSize.Height() < aMinSize.Height() )
981 pImp->aSplitSize.Height() = aMinSize.Height();
984 bool bVertHorzRead( false );
985 if (pInfo && !pInfo->aExtraString.isEmpty())
987 // get information about alignment, split size and position in SplitWindow
988 OUString aStr;
989 sal_Int32 nPos = pInfo->aExtraString.indexOf("AL:");
990 if ( nPos != -1 )
992 // alignment information
993 sal_Int32 n1 = pInfo->aExtraString.indexOf('(', nPos);
994 if ( n1 != -1 )
996 sal_Int32 n2 = pInfo->aExtraString.indexOf(')', n1);
997 if ( n2 != -1 )
999 // extract alignment information from extrastring
1000 aStr = pInfo->aExtraString.copy(nPos, n2 - nPos + 1);
1001 pInfo->aExtraString = pInfo->aExtraString.replaceAt(nPos, n2 - nPos + 1, "");
1002 aStr = aStr.replaceAt(nPos, n1-nPos+1, "");
1007 if ( !aStr.isEmpty() )
1009 // accept window state only if alignment is also set
1010 pImp->aWinState = pInfo->aWinState;
1012 // check for valid alignment
1013 SfxChildAlignment eLocalAlignment = (SfxChildAlignment) (sal_uInt16) aStr.toInt32();
1014 if ( pImp->bDockingPrevented )
1015 // docking prevented, ignore old configuration and take alignment from default
1016 aStr.clear();
1017 else
1018 SetAlignment( eLocalAlignment );
1020 SfxChildAlignment eAlign = CheckAlignment(GetAlignment(),GetAlignment());
1021 if ( eAlign != GetAlignment() )
1023 OSL_FAIL("Invalid Alignment!");
1024 SetAlignment( eAlign );
1025 aStr.clear();
1028 // get last alignment (for toggeling)
1029 nPos = aStr.indexOf(',');
1030 if ( nPos != -1 )
1032 aStr = aStr.copy(nPos+1);
1033 pImp->SetLastAlignment( (SfxChildAlignment) (sal_uInt16) aStr.toInt32() );
1036 nPos = aStr.indexOf(',');
1037 if ( nPos != -1 )
1039 // get split size and position in SplitWindow
1040 Point aPos;
1041 aStr = aStr.copy(nPos+1);
1042 if ( GetPosSizeFromString( aStr, aPos, pImp->aSplitSize ) )
1044 pImp->nLine = pImp->nDockLine = (sal_uInt16) aPos.X();
1045 pImp->nPos = pImp->nDockPos = (sal_uInt16) aPos.Y();
1046 pImp->nVerticalSize = pImp->aSplitSize.Height();
1047 pImp->nHorizontalSize = pImp->aSplitSize.Width();
1048 if ( GetSplitSizeFromString( aStr, pImp->aSplitSize ))
1049 bVertHorzRead = true;
1053 else {
1054 OSL_FAIL( "Information is missing!" );
1058 if ( !bVertHorzRead )
1060 pImp->nVerticalSize = pImp->aSplitSize.Height();
1061 pImp->nHorizontalSize = pImp->aSplitSize.Width();
1064 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
1065 if ( GetAlignment() != SfxChildAlignment::NOALIGNMENT )
1067 // check if SfxWorkWindow is able to allow docking at its border
1068 if (
1069 !pWorkWin->IsDockingAllowed() ||
1070 !pWorkWin->IsInternalDockingAllowed() ||
1071 ( (GetFloatStyle() & WB_STANDALONE) && Application::IsInModalMode()) )
1073 SetAlignment( SfxChildAlignment::NOALIGNMENT );
1077 // detect floating mode
1078 // toggeling mode will not execute code in handlers, because pImp->bConstructed is not set yet
1079 bool bFloatMode = IsFloatingMode();
1080 if ( bFloatMode != ((GetAlignment() == SfxChildAlignment::NOALIGNMENT)) )
1082 bFloatMode = !bFloatMode;
1083 SetFloatingMode( bFloatMode );
1084 if ( bFloatMode )
1086 if ( !pImp->aWinState.isEmpty() )
1087 GetFloatingWindow()->SetWindowState( pImp->aWinState );
1088 else
1089 GetFloatingWindow()->SetOutputSizePixel( GetFloatingSize() );
1093 if ( IsFloatingMode() )
1095 // validate last alignment
1096 SfxChildAlignment eLastAlign = pImp->GetLastAlignment();
1097 if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
1098 eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::LEFT);
1099 if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
1100 eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::RIGHT);
1101 if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
1102 eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::TOP);
1103 if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
1104 eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::BOTTOM);
1105 pImp->SetLastAlignment(eLastAlign);
1107 else
1109 // docked window must have NOALIGNMENT as last alignment
1110 pImp->SetLastAlignment(SfxChildAlignment::NOALIGNMENT);
1112 if ( pImp->bSplitable )
1114 pImp->pSplitWin = pWorkWin->GetSplitWindow_Impl(GetAlignment());
1115 pImp->pSplitWin->InsertWindow(this, pImp->aSplitSize);
1117 else
1119 //?????? Currently not supported
1120 // Window is docked individually; size is calculated.
1121 // It must therefore be initialized with the DloatingSize if
1122 // someone relies on it that a reasonable size is set
1123 SetSizePixel(GetFloatingSize());
1124 SetSizePixel(CalcDockingSize(GetAlignment()));
1128 // save alignment
1129 pImp->SetDockAlignment( GetAlignment() );
1132 void SfxDockingWindow::Initialize_Impl()
1134 if ( !pMgr )
1136 pImp->bConstructed = true;
1137 return;
1140 FloatingWindow* pFloatWin = GetFloatingWindow();
1141 bool bSet = false;
1142 if ( pFloatWin )
1144 bSet = !pFloatWin->IsDefaultPos();
1146 else
1148 Point aPos = GetFloatingPos();
1149 if ( aPos != Point() )
1150 bSet = true;
1153 if ( !bSet)
1155 SfxViewFrame *pFrame = pBindings->GetDispatcher_Impl()->GetFrame();
1156 vcl::Window* pEditWin = pFrame->GetViewShell()->GetWindow();
1157 Point aPos = pEditWin->OutputToScreenPixel( pEditWin->GetPosPixel() );
1158 aPos = GetParent()->ScreenToOutputPixel( aPos );
1159 SetFloatingPos( aPos );
1162 if ( pFloatWin )
1164 // initialize floating window
1165 if ( pImp->aWinState.isEmpty() )
1166 // window state never set before, get if from defaults
1167 pImp->aWinState = pFloatWin->GetWindowState();
1169 // trick: use VCL method SetWindowState to adjust position and size
1170 pFloatWin->SetWindowState( pImp->aWinState );
1171 Size aSize(pFloatWin->GetSizePixel());
1173 // remember floating size for calculating alignment and tracking rectangle
1174 SetFloatingSize(aSize);
1178 // allow calling of docking handlers
1179 pImp->bConstructed = true;
1182 /** Fills a SfxChildWinInfo with specific data from SfxDockingWindow,
1183 so that it can be written in the INI file. It is assumed that rinfo
1184 receives all other possible relevant data in the ChildWindow class.
1185 Insertions are marked with size and the ZoomIn flag.
1186 If this method is overridden, the base implementation must be called first.
1188 void SfxDockingWindow::FillInfo(SfxChildWinInfo& rInfo) const
1190 if (!pMgr || !pImp)
1191 return;
1193 if (GetFloatingWindow() && pImp->bConstructed)
1194 pImp->aWinState = GetFloatingWindow()->GetWindowState();
1196 rInfo.aWinState = pImp->aWinState;
1197 rInfo.aExtraString = "AL:(";
1198 rInfo.aExtraString += OUString::number((sal_uInt16) GetAlignment());
1199 rInfo.aExtraString += ",";
1200 rInfo.aExtraString += OUString::number ((sal_uInt16) pImp->GetLastAlignment());
1201 if ( pImp->bSplitable )
1203 Point aPos(pImp->nLine, pImp->nPos);
1204 rInfo.aExtraString += ",";
1205 rInfo.aExtraString += OUString::number( aPos.X() );
1206 rInfo.aExtraString += "/";
1207 rInfo.aExtraString += OUString::number( aPos.Y() );
1208 rInfo.aExtraString += "/";
1209 rInfo.aExtraString += OUString::number( pImp->nHorizontalSize );
1210 rInfo.aExtraString += "/";
1211 rInfo.aExtraString += OUString::number( pImp->nVerticalSize );
1212 rInfo.aExtraString += ",";
1213 rInfo.aExtraString += OUString::number( pImp->aSplitSize.Width() );
1214 rInfo.aExtraString += ";";
1215 rInfo.aExtraString += OUString::number( pImp->aSplitSize.Height() );
1218 rInfo.aExtraString += ")";
1221 SfxDockingWindow::~SfxDockingWindow()
1223 disposeOnce();
1226 void SfxDockingWindow::dispose()
1228 ReleaseChildWindow_Impl();
1229 delete pImp; pImp = NULL;
1230 DockingWindow::dispose();
1233 void SfxDockingWindow::ReleaseChildWindow_Impl()
1235 if ( pMgr && pMgr->GetFrame() == pBindings->GetActiveFrame() )
1236 pBindings->SetActiveFrame( NULL );
1238 if ( pMgr && pImp->pSplitWin && pImp->pSplitWin->IsItemValid( GetType() ) )
1239 pImp->pSplitWin->RemoveWindow(this);
1241 pMgr=NULL;
1244 /** This method calculates a resulting alignment for the given mouse position
1245 and tracking rectangle. When changing the alignment it can also be that
1246 the tracking rectangle is changed, so that an altered rectangle is
1247 returned. The user of this class can influence behaviour of this method,
1248 and thus the behavior of his DockinWindow class when docking where the
1249 called virtual method:
1251 SfxDockingWindow :: CalcDockingSize (SfxChildAlignment eAlign)
1253 is overridden (see below).
1255 SfxChildAlignment SfxDockingWindow::CalcAlignment(const Point& rPos, Rectangle& rRect)
1257 // calculate hypothetical sizes for different modes
1258 Size aFloatingSize(CalcDockingSize(SfxChildAlignment::NOALIGNMENT));
1259 Size aVerticalSize(CalcDockingSize(SfxChildAlignment::LEFT));
1260 Size aHorizontalSize(CalcDockingSize(SfxChildAlignment::TOP));
1262 // check if docking is permitted
1263 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
1264 if ( !pWorkWin->IsDockingAllowed() )
1266 rRect.SetSize( aFloatingSize );
1267 return pImp->GetDockAlignment();
1270 // calculate borders to shrink inner area before checking for intersection with tracking rectangle
1271 long nLRBorder, nTBBorder;
1272 if ( pImp->bSplitable )
1274 // take the smaller size of docked and floating mode
1275 Size aSize = pImp->aSplitSize;
1276 if ( GetFloatingSize().Height() < aSize.Height() )
1277 aSize.Height() = GetFloatingSize().Height();
1278 if ( GetFloatingSize().Width() < aSize.Width() )
1279 aSize.Width() = GetFloatingSize().Width();
1281 nLRBorder = aSize.Width();
1282 nTBBorder = aSize.Height();
1284 else
1286 nLRBorder = aVerticalSize.Width();
1287 nTBBorder = aHorizontalSize.Height();
1290 // limit border to predefined constant values
1291 if ( nLRBorder > MAX_TOGGLEAREA_WIDTH )
1292 nLRBorder = MAX_TOGGLEAREA_WIDTH;
1293 if ( nTBBorder > MAX_TOGGLEAREA_WIDTH )
1294 nTBBorder = MAX_TOGGLEAREA_WIDTH;
1296 // shrink area for floating mode if possible
1297 Rectangle aInRect = GetInnerRect();
1298 if ( aInRect.GetWidth() > nLRBorder )
1299 aInRect.Left() += nLRBorder/2;
1300 if ( aInRect.GetWidth() > nLRBorder )
1301 aInRect.Right() -= nLRBorder/2;
1302 if ( aInRect.GetHeight() > nTBBorder )
1303 aInRect.Top() += nTBBorder/2;
1304 if ( aInRect.GetHeight() > nTBBorder )
1305 aInRect.Bottom() -= nTBBorder/2;
1307 // calculate alignment resulting from docking rectangle
1308 bool bBecomesFloating = false;
1309 SfxChildAlignment eDockAlign = pImp->GetDockAlignment();
1310 Rectangle aDockingRect( rRect );
1311 if ( !IsFloatingMode() )
1313 // don't use tracking rectangle for alignment check, because it will be too large
1314 // to get a floating mode as result - switch to floating size
1315 // so the calculation only depends on the position of the rectangle, not the current
1316 // docking state of the window
1317 aDockingRect.SetSize( GetFloatingSize() );
1319 // in this mode docking is never done by keyboard, so it's OK to use the mouse position
1320 aDockingRect.SetPos( pWorkWin->GetWindow()->OutputToScreenPixel( pWorkWin->GetWindow()->GetPointerPosPixel() ) );
1323 Point aPos = aDockingRect.TopLeft();
1324 Rectangle aIntersect = GetOuterRect().GetIntersection( aDockingRect );
1325 if ( aIntersect.IsEmpty() )
1326 // docking rectangle completely outside docking area -> floating mode
1327 bBecomesFloating = true;
1328 else
1330 // create a small test rect around the mouse position and use this one
1331 // instead of the passed rRect to not dock too easily or by accident
1332 Rectangle aSmallDockingRect;
1333 aSmallDockingRect.SetSize( Size( MAX_TOGGLEAREA_WIDTH, MAX_TOGGLEAREA_HEIGHT ) );
1334 Point aNewPos(rPos);
1335 aNewPos.X() -= aSmallDockingRect.GetWidth()/2;
1336 aNewPos.Y() -= aSmallDockingRect.GetHeight()/2;
1337 aSmallDockingRect.SetPos(rPos);
1338 Rectangle aIntersectRect = aInRect.GetIntersection( aSmallDockingRect );
1339 if ( aIntersectRect == aSmallDockingRect )
1340 // docking rectangle completely inside (shrunk) inner area -> floating mode
1341 bBecomesFloating = true;
1344 if ( bBecomesFloating )
1346 eDockAlign = CheckAlignment(pImp->GetDockAlignment(),SfxChildAlignment::NOALIGNMENT);
1348 else
1350 // docking rectangle is in the "sensible area"
1351 Point aInPosTL( aPos.X()-aInRect.Left(), aPos.Y()-aInRect.Top() );
1352 Point aInPosBR( aPos.X()-aInRect.Left() + aDockingRect.GetWidth(), aPos.Y()-aInRect.Top() + aDockingRect.GetHeight() );
1353 Size aInSize = aInRect.GetSize();
1354 bool bNoChange = false;
1356 // check if alignment is still unchanged
1357 switch ( GetAlignment() )
1359 case SfxChildAlignment::LEFT:
1360 case SfxChildAlignment::FIRSTLEFT:
1361 case SfxChildAlignment::LASTLEFT:
1362 if (aInPosTL.X() <= 0)
1364 eDockAlign = GetAlignment();
1365 bNoChange = true;
1367 break;
1368 case SfxChildAlignment::TOP:
1369 case SfxChildAlignment::LOWESTTOP:
1370 case SfxChildAlignment::HIGHESTTOP:
1371 if ( aInPosTL.Y() <= 0)
1373 eDockAlign = GetAlignment();
1374 bNoChange = true;
1376 break;
1377 case SfxChildAlignment::RIGHT:
1378 case SfxChildAlignment::FIRSTRIGHT:
1379 case SfxChildAlignment::LASTRIGHT:
1380 if ( aInPosBR.X() >= aInSize.Width())
1382 eDockAlign = GetAlignment();
1383 bNoChange = true;
1385 break;
1386 case SfxChildAlignment::BOTTOM:
1387 case SfxChildAlignment::LOWESTBOTTOM:
1388 case SfxChildAlignment::HIGHESTBOTTOM:
1389 if ( aInPosBR.Y() >= aInSize.Height())
1391 eDockAlign = GetAlignment();
1392 bNoChange = true;
1394 break;
1395 default:
1396 break;
1399 if ( !bNoChange )
1401 // alignment will change, test alignment according to distance of the docking rectangles edges
1402 bool bForbidden = true;
1403 if ( aInPosTL.X() <= 0)
1405 eDockAlign = CheckAlignment(pImp->GetDockAlignment(),SfxChildAlignment::LEFT);
1406 bForbidden = ( eDockAlign != SfxChildAlignment::LEFT &&
1407 eDockAlign != SfxChildAlignment::FIRSTLEFT &&
1408 eDockAlign != SfxChildAlignment::LASTLEFT );
1411 if ( bForbidden && aInPosTL.Y() <= 0)
1413 eDockAlign = CheckAlignment(pImp->GetDockAlignment(),SfxChildAlignment::TOP);
1414 bForbidden = ( eDockAlign != SfxChildAlignment::TOP &&
1415 eDockAlign != SfxChildAlignment::HIGHESTTOP &&
1416 eDockAlign != SfxChildAlignment::LOWESTTOP );
1419 if ( bForbidden && aInPosBR.X() >= aInSize.Width())
1421 eDockAlign = CheckAlignment(pImp->GetDockAlignment(),SfxChildAlignment::RIGHT);
1422 bForbidden = ( eDockAlign != SfxChildAlignment::RIGHT &&
1423 eDockAlign != SfxChildAlignment::FIRSTRIGHT &&
1424 eDockAlign != SfxChildAlignment::LASTRIGHT );
1427 if ( bForbidden && aInPosBR.Y() >= aInSize.Height())
1429 eDockAlign = CheckAlignment(pImp->GetDockAlignment(),SfxChildAlignment::BOTTOM);
1430 bForbidden = ( eDockAlign != SfxChildAlignment::BOTTOM &&
1431 eDockAlign != SfxChildAlignment::HIGHESTBOTTOM &&
1432 eDockAlign != SfxChildAlignment::LOWESTBOTTOM );
1435 // the calculated alignment was rejected by the window -> take floating mode
1436 if ( bForbidden )
1437 eDockAlign = CheckAlignment(pImp->GetDockAlignment(),SfxChildAlignment::NOALIGNMENT);
1441 if ( eDockAlign == SfxChildAlignment::NOALIGNMENT )
1443 // In the FloatingMode the tracking rectangle will get the floating
1444 // size. Due to a bug the rRect may only be changed when the
1445 // alignment is changed!
1446 if ( eDockAlign != pImp->GetDockAlignment() )
1447 aDockingRect.SetSize( aFloatingSize );
1449 else if ( pImp->bSplitable )
1451 sal_uInt16 nLine, nPos;
1452 SfxSplitWindow *pSplitWin = pWorkWin->GetSplitWindow_Impl(eDockAlign);
1453 aPos = pSplitWin->ScreenToOutputPixel( aPos );
1454 if ( pSplitWin->GetWindowPos( aPos, nLine, nPos ) )
1456 // mouse over splitwindow, get line and position
1457 pImp->nDockLine = nLine;
1458 pImp->nDockPos = nPos;
1459 pImp->bNewLine = false;
1461 else
1463 // mouse touches inner border -> create new line
1464 if ( eDockAlign == GetAlignment() && pImp->pSplitWin &&
1465 pImp->nLine == pImp->pSplitWin->GetLineCount()-1 && pImp->pSplitWin->GetWindowCount(pImp->nLine) == 1 )
1467 // if this window is the only one in the last line, it can't be docked as new line in the same splitwindow
1468 pImp->nDockLine = pImp->nLine;
1469 pImp->nDockPos = pImp->nPos;
1470 pImp->bNewLine = false;
1472 else
1474 // create new line
1475 pImp->nDockLine = pSplitWin->GetLineCount();
1476 pImp->nDockPos = 0;
1477 pImp->bNewLine = true;
1481 bool bChanged = pImp->nLine != pImp->nDockLine || pImp->nPos != pImp->nDockPos || eDockAlign != GetAlignment();
1482 if ( !bChanged && !IsFloatingMode() )
1484 // window only sightly moved, no change of any property
1485 rRect.SetSize( pImp->aSplitSize );
1486 rRect.SetPos( aDockingRect.TopLeft() );
1487 return eDockAlign;
1490 // calculate new size and position
1491 Size aSize;
1492 Point aPoint = aDockingRect.TopLeft();
1493 Size aInnerSize = GetInnerRect().GetSize();
1494 if ( eDockAlign == SfxChildAlignment::LEFT || eDockAlign == SfxChildAlignment::RIGHT )
1496 if ( pImp->bNewLine )
1498 // set height to height of free area
1499 aSize.Height() = aInnerSize.Height();
1500 aSize.Width() = pImp->nHorizontalSize;
1501 if ( eDockAlign == SfxChildAlignment::LEFT )
1503 aPoint = aInnerRect.TopLeft();
1505 else
1507 aPoint = aInnerRect.TopRight();
1508 aPoint.X() -= aSize.Width();
1511 else
1513 // get width from splitwindow
1514 aSize.Width() = pSplitWin->GetLineSize(nLine);
1515 aSize.Height() = pImp->aSplitSize.Height();
1518 else
1520 if ( pImp->bNewLine )
1522 // set width to width of free area
1523 aSize.Width() = aInnerSize.Width();
1524 aSize.Height() = pImp->nVerticalSize;
1525 if ( eDockAlign == SfxChildAlignment::TOP )
1527 aPoint = aInnerRect.TopLeft();
1529 else
1531 aPoint = aInnerRect.BottomLeft();
1532 aPoint.Y() -= aSize.Height();
1535 else
1537 // get height from splitwindow
1538 aSize.Height() = pSplitWin->GetLineSize(nLine);
1539 aSize.Width() = pImp->aSplitSize.Width();
1543 aDockingRect.SetSize( aSize );
1544 aDockingRect.SetPos( aPoint );
1546 else
1548 // window can be docked, but outside our splitwindows
1549 // tracking rectangle only needs to be modified if alignment was changed
1550 if ( eDockAlign != pImp->GetDockAlignment() )
1552 switch ( eDockAlign )
1554 case SfxChildAlignment::LEFT:
1555 case SfxChildAlignment::RIGHT:
1556 case SfxChildAlignment::FIRSTLEFT:
1557 aDockingRect.SetPos( aInnerRect.TopLeft() );
1558 aDockingRect.SetSize( aVerticalSize );
1559 break;
1560 case SfxChildAlignment::LASTLEFT:
1561 case SfxChildAlignment::FIRSTRIGHT:
1562 case SfxChildAlignment::LASTRIGHT:
1564 Point aPt( aInnerRect.TopRight() );
1565 aPt.X() -= aDockingRect.GetWidth();
1566 aDockingRect.SetPos( aPt );
1567 aDockingRect.SetSize( aVerticalSize );
1568 break;
1571 case SfxChildAlignment::TOP:
1572 case SfxChildAlignment::BOTTOM:
1573 case SfxChildAlignment::LOWESTTOP:
1574 aDockingRect.SetPos( aInnerRect.TopLeft() );
1575 aDockingRect.SetSize( aHorizontalSize );
1576 break;
1577 case SfxChildAlignment::HIGHESTTOP:
1578 case SfxChildAlignment::LOWESTBOTTOM:
1579 case SfxChildAlignment::HIGHESTBOTTOM:
1581 Point aPt( aInnerRect.BottomLeft() );
1582 aPt.Y() -= aDockingRect.GetHeight();
1583 aDockingRect.SetPos( aPt );
1584 aDockingRect.SetSize( aHorizontalSize );
1585 break;
1587 default:
1588 break;
1593 rRect = aDockingRect;
1594 return eDockAlign;
1597 /** Virtual method of the SfxDockingWindow class. This method determines how
1598 the size of the DockingWindows changes depending on the alignment. The base
1599 implementation uses the floating mode, the size of the marked Floating
1600 Size. For horizontal alignment, the width will be the width of the outer
1601 DockingRectangle, with vertical alignment the height will be the height of
1602 the inner DockingRectangle (resulting from the order in which the SFX child
1603 windows are displayed). The other size is set to the current floating-size,
1604 this could changed by a to intervening derived class. The docking size must
1605 be the same for Left/Right and Top/Bottom.
1607 Size SfxDockingWindow::CalcDockingSize(SfxChildAlignment eAlign)
1609 // Note: if the resizing is also possible in the docked state, then the
1610 // Floating-size does also have to be adjusted?
1612 Size aSize = GetFloatingSize();
1613 switch (eAlign)
1615 case SfxChildAlignment::TOP:
1616 case SfxChildAlignment::BOTTOM:
1617 case SfxChildAlignment::LOWESTTOP:
1618 case SfxChildAlignment::HIGHESTTOP:
1619 case SfxChildAlignment::LOWESTBOTTOM:
1620 case SfxChildAlignment::HIGHESTBOTTOM:
1621 aSize.Width() = aOuterRect.Right() - aOuterRect.Left();
1622 break;
1623 case SfxChildAlignment::LEFT:
1624 case SfxChildAlignment::RIGHT:
1625 case SfxChildAlignment::FIRSTLEFT:
1626 case SfxChildAlignment::LASTLEFT:
1627 case SfxChildAlignment::FIRSTRIGHT:
1628 case SfxChildAlignment::LASTRIGHT:
1629 aSize.Height() = aInnerRect.Bottom() - aInnerRect.Top();
1630 break;
1631 case SfxChildAlignment::NOALIGNMENT:
1632 break;
1633 default:
1634 break;
1637 return aSize;
1640 /** Virtual method of the SfxDockingWindow class. Here a derived class can
1641 disallow certain alignments. The base implementation does not
1642 prohibit alignment.
1644 SfxChildAlignment SfxDockingWindow::CheckAlignment(SfxChildAlignment,
1645 SfxChildAlignment eAlign)
1647 return eAlign;
1650 /** The window is closed when the ChildWindow is destroyed by running the
1651 ChildWindow-slots. If this is method is overridden by a derived class
1652 method, then the SfxDockingDialogWindow: Close() must be called afterwards
1653 if the Close() was not cancelled with "return sal_False".
1655 bool SfxDockingWindow::Close()
1657 // Execute with Parameters, since Toggle is ignored by some ChildWindows.
1658 if ( !pMgr )
1659 return true;
1661 SfxBoolItem aValue( pMgr->GetType(), false);
1662 pBindings->GetDispatcher_Impl()->Execute(
1663 pMgr->GetType(), SfxCallMode::RECORD | SfxCallMode::ASYNCHRON, &aValue, 0L );
1664 return true;
1667 /** Returns a boundary line to the docked edge and a frame when the Window is in
1668 a docked state. In this way SVLOOK is considered.
1670 void SfxDockingWindow::Paint(vcl::RenderContext& rRenderContext, const Rectangle& /*rRect*/)
1672 if (pImp->bSplitable || IsFloatingMode())
1673 return;
1675 Rectangle aRect(Point(0, 0), GetOutputSizePixel());
1676 switch (GetAlignment())
1678 case SfxChildAlignment::TOP:
1680 rRenderContext.DrawLine(aRect.BottomLeft(), aRect.BottomRight());
1681 aRect.Bottom()--;
1682 break;
1685 case SfxChildAlignment::BOTTOM:
1687 rRenderContext.DrawLine(aRect.TopLeft(), aRect.TopRight());
1688 aRect.Top()++;
1689 break;
1692 case SfxChildAlignment::LEFT:
1694 rRenderContext.DrawLine(aRect.TopRight(), aRect.BottomRight());
1695 aRect.Right()--;
1696 break;
1699 case SfxChildAlignment::RIGHT:
1701 rRenderContext.DrawLine(aRect.TopLeft(), aRect.BottomLeft());
1702 aRect.Left()++;
1703 break;
1706 default:
1707 break;
1710 DecorationView aView(&rRenderContext);
1711 aView.DrawFrame(aRect, DrawFrameStyle::Out);
1714 /** With this method, a minimal OutputSize be can set, that is queried in
1715 the Resizing()-Handler.
1717 void SfxDockingWindow::SetMinOutputSizePixel( const Size& rSize )
1719 pImp->aMinSize = rSize;
1720 DockingWindow::SetMinOutputSizePixel( rSize );
1723 /** Set the minimum size which is returned.*/
1724 Size SfxDockingWindow::GetMinOutputSizePixel() const
1726 return pImp->aMinSize;
1729 bool SfxDockingWindow::Notify( NotifyEvent& rEvt )
1731 if ( !pImp )
1732 return DockingWindow::Notify( rEvt );
1734 if ( rEvt.GetType() == MouseNotifyEvent::GETFOCUS )
1736 if (pMgr != NULL)
1737 pBindings->SetActiveFrame( pMgr->GetFrame() );
1739 if ( pImp->pSplitWin )
1740 pImp->pSplitWin->SetActiveWindow_Impl( this );
1741 else if (pMgr != NULL)
1742 pMgr->Activate_Impl();
1744 // In VCL Notify goes first to the window itself, also call the
1745 // base class, otherwise the parent learns nothing
1746 // if ( rEvt.GetWindow() == this ) PB: #i74693# not necessary any longer
1747 DockingWindow::Notify( rEvt );
1748 return true;
1750 else if( rEvt.GetType() == MouseNotifyEvent::KEYINPUT )
1752 // First, allow KeyInput for Dialog functions
1753 if ( !DockingWindow::Notify( rEvt ) && SfxViewShell::Current() )
1754 // then also for valid global accelerators.
1755 return SfxViewShell::Current()->GlobalKeyInput_Impl( *rEvt.GetKeyEvent() );
1756 return true;
1758 else if ( rEvt.GetType() == MouseNotifyEvent::LOSEFOCUS && !HasChildPathFocus() )
1760 pBindings->SetActiveFrame( NULL );
1761 if (pMgr != NULL)
1762 pMgr->Deactivate_Impl();
1765 return DockingWindow::Notify( rEvt );
1769 sal_uInt16 SfxDockingWindow::GetWinBits_Impl() const
1771 sal_uInt16 nBits = 0;
1772 return nBits;
1777 void SfxDockingWindow::SetItemSize_Impl( const Size& rSize )
1779 pImp->aSplitSize = rSize;
1781 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
1782 SfxChildIdentifier eIdent = SfxChildIdentifier::DOCKINGWINDOW;
1783 if ( pImp->bSplitable )
1784 eIdent = SfxChildIdentifier::SPLITWINDOW;
1785 pWorkWin->ConfigChild_Impl( eIdent, SfxDockingConfig::ALIGNDOCKINGWINDOW, pMgr->GetType() );
1788 void SfxDockingWindow::Disappear_Impl()
1790 if ( pImp->pSplitWin && pImp->pSplitWin->IsItemValid( GetType() ) )
1791 pImp->pSplitWin->RemoveWindow(this);
1794 void SfxDockingWindow::Reappear_Impl()
1796 if ( pImp->pSplitWin && !pImp->pSplitWin->IsItemValid( GetType() ) )
1798 pImp->pSplitWin->InsertWindow( this, pImp->aSplitSize );
1802 bool SfxDockingWindow::IsAutoHide_Impl() const
1804 if ( pImp->pSplitWin )
1805 return !pImp->pSplitWin->IsFadeIn();
1806 else
1807 return false;
1810 void SfxDockingWindow::AutoShow_Impl( bool bShow )
1812 if ( pImp->pSplitWin )
1814 if ( bShow )
1815 pImp->pSplitWin->FadeIn();
1816 else
1817 pImp->pSplitWin->FadeOut();
1821 void SfxDockingWindow::StateChanged( StateChangedType nStateChange )
1823 if ( nStateChange == StateChangedType::InitShow )
1824 Initialize_Impl();
1826 DockingWindow::StateChanged( nStateChange );
1829 void SfxDockingWindow::Move()
1831 if ( pImp )
1832 pImp->aMoveIdle.Start();
1835 IMPL_LINK_NOARG_TYPED(SfxDockingWindow, TimerHdl, Idle *, void)
1837 pImp->aMoveIdle.Stop();
1838 if ( IsReallyVisible() && IsFloatingMode() )
1840 if( !GetFloatingWindow()->IsRollUp() )
1841 SetFloatingSize( GetOutputSizePixel() );
1842 pImp->aWinState = GetFloatingWindow()->GetWindowState();
1843 SfxChildIdentifier eIdent = SfxChildIdentifier::DOCKINGWINDOW;
1844 if ( pImp->bSplitable )
1845 eIdent = SfxChildIdentifier::SPLITWINDOW;
1846 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
1847 pWorkWin->ConfigChild_Impl( eIdent, SfxDockingConfig::ALIGNDOCKINGWINDOW, pMgr->GetType() );
1851 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */