Bump version to 24.04.3.4
[LibreOffice.git] / sfx2 / source / dialog / dockwin.cxx
blobf71501642fe8a0c49f3c1c8aa871705fba8b9114
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 <svl/solar.hrc>
22 #include <vcl/event.hxx>
23 #include <vcl/settings.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/timer.hxx>
27 #include <vcl/idle.hxx>
28 #include <o3tl/safeint.hxx>
29 #include <o3tl/string_view.hxx>
30 #include <osl/diagnose.h>
31 #include <toolkit/helper/vclunohelper.hxx>
32 #include <tools/debug.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <comphelper/propertysequence.hxx>
35 #include <svl/itemset.hxx>
37 #include <sfx2/dockwin.hxx>
38 #include <sfx2/bindings.hxx>
39 #include <sfx2/viewfrm.hxx>
40 #include <sfx2/dispatch.hxx>
41 #include <workwin.hxx>
42 #include <splitwin.hxx>
43 #include <sfx2/viewsh.hxx>
45 #include <com/sun/star/beans/UnknownPropertyException.hpp>
46 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
47 #include <com/sun/star/awt/XWindow.hpp>
48 #include <com/sun/star/uno/XComponentContext.hpp>
49 #include <com/sun/star/frame/ModuleManager.hpp>
50 #include <com/sun/star/container/XNameAccess.hpp>
51 #include <com/sun/star/ui/theWindowStateConfiguration.hpp>
52 #include <com/sun/star/ui/theWindowContentFactoryManager.hpp>
54 #define MAX_TOGGLEAREA_WIDTH 20
55 #define MAX_TOGGLEAREA_HEIGHT 20
57 using namespace ::com::sun::star;
59 // If you want to change the number you also have to:
60 // - Add new slot ids to sfxsids.hrc
61 // - Add new slots to frmslots.sdi
62 // - Add new slot definitions to sfx.sdi
63 const int NUM_OF_DOCKINGWINDOWS = 10;
65 namespace {
67 class SfxTitleDockingWindow : public SfxDockingWindow
69 VclPtr<vcl::Window> m_pWrappedWindow;
71 public:
72 SfxTitleDockingWindow(
73 SfxBindings* pBindings ,
74 SfxChildWindow* pChildWin ,
75 vcl::Window* pParent ,
76 WinBits nBits);
77 virtual ~SfxTitleDockingWindow() override;
78 virtual void dispose() override;
80 vcl::Window* GetWrappedWindow() const { return m_pWrappedWindow; }
81 void SetWrappedWindow(vcl::Window* const pWindow);
83 virtual void StateChanged( StateChangedType nType ) override;
84 virtual void Resize() override;
85 virtual void Resizing( Size& rSize ) override;
88 struct WindowState
90 OUString sTitle;
94 static bool lcl_getWindowState( const uno::Reference< container::XNameAccess >& xWindowStateMgr, const OUString& rResourceURL, WindowState& rWindowState )
96 bool bResult = false;
98 try
100 uno::Any a;
101 uno::Sequence< beans::PropertyValue > aWindowState;
102 a = xWindowStateMgr->getByName( rResourceURL );
103 if ( a >>= aWindowState )
105 for ( const auto& rProp : std::as_const(aWindowState) )
107 if ( rProp.Name == "UIName" )
109 rProp.Value >>= rWindowState.sTitle;
114 bResult = true;
116 catch ( container::NoSuchElementException& )
118 bResult = false;
121 return bResult;
124 SfxDockingWrapper::SfxDockingWrapper( vcl::Window* pParentWnd ,
125 sal_uInt16 nId ,
126 SfxBindings* pBindings ,
127 SfxChildWinInfo* pInfo )
128 : SfxChildWindow( pParentWnd , nId )
130 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
132 VclPtr<SfxTitleDockingWindow> pTitleDockWindow = VclPtr<SfxTitleDockingWindow>::Create( pBindings, this, pParentWnd,
133 WB_STDDOCKWIN | WB_CLIPCHILDREN | WB_SIZEABLE | WB_3DLOOK);
134 SetWindow( pTitleDockWindow );
136 // Use factory manager to retrieve XWindow factory. That can be used to instantiate
137 // the real window factory.
138 uno::Reference< lang::XSingleComponentFactory > xFactoryMgr = ui::theWindowContentFactoryManager::get(xContext);
140 SfxDispatcher* pDispatcher = pBindings->GetDispatcher();
141 uno::Reference< frame::XFrame > xFrame = pDispatcher->GetFrame()->GetFrame().GetFrameInterface();
142 // create a resource URL from the nId provided by the sfx2
143 OUString aResourceURL = "private:resource/dockingwindow/" + OUString::number(nId);
144 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
146 {"Frame", uno::Any(xFrame)},
147 {"ResourceURL", uno::Any(aResourceURL)},
148 }));
150 uno::Reference< awt::XWindow > xWindow;
153 xWindow.set(
154 xFactoryMgr->createInstanceWithArgumentsAndContext( aArgs, xContext ),
155 uno::UNO_QUERY );
157 static uno::WeakReference< frame::XModuleManager2 > s_xModuleManager;
159 uno::Reference< frame::XModuleManager2 > xModuleManager( s_xModuleManager );
160 if ( !xModuleManager.is() )
162 xModuleManager = frame::ModuleManager::create(xContext);
163 s_xModuleManager = xModuleManager;
166 static uno::WeakReference< container::XNameAccess > s_xWindowStateConfiguration;
168 uno::Reference< container::XNameAccess > xWindowStateConfiguration( s_xWindowStateConfiguration );
169 if ( !xWindowStateConfiguration.is() )
171 xWindowStateConfiguration = ui::theWindowStateConfiguration::get( xContext );
172 s_xWindowStateConfiguration = xWindowStateConfiguration;
175 OUString sModuleIdentifier = xModuleManager->identify( xFrame );
177 uno::Reference< container::XNameAccess > xModuleWindowState(
178 xWindowStateConfiguration->getByName( sModuleIdentifier ),
179 uno::UNO_QUERY );
180 if ( xModuleWindowState.is() )
182 WindowState aDockWinState;
183 if ( lcl_getWindowState( xModuleWindowState, aResourceURL, aDockWinState ))
184 pTitleDockWindow->SetText( aDockWinState.sTitle );
187 catch ( beans::UnknownPropertyException& )
190 catch ( uno::RuntimeException& )
193 catch ( uno::Exception& )
197 VclPtr<vcl::Window> pContentWindow = VCLUnoHelper::GetWindow(xWindow);
198 if ( pContentWindow )
199 pContentWindow->SetStyle( pContentWindow->GetStyle() | WB_DIALOGCONTROL | WB_CHILDDLGCTRL );
200 pTitleDockWindow->SetWrappedWindow(pContentWindow);
202 GetWindow()->SetOutputSizePixel( Size( 270, 240 ) );
204 static_cast<SfxDockingWindow*>( GetWindow() )->Initialize( pInfo );
205 SetHideNotDelete( true );
208 std::unique_ptr<SfxChildWindow> SfxDockingWrapper::CreateImpl(vcl::Window *pParent, sal_uInt16 nId,
209 SfxBindings *pBindings, SfxChildWinInfo* pInfo)
211 return std::make_unique<SfxDockingWrapper>(pParent, nId, pBindings, pInfo);
214 void SfxDockingWrapper::RegisterChildWindow (bool bVis, SfxModule *pMod, SfxChildWindowFlags nFlags)
216 // pre-register a couple of docking windows
217 for (int i=0; i < NUM_OF_DOCKINGWINDOWS; i++ )
219 sal_uInt16 nID = sal_uInt16(SID_DOCKWIN_START+i);
220 SfxChildWinFactory aFact( SfxDockingWrapper::CreateImpl, nID, 0xffff );
221 aFact.aInfo.nFlags |= nFlags;
222 aFact.aInfo.bVisible = bVis;
223 SfxChildWindow::RegisterChildWindow(pMod, aFact);
227 SfxChildWinInfo SfxDockingWrapper::GetInfo() const
229 SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
230 static_cast<SfxDockingWindow*>(GetWindow())->FillInfo( aInfo );
231 return aInfo;
234 SfxTitleDockingWindow::SfxTitleDockingWindow(SfxBindings* pBind, SfxChildWindow* pChildWin,
235 vcl::Window* pParent, WinBits nBits)
236 : SfxDockingWindow(pBind, pChildWin, pParent, nBits)
237 , m_pWrappedWindow(nullptr)
241 SfxTitleDockingWindow::~SfxTitleDockingWindow()
243 disposeOnce();
246 void SfxTitleDockingWindow::dispose()
248 m_pWrappedWindow.disposeAndClear();
249 SfxDockingWindow::dispose();
252 void SfxTitleDockingWindow::SetWrappedWindow( vcl::Window* const pWindow )
254 m_pWrappedWindow = pWindow;
255 if (m_pWrappedWindow)
257 m_pWrappedWindow->SetParent(this);
258 m_pWrappedWindow->SetSizePixel( GetOutputSizePixel() );
259 m_pWrappedWindow->Show();
263 void SfxTitleDockingWindow::StateChanged( StateChangedType nType )
265 if ( nType == StateChangedType::InitShow )
267 vcl::Window* pWindow = GetWrappedWindow();
268 if ( pWindow )
270 pWindow->SetSizePixel( GetOutputSizePixel() );
271 pWindow->Show();
275 SfxDockingWindow::StateChanged(nType);
278 void SfxTitleDockingWindow::Resize()
280 SfxDockingWindow::Resize();
281 if (m_pWrappedWindow)
282 m_pWrappedWindow->SetSizePixel( GetOutputSizePixel() );
285 void SfxTitleDockingWindow::Resizing( Size &rSize )
287 SfxDockingWindow::Resizing( rSize );
288 if (m_pWrappedWindow)
289 m_pWrappedWindow->SetSizePixel( GetOutputSizePixel() );
292 static bool lcl_checkDockingWindowID( sal_uInt16 nID )
294 return nID >= SID_DOCKWIN_START && nID < o3tl::make_unsigned(SID_DOCKWIN_START+NUM_OF_DOCKINGWINDOWS);
297 static SfxWorkWindow* lcl_getWorkWindowFromXFrame( const uno::Reference< frame::XFrame >& rFrame )
299 // We need to find the corresponding SfxFrame of our XFrame
300 SfxFrame* pFrame = SfxFrame::GetFirst();
301 SfxFrame* pXFrame = nullptr;
302 while ( pFrame )
304 uno::Reference< frame::XFrame > xViewShellFrame( pFrame->GetFrameInterface() );
305 if ( xViewShellFrame == rFrame )
307 pXFrame = pFrame;
308 break;
310 else
311 pFrame = SfxFrame::GetNext( *pFrame );
314 // If we have a SfxFrame we can retrieve the work window (Sfx layout manager for docking windows)
315 if ( pXFrame )
316 return pXFrame->GetWorkWindow_Impl();
317 else
318 return nullptr;
321 /** Factory function used by the framework layout manager to "create" a docking window with a special name.
322 The string rDockingWindowName MUST BE a valid ID! The ID is pre-defined by a certain slot range located
323 in sfxsids.hrc (currently SID_DOCKWIN_START = 9800).
325 void SfxDockingWindowFactory( const uno::Reference< frame::XFrame >& rFrame, std::u16string_view rDockingWindowName )
327 SolarMutexGuard aGuard;
328 sal_uInt16 nID = sal_uInt16(o3tl::toInt32(rDockingWindowName));
330 // Check the range of the provided ID otherwise nothing will happen
331 if ( !lcl_checkDockingWindowID( nID ))
332 return;
334 SfxWorkWindow* pWorkWindow = lcl_getWorkWindowFromXFrame( rFrame );
335 if ( pWorkWindow )
337 SfxChildWindow* pChildWindow = pWorkWindow->GetChildWindow_Impl(nID);
338 if ( !pChildWindow )
340 // Register window at the workwindow child window list
341 pWorkWindow->SetChildWindow_Impl( nID, true, false );
346 /** Function used by the framework layout manager to determine the visibility state of a docking window with
347 a special name. The string rDockingWindowName MUST BE a valid ID! The ID is pre-defined by a certain slot
348 range located in sfxsids.hrc (currently SID_DOCKWIN_START = 9800).
350 bool IsDockingWindowVisible( const uno::Reference< frame::XFrame >& rFrame, std::u16string_view rDockingWindowName )
352 SolarMutexGuard aGuard;
354 sal_uInt16 nID = sal_uInt16(o3tl::toInt32(rDockingWindowName));
356 // Check the range of the provided ID otherwise nothing will happen
357 if ( lcl_checkDockingWindowID( nID ))
359 SfxWorkWindow* pWorkWindow = lcl_getWorkWindowFromXFrame( rFrame );
360 if ( pWorkWindow )
362 SfxChildWindow* pChildWindow = pWorkWindow->GetChildWindow_Impl(nID);
363 if ( pChildWindow )
364 return true;
368 return false;
371 class SfxDockingWindow_Impl
373 friend class SfxDockingWindow;
375 SfxChildAlignment eLastAlignment;
376 SfxChildAlignment eDockAlignment;
377 bool bConstructed;
378 Size aMinSize;
379 VclPtr<SfxSplitWindow> pSplitWin;
380 Idle aMoveIdle;
382 // The following members are only valid in the time from startDocking to
383 // EndDocking:
384 Size aSplitSize;
385 tools::Long nHorizontalSize;
386 tools::Long nVerticalSize;
387 sal_uInt16 nLine;
388 sal_uInt16 nPos;
389 sal_uInt16 nDockLine;
390 sal_uInt16 nDockPos;
391 bool bNewLine;
392 bool bDockingPrevented;
393 OUString aWinState;
395 explicit SfxDockingWindow_Impl(SfxDockingWindow *pBase);
396 SfxChildAlignment GetLastAlignment() const
397 { return eLastAlignment; }
398 void SetLastAlignment(SfxChildAlignment eAlign)
399 { eLastAlignment = eAlign; }
400 SfxChildAlignment GetDockAlignment() const
401 { return eDockAlignment; }
402 void SetDockAlignment(SfxChildAlignment eAlign)
403 { eDockAlignment = eAlign; }
406 SfxDockingWindow_Impl::SfxDockingWindow_Impl(SfxDockingWindow* pBase)
407 :eLastAlignment(SfxChildAlignment::NOALIGNMENT)
408 ,eDockAlignment(SfxChildAlignment::NOALIGNMENT)
409 ,bConstructed(false)
410 ,pSplitWin(nullptr)
411 ,aMoveIdle( "sfx::SfxDockingWindow_Impl aMoveIdle" )
412 ,nHorizontalSize(0)
413 ,nVerticalSize(0)
414 ,nLine(0)
415 ,nPos(0)
416 ,nDockLine(0)
417 ,nDockPos(0)
418 ,bNewLine(false)
419 ,bDockingPrevented(false)
421 aMoveIdle.SetPriority(TaskPriority::RESIZE);
422 aMoveIdle.SetInvokeHandler(LINK(pBase,SfxDockingWindow,TimerHdl));
425 /* [Description]
427 This virtual method of the class FloatingWindow keeps track of changes in
428 FloatingSize. If this method is overridden by a derived class,
429 then the FloatingWindow: Resize() must also be called.
431 void SfxDockingWindow::Resize()
433 ResizableDockingWindow::Resize();
434 Invalidate();
435 if ( !pImpl || !pImpl->bConstructed || !pMgr )
436 return;
438 if ( IsFloatingMode() )
440 // start timer for saving window status information
441 pImpl->aMoveIdle.Start();
443 else
445 Size aSize( GetSizePixel() );
446 switch ( pImpl->GetDockAlignment() )
448 case SfxChildAlignment::LEFT:
449 case SfxChildAlignment::FIRSTLEFT:
450 case SfxChildAlignment::LASTLEFT:
451 case SfxChildAlignment::RIGHT:
452 case SfxChildAlignment::FIRSTRIGHT:
453 case SfxChildAlignment::LASTRIGHT:
454 pImpl->nHorizontalSize = aSize.Width();
455 pImpl->aSplitSize = aSize;
456 break;
457 case SfxChildAlignment::TOP:
458 case SfxChildAlignment::LOWESTTOP:
459 case SfxChildAlignment::HIGHESTTOP:
460 case SfxChildAlignment::BOTTOM:
461 case SfxChildAlignment::HIGHESTBOTTOM:
462 case SfxChildAlignment::LOWESTBOTTOM:
463 pImpl->nVerticalSize = aSize.Height();
464 pImpl->aSplitSize = aSize;
465 break;
466 default:
467 break;
472 /* [Description]
474 This virtual method of the class DockingWindow makes it possible to
475 intervene in the switching of the floating mode.
476 If this method is overridden by a derived class,
477 then the SfxDockingWindow::PrepareToggleFloatingMode() must be called
478 afterwards, if not FALSE is returned.
480 bool SfxDockingWindow::PrepareToggleFloatingMode()
482 if (!pImpl || !pImpl->bConstructed)
483 return true;
485 if ( (Application::IsInModalMode() && IsFloatingMode()) || !pMgr )
486 return false;
488 if ( pImpl->bDockingPrevented )
489 return false;
491 if (!IsFloatingMode())
493 // Test, if FloatingMode is permitted.
494 if ( CheckAlignment(GetAlignment(),SfxChildAlignment::NOALIGNMENT) != SfxChildAlignment::NOALIGNMENT )
495 return false;
497 if ( pImpl->pSplitWin )
499 // The DockingWindow is inside a SplitWindow and will be teared of.
500 pImpl->pSplitWin->RemoveWindow(this/*, sal_False*/);
501 pImpl->pSplitWin = nullptr;
504 else if ( pMgr )
506 pImpl->aWinState = GetFloatingWindow()->GetWindowState();
508 // Test if it is allowed to dock,
509 if (CheckAlignment(GetAlignment(),pImpl->GetLastAlignment()) == SfxChildAlignment::NOALIGNMENT)
510 return false;
512 // Test, if the Workwindow allows for docking at the moment.
513 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
514 if ( !pWorkWin->IsDockingAllowed() || !pWorkWin->IsInternalDockingAllowed() )
515 return false;
518 return true;
521 /* [Description]
523 This virtual method of the DockingWindow class sets the internal data of
524 the SfxDockingWindow and ensures the correct alignment on the parent window.
525 Through PrepareToggleFloatMode and Initialize it is ensured that
526 pImpl-> GetLastAlignment() always delivers an allowed alignment. If this
527 method is overridden by a derived class, then first the
528 SfxDockingWindow::ToggleFloatingMode() must be called.
530 void SfxDockingWindow::ToggleFloatingMode()
532 if ( !pImpl || !pImpl->bConstructed || !pMgr )
533 return; // No Handler call
535 // Remember old alignment and then switch.
536 // SV has already switched, but the alignment SfxDockingWindow is still
537 // the old one. What I was before?
538 SfxChildAlignment eLastAlign = GetAlignment();
540 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
542 if (IsFloatingMode())
544 SetAlignment(SfxChildAlignment::NOALIGNMENT);
545 if ( !pImpl->aWinState.isEmpty() )
546 GetFloatingWindow()->SetWindowState( pImpl->aWinState );
547 else
548 GetFloatingWindow()->SetOutputSizePixel( GetFloatingSize() );
550 else
552 if (pImpl->GetDockAlignment() == eLastAlign)
554 // If ToggleFloatingMode was called, but the DockAlignment still
555 // is unchanged, then this means that it must have been a toggling
556 // through DClick, so use last alignment
557 SetAlignment (pImpl->GetLastAlignment());
559 else
562 // Toggling was triggered by dragging
563 pImpl->nLine = pImpl->nDockLine;
564 pImpl->nPos = pImpl->nDockPos;
565 SetAlignment (pImpl->GetDockAlignment());
568 // The DockingWindow is now in a SplitWindow
569 pImpl->pSplitWin = pWorkWin->GetSplitWindow_Impl(GetAlignment());
571 // The LastAlignment is still the last docked
572 SfxSplitWindow *pSplit = pWorkWin->GetSplitWindow_Impl(pImpl->GetLastAlignment());
574 DBG_ASSERT( pSplit, "LastAlignment is not correct!" );
575 if ( pSplit && pSplit != pImpl->pSplitWin )
576 pSplit->ReleaseWindow_Impl(this);
577 if ( pImpl->GetDockAlignment() == eLastAlign )
578 pImpl->pSplitWin->InsertWindow( this, pImpl->aSplitSize );
579 else
580 pImpl->pSplitWin->InsertWindow( this, pImpl->aSplitSize, pImpl->nLine, pImpl->nPos, pImpl->bNewLine );
581 if ( !pImpl->pSplitWin->IsFadeIn() )
582 pImpl->pSplitWin->FadeIn();
585 // Keep the old alignment for the next toggle; set it only now due to the
586 // unregister SplitWindow!
587 pImpl->SetLastAlignment(eLastAlign);
589 // Reset DockAlignment, if EndDocking is still called
590 pImpl->SetDockAlignment(GetAlignment());
592 // Dock or undock SfxChildWindow correctly.
593 pWorkWin->ConfigChild_Impl( SfxChildIdentifier::SPLITWINDOW, SfxDockingConfig::TOGGLEFLOATMODE, pMgr->GetType() );
596 /* [Description]
598 This virtual method of the DockingWindow class takes the inner and outer
599 docking rectangle from the parent window. If this method is overridden by
600 a derived class, then SfxDockingWindow:StartDocking() has to be called at
601 the end.
603 void SfxDockingWindow::StartDocking()
605 if ( !pImpl || !pImpl->bConstructed || !pMgr )
606 return;
607 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
608 pWorkWin->ConfigChild_Impl( SfxChildIdentifier::SPLITWINDOW, SfxDockingConfig::SETDOCKINGRECTS, pMgr->GetType() );
609 pImpl->SetDockAlignment(GetAlignment());
611 if ( pImpl->pSplitWin )
613 // Get the current docking data
614 pImpl->pSplitWin->GetWindowPos(this, pImpl->nLine, pImpl->nPos);
615 pImpl->nDockLine = pImpl->nLine;
616 pImpl->nDockPos = pImpl->nPos;
617 pImpl->bNewLine = false;
621 /* [Description]
623 This virtual method of the DockingWindow class calculates the current
624 tracking rectangle. For this purpose the method CalcAlignment(RPOs, rRect)
625 is used, the behavior can be influenced by the derived classes (see below).
626 This method should if possible not be overwritten.
628 bool SfxDockingWindow::Docking( const Point& rPos, tools::Rectangle& rRect )
630 if ( Application::IsInModalMode() )
631 return true;
633 if ( !pImpl || !pImpl->bConstructed || !pMgr )
635 rRect.SetSize( Size() );
636 return IsFloatingMode();
639 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
640 if ( pImpl->bDockingPrevented || !pWorkWin->IsInternalDockingAllowed() )
641 return false;
643 bool bFloatMode = false;
645 if ( GetOuterRect().Contains( rPos ) )
647 // Mouse within OuterRect: calculate Alignment and Rectangle
648 SfxChildAlignment eAlign = CalcAlignment(rPos, rRect);
649 if (eAlign == SfxChildAlignment::NOALIGNMENT)
650 bFloatMode = true;
651 pImpl->SetDockAlignment(eAlign);
653 else
655 // Mouse is not within OuterRect: must be FloatingWindow
656 // Is this allowed?
657 if (CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::NOALIGNMENT) != SfxChildAlignment::NOALIGNMENT)
658 return false;
659 bFloatMode = true;
660 if ( SfxChildAlignment::NOALIGNMENT != pImpl->GetDockAlignment() )
662 // Due to a bug the rRect may only be changed when the
663 // alignment is changed!
664 pImpl->SetDockAlignment(SfxChildAlignment::NOALIGNMENT);
665 rRect.SetSize(CalcDockingSize(SfxChildAlignment::NOALIGNMENT));
669 return bFloatMode;
672 /** Virtual method of the DockingWindow class ensures the correct alignment on
673 the parent window. If this method is overridden by a derived class, then
674 SfxDockingWindow::EndDocking() must be called first.
676 void SfxDockingWindow::EndDocking( const tools::Rectangle& rRect, bool bFloatMode )
678 if ( !pImpl || !pImpl->bConstructed || IsDockingCanceled() || !pMgr )
679 return;
681 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
683 // If the alignment changes and the window is in a docked state in a
684 // SplitWindow, then it must be re-registered. If it is docked again,
685 // PrepareToggleFloatingMode() and ToggleFloatingMode() perform the
686 // re-registered
687 bool bReArrange = !bFloatMode;
689 if ( bReArrange )
691 if ( GetAlignment() != pImpl->GetDockAlignment() )
693 // before Show() is called must the reassignment have been made,
694 // therefore the base class can not be called
695 if ( IsFloatingMode() )
696 Show( false, ShowFlags::NoFocusChange );
698 // Set the size for toggling.
699 pImpl->aSplitSize = rRect.GetSize();
700 if ( IsFloatingMode() )
702 SetFloatingMode( bFloatMode );
703 if ( IsFloatingMode() )
704 Show( true, ShowFlags::NoFocusChange );
706 else
708 pImpl->pSplitWin->RemoveWindow(this,false);
709 pImpl->nLine = pImpl->nDockLine;
710 pImpl->nPos = pImpl->nDockPos;
711 pImpl->pSplitWin->ReleaseWindow_Impl(this);
712 pImpl->pSplitWin = pWorkWin->GetSplitWindow_Impl(pImpl->GetDockAlignment());
713 pImpl->pSplitWin->InsertWindow( this, pImpl->aSplitSize, pImpl->nDockLine, pImpl->nDockPos, pImpl->bNewLine );
714 if ( !pImpl->pSplitWin->IsFadeIn() )
715 pImpl->pSplitWin->FadeIn();
718 else if ( pImpl->nLine != pImpl->nDockLine || pImpl->nPos != pImpl->nDockPos || pImpl->bNewLine )
720 // Moved within Splitwindows
721 if ( pImpl->nLine != pImpl->nDockLine )
722 pImpl->aSplitSize = rRect.GetSize();
723 pImpl->pSplitWin->MoveWindow( this, pImpl->aSplitSize, pImpl->nDockLine, pImpl->nDockPos, pImpl->bNewLine );
726 else
728 ResizableDockingWindow::EndDocking(rRect, bFloatMode);
731 SetAlignment( IsFloatingMode() ? SfxChildAlignment::NOALIGNMENT : pImpl->GetDockAlignment() );
734 /* [Description]
736 Virtual method of the DockingWindow class. Here, the interactive resize in
737 FloatingMode can be influenced, for example by only allowing for discrete
738 values for width and / or height. The base implementation prevents that the
739 output size is smaller than one set with SetMinOutputSizePixel().
741 void SfxDockingWindow::Resizing( Size& /*rSize*/ )
746 /* [Description]
748 Constructor for the SfxDockingWindow class. A SfxChildWindow will be
749 required because the docking is implemented in Sfx through SfxChildWindows.
751 SfxDockingWindow::SfxDockingWindow( SfxBindings *pBindinx, SfxChildWindow *pCW,
752 vcl::Window* pParent, WinBits nWinBits)
753 : ResizableDockingWindow(pParent, nWinBits)
754 , pBindings(pBindinx)
755 , pMgr(pCW)
757 pImpl.reset(new SfxDockingWindow_Impl(this));
760 /** Constructor for the SfxDockingWindow class. A SfxChildWindow will be
761 required because the docking is implemented in Sfx through SfxChildWindows.
763 SfxDockingWindow::SfxDockingWindow( SfxBindings *pBindinx, SfxChildWindow *pCW,
764 vcl::Window* pParent, const OUString& rID, const OUString& rUIXMLDescription)
765 : ResizableDockingWindow(pParent)
766 , pBindings(pBindinx)
767 , pMgr(pCW)
769 m_xBuilder = Application::CreateInterimBuilder(m_xBox, rUIXMLDescription, true);
770 m_xContainer = m_xBuilder->weld_box(rID);
772 pImpl.reset(new SfxDockingWindow_Impl(this));
775 /** Initialization of the SfxDockingDialog class via a SfxChildWinInfo.
776 The initialization is done only in a 2nd step after the constructor, this
777 constructor should be called from the derived class or from the
778 SfxChildWindows.
780 void SfxDockingWindow::Initialize(SfxChildWinInfo *pInfo)
782 if ( !pMgr )
784 pImpl->SetDockAlignment( SfxChildAlignment::NOALIGNMENT );
785 pImpl->bConstructed = true;
786 return;
789 if (pInfo && (pInfo->nFlags & SfxChildWindowFlags::FORCEDOCK))
790 pImpl->bDockingPrevented = true;
792 pImpl->aSplitSize = GetOutputSizePixel();
793 if ( !GetFloatingSize().Width() )
795 Size aMinSize( GetMinOutputSizePixel() );
796 SetFloatingSize( pImpl->aSplitSize );
797 if ( pImpl->aSplitSize.Width() < aMinSize.Width() )
798 pImpl->aSplitSize.setWidth( aMinSize.Width() );
799 if ( pImpl->aSplitSize.Height() < aMinSize.Height() )
800 pImpl->aSplitSize.setHeight( aMinSize.Height() );
803 bool bVertHorzRead( false );
804 if (pInfo && !pInfo->aExtraString.isEmpty())
806 // get information about alignment, split size and position in SplitWindow
807 OUString aStr;
808 sal_Int32 nPos = pInfo->aExtraString.indexOf("AL:");
809 if ( nPos != -1 )
811 // alignment information
812 sal_Int32 n1 = pInfo->aExtraString.indexOf('(', nPos);
813 if ( n1 != -1 )
815 sal_Int32 n2 = pInfo->aExtraString.indexOf(')', n1);
816 if ( n2 != -1 )
818 // extract alignment information from extrastring
819 aStr = pInfo->aExtraString.copy(nPos, n2 - nPos + 1);
820 pInfo->aExtraString = pInfo->aExtraString.replaceAt(nPos, n2 - nPos + 1, u"");
821 aStr = aStr.replaceAt(nPos, n1-nPos+1, u"");
826 if ( !aStr.isEmpty() )
828 // accept window state only if alignment is also set
829 pImpl->aWinState = pInfo->aWinState;
831 // check for valid alignment
832 SfxChildAlignment eLocalAlignment = static_cast<SfxChildAlignment>(static_cast<sal_uInt16>(aStr.toInt32()));
833 bool bIgnoreFloatConfig = (eLocalAlignment == SfxChildAlignment::NOALIGNMENT &&
834 !StyleSettings::GetDockingFloatsSupported());
835 if (pImpl->bDockingPrevented || bIgnoreFloatConfig)
836 // docking prevented, ignore old configuration and take alignment from default
837 aStr.clear();
838 else
839 SetAlignment( eLocalAlignment );
841 SfxChildAlignment eAlign = CheckAlignment(GetAlignment(),GetAlignment());
842 if ( eAlign != GetAlignment() )
844 OSL_FAIL("Invalid Alignment!");
845 SetAlignment( eAlign );
846 aStr.clear();
849 // get last alignment (for toggling)
850 nPos = aStr.indexOf(',');
851 if ( nPos != -1 )
853 aStr = aStr.copy(nPos+1);
854 pImpl->SetLastAlignment( static_cast<SfxChildAlignment>(static_cast<sal_uInt16>(aStr.toInt32())) );
857 nPos = aStr.indexOf(',');
858 if ( nPos != -1 )
860 // get split size and position in SplitWindow
861 Point aPos;
862 aStr = aStr.copy(nPos+1);
863 if ( GetPosSizeFromString( aStr, aPos, pImpl->aSplitSize ) )
865 pImpl->nLine = pImpl->nDockLine = static_cast<sal_uInt16>(aPos.X());
866 pImpl->nPos = pImpl->nDockPos = static_cast<sal_uInt16>(aPos.Y());
867 pImpl->nVerticalSize = pImpl->aSplitSize.Height();
868 pImpl->nHorizontalSize = pImpl->aSplitSize.Width();
869 if ( GetSplitSizeFromString( aStr, pImpl->aSplitSize ))
870 bVertHorzRead = true;
874 else {
875 OSL_FAIL( "Information is missing!" );
879 if ( !bVertHorzRead )
881 pImpl->nVerticalSize = pImpl->aSplitSize.Height();
882 pImpl->nHorizontalSize = pImpl->aSplitSize.Width();
885 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
886 if ( GetAlignment() != SfxChildAlignment::NOALIGNMENT )
888 // check if SfxWorkWindow is able to allow docking at its border
889 if (
890 !pWorkWin->IsDockingAllowed() ||
891 !pWorkWin->IsInternalDockingAllowed() ||
892 ( (GetFloatStyle() & WB_STANDALONE) && Application::IsInModalMode()) )
894 SetAlignment( SfxChildAlignment::NOALIGNMENT );
898 // detect floating mode
899 // toggling mode will not execute code in handlers, because pImpl->bConstructed is not set yet
900 bool bFloatMode = IsFloatingMode();
901 if ( bFloatMode != (GetAlignment() == SfxChildAlignment::NOALIGNMENT) )
903 bFloatMode = !bFloatMode;
904 SetFloatingMode( bFloatMode );
905 if ( bFloatMode )
907 if ( !pImpl->aWinState.isEmpty() )
908 GetFloatingWindow()->SetWindowState( pImpl->aWinState );
909 else
910 GetFloatingWindow()->SetOutputSizePixel( GetFloatingSize() );
914 if ( IsFloatingMode() )
916 // validate last alignment
917 SfxChildAlignment eLastAlign = pImpl->GetLastAlignment();
918 if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
919 eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::LEFT);
920 if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
921 eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::RIGHT);
922 if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
923 eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::TOP);
924 if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
925 eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::BOTTOM);
926 pImpl->SetLastAlignment(eLastAlign);
928 else
930 // docked window must have NOALIGNMENT as last alignment
931 pImpl->SetLastAlignment(SfxChildAlignment::NOALIGNMENT);
933 pImpl->pSplitWin = pWorkWin->GetSplitWindow_Impl(GetAlignment());
934 pImpl->pSplitWin->InsertWindow(this, pImpl->aSplitSize);
937 // save alignment
938 pImpl->SetDockAlignment( GetAlignment() );
941 void SfxDockingWindow::Initialize_Impl()
943 if ( !pMgr )
945 pImpl->bConstructed = true;
946 return;
949 SystemWindow* pFloatWin = GetFloatingWindow();
950 bool bSet = false;
951 if ( pFloatWin )
953 bSet = !pFloatWin->IsDefaultPos();
955 else
957 Point aPos = GetFloatingPos();
958 if ( aPos != Point() )
959 bSet = true;
962 if ( !bSet)
964 SfxViewFrame *pFrame = pBindings->GetDispatcher_Impl()->GetFrame();
965 vcl::Window* pEditWin = pFrame->GetViewShell()->GetWindow();
966 Point aPos = pEditWin->OutputToScreenPixel( pEditWin->GetPosPixel() );
967 aPos = GetParent()->ScreenToOutputPixel( aPos );
968 SetFloatingPos( aPos );
971 if ( pFloatWin )
973 // initialize floating window
974 if ( pImpl->aWinState.isEmpty() )
975 // window state never set before, get if from defaults
976 pImpl->aWinState = pFloatWin->GetWindowState();
978 // trick: use VCL method SetWindowState to adjust position and size
979 pFloatWin->SetWindowState( pImpl->aWinState );
980 Size aSize(pFloatWin->GetSizePixel());
982 // remember floating size for calculating alignment and tracking rectangle
983 SetFloatingSize(aSize);
987 // allow calling of docking handlers
988 pImpl->bConstructed = true;
991 /** Fills a SfxChildWinInfo with specific data from SfxDockingWindow,
992 so that it can be written in the INI file. It is assumed that rinfo
993 receives all other possible relevant data in the ChildWindow class.
994 Insertions are marked with size and the ZoomIn flag.
995 If this method is overridden, the base implementation must be called first.
997 void SfxDockingWindow::FillInfo(SfxChildWinInfo& rInfo) const
999 if (!pMgr || !pImpl)
1000 return;
1002 if (GetFloatingWindow() && pImpl->bConstructed)
1003 pImpl->aWinState = GetFloatingWindow()->GetWindowState();
1005 rInfo.aWinState = pImpl->aWinState;
1006 rInfo.aExtraString = "AL:(";
1007 rInfo.aExtraString += OUString::number(static_cast<sal_uInt16>(GetAlignment()));
1008 rInfo.aExtraString += ",";
1009 rInfo.aExtraString += OUString::number (static_cast<sal_uInt16>(pImpl->GetLastAlignment()));
1011 Point aPos(pImpl->nLine, pImpl->nPos);
1012 rInfo.aExtraString += ",";
1013 rInfo.aExtraString += OUString::number( aPos.X() );
1014 rInfo.aExtraString += "/";
1015 rInfo.aExtraString += OUString::number( aPos.Y() );
1016 rInfo.aExtraString += "/";
1017 rInfo.aExtraString += OUString::number( pImpl->nHorizontalSize );
1018 rInfo.aExtraString += "/";
1019 rInfo.aExtraString += OUString::number( pImpl->nVerticalSize );
1020 rInfo.aExtraString += ",";
1021 rInfo.aExtraString += OUString::number( pImpl->aSplitSize.Width() );
1022 rInfo.aExtraString += ";";
1023 rInfo.aExtraString += OUString::number( pImpl->aSplitSize.Height() );
1025 rInfo.aExtraString += ")";
1028 SfxDockingWindow::~SfxDockingWindow()
1030 disposeOnce();
1033 void SfxDockingWindow::dispose()
1035 ReleaseChildWindow_Impl();
1036 pImpl.reset();
1037 m_xContainer.reset();
1038 m_xBuilder.reset();
1039 ResizableDockingWindow::dispose();
1042 void SfxDockingWindow::ReleaseChildWindow_Impl()
1044 if ( pMgr && pMgr->GetFrame() == pBindings->GetActiveFrame() )
1045 pBindings->SetActiveFrame( nullptr );
1047 if ( pMgr && pImpl->pSplitWin && pImpl->pSplitWin->IsItemValid( GetType() ) )
1048 pImpl->pSplitWin->RemoveWindow(this);
1050 pMgr=nullptr;
1053 /** This method calculates a resulting alignment for the given mouse position
1054 and tracking rectangle. When changing the alignment it can also be that
1055 the tracking rectangle is changed, so that an altered rectangle is
1056 returned. The user of this class can influence behaviour of this method,
1057 and thus the behavior of his DockinWindow class when docking where the
1058 called virtual method:
1060 SfxDockingWindow::CalcDockingSize (SfxChildAlignment eAlign)
1062 is overridden (see below).
1064 SfxChildAlignment SfxDockingWindow::CalcAlignment(const Point& rPos, tools::Rectangle& rRect)
1066 // calculate hypothetical sizes for different modes
1067 Size aFloatingSize(CalcDockingSize(SfxChildAlignment::NOALIGNMENT));
1069 // check if docking is permitted
1070 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
1071 if ( !pWorkWin->IsDockingAllowed() )
1073 rRect.SetSize( aFloatingSize );
1074 return pImpl->GetDockAlignment();
1077 // calculate borders to shrink inner area before checking for intersection with tracking rectangle
1078 tools::Long nLRBorder, nTBBorder;
1080 // take the smaller size of docked and floating mode
1081 Size aBorderTmp = pImpl->aSplitSize;
1082 if ( GetFloatingSize().Height() < aBorderTmp.Height() )
1083 aBorderTmp.setHeight( GetFloatingSize().Height() );
1084 if ( GetFloatingSize().Width() < aBorderTmp.Width() )
1085 aBorderTmp.setWidth( GetFloatingSize().Width() );
1087 nLRBorder = aBorderTmp.Width();
1088 nTBBorder = aBorderTmp.Height();
1090 // limit border to predefined constant values
1091 if ( nLRBorder > MAX_TOGGLEAREA_WIDTH )
1092 nLRBorder = MAX_TOGGLEAREA_WIDTH;
1093 if ( nTBBorder > MAX_TOGGLEAREA_WIDTH )
1094 nTBBorder = MAX_TOGGLEAREA_WIDTH;
1096 // shrink area for floating mode if possible
1097 tools::Rectangle aInRect = GetInnerRect();
1098 if ( aInRect.GetWidth() > nLRBorder )
1099 aInRect.AdjustLeft(nLRBorder/2 );
1100 if ( aInRect.GetWidth() > nLRBorder )
1101 aInRect.AdjustRight( -(nLRBorder/2) );
1102 if ( aInRect.GetHeight() > nTBBorder )
1103 aInRect.AdjustTop(nTBBorder/2 );
1104 if ( aInRect.GetHeight() > nTBBorder )
1105 aInRect.AdjustBottom( -(nTBBorder/2) );
1107 // calculate alignment resulting from docking rectangle
1108 bool bBecomesFloating = false;
1109 SfxChildAlignment eDockAlign = pImpl->GetDockAlignment();
1110 tools::Rectangle aDockingRect( rRect );
1111 if ( !IsFloatingMode() )
1113 // don't use tracking rectangle for alignment check, because it will be too large
1114 // to get a floating mode as result - switch to floating size
1115 // so the calculation only depends on the position of the rectangle, not the current
1116 // docking state of the window
1117 aDockingRect.SetSize( GetFloatingSize() );
1119 // in this mode docking is never done by keyboard, so it's OK to use the mouse position
1120 aDockingRect.SetPos( pWorkWin->GetWindow()->OutputToScreenPixel( pWorkWin->GetWindow()->GetPointerPosPixel() ) );
1123 Point aPos = aDockingRect.TopLeft();
1124 tools::Rectangle aIntersect = GetOuterRect().GetIntersection( aDockingRect );
1125 if ( aIntersect.IsEmpty() )
1126 // docking rectangle completely outside docking area -> floating mode
1127 bBecomesFloating = true;
1128 else
1130 // create a small test rect around the mouse position and use this one
1131 // instead of the passed rRect to not dock too easily or by accident
1132 tools::Rectangle aSmallDockingRect;
1133 aSmallDockingRect.SetSize( Size( MAX_TOGGLEAREA_WIDTH, MAX_TOGGLEAREA_HEIGHT ) );
1134 Point aNewPos(rPos);
1135 aNewPos.AdjustX( -(aSmallDockingRect.GetWidth()/2) );
1136 aNewPos.AdjustY( -(aSmallDockingRect.GetHeight()/2) );
1137 aSmallDockingRect.SetPos(aNewPos);
1138 tools::Rectangle aIntersectRect = aInRect.GetIntersection( aSmallDockingRect );
1139 if ( aIntersectRect == aSmallDockingRect )
1140 // docking rectangle completely inside (shrunk) inner area -> floating mode
1141 bBecomesFloating = true;
1144 if ( bBecomesFloating )
1146 eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::NOALIGNMENT);
1148 else
1150 // docking rectangle is in the "sensible area"
1151 Point aInPosTL( aPos.X()-aInRect.Left(), aPos.Y()-aInRect.Top() );
1152 Point aInPosBR( aPos.X()-aInRect.Left() + aDockingRect.GetWidth(), aPos.Y()-aInRect.Top() + aDockingRect.GetHeight() );
1153 Size aInSize = aInRect.GetSize();
1154 bool bNoChange = false;
1156 // check if alignment is still unchanged
1157 switch ( GetAlignment() )
1159 case SfxChildAlignment::LEFT:
1160 case SfxChildAlignment::FIRSTLEFT:
1161 case SfxChildAlignment::LASTLEFT:
1162 if (aInPosTL.X() <= 0)
1164 eDockAlign = GetAlignment();
1165 bNoChange = true;
1167 break;
1168 case SfxChildAlignment::TOP:
1169 case SfxChildAlignment::LOWESTTOP:
1170 case SfxChildAlignment::HIGHESTTOP:
1171 if ( aInPosTL.Y() <= 0)
1173 eDockAlign = GetAlignment();
1174 bNoChange = true;
1176 break;
1177 case SfxChildAlignment::RIGHT:
1178 case SfxChildAlignment::FIRSTRIGHT:
1179 case SfxChildAlignment::LASTRIGHT:
1180 if ( aInPosBR.X() >= aInSize.Width())
1182 eDockAlign = GetAlignment();
1183 bNoChange = true;
1185 break;
1186 case SfxChildAlignment::BOTTOM:
1187 case SfxChildAlignment::LOWESTBOTTOM:
1188 case SfxChildAlignment::HIGHESTBOTTOM:
1189 if ( aInPosBR.Y() >= aInSize.Height())
1191 eDockAlign = GetAlignment();
1192 bNoChange = true;
1194 break;
1195 default:
1196 break;
1199 if ( !bNoChange )
1201 // alignment will change, test alignment according to distance of the docking rectangles edges
1202 bool bForbidden = true;
1203 if ( aInPosTL.X() <= 0)
1205 eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::LEFT);
1206 bForbidden = ( eDockAlign != SfxChildAlignment::LEFT &&
1207 eDockAlign != SfxChildAlignment::FIRSTLEFT &&
1208 eDockAlign != SfxChildAlignment::LASTLEFT );
1211 if ( bForbidden && aInPosTL.Y() <= 0)
1213 eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::TOP);
1214 bForbidden = ( eDockAlign != SfxChildAlignment::TOP &&
1215 eDockAlign != SfxChildAlignment::HIGHESTTOP &&
1216 eDockAlign != SfxChildAlignment::LOWESTTOP );
1219 if ( bForbidden && aInPosBR.X() >= aInSize.Width())
1221 eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::RIGHT);
1222 bForbidden = ( eDockAlign != SfxChildAlignment::RIGHT &&
1223 eDockAlign != SfxChildAlignment::FIRSTRIGHT &&
1224 eDockAlign != SfxChildAlignment::LASTRIGHT );
1227 if ( bForbidden && aInPosBR.Y() >= aInSize.Height())
1229 eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::BOTTOM);
1230 bForbidden = ( eDockAlign != SfxChildAlignment::BOTTOM &&
1231 eDockAlign != SfxChildAlignment::HIGHESTBOTTOM &&
1232 eDockAlign != SfxChildAlignment::LOWESTBOTTOM );
1235 // the calculated alignment was rejected by the window -> take floating mode
1236 if ( bForbidden )
1237 eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::NOALIGNMENT);
1241 if ( eDockAlign == SfxChildAlignment::NOALIGNMENT )
1243 // In the FloatingMode the tracking rectangle will get the floating
1244 // size. Due to a bug the rRect may only be changed when the
1245 // alignment is changed!
1246 if ( eDockAlign != pImpl->GetDockAlignment() )
1247 aDockingRect.SetSize( aFloatingSize );
1249 else
1251 sal_uInt16 nLine, nPos;
1252 SfxSplitWindow *pSplitWin = pWorkWin->GetSplitWindow_Impl(eDockAlign);
1253 aPos = pSplitWin->ScreenToOutputPixel( aPos );
1254 if ( pSplitWin->GetWindowPos( aPos, nLine, nPos ) )
1256 // mouse over splitwindow, get line and position
1257 pImpl->nDockLine = nLine;
1258 pImpl->nDockPos = nPos;
1259 pImpl->bNewLine = false;
1261 else
1263 // mouse touches inner border -> create new line
1264 if ( eDockAlign == GetAlignment() && pImpl->pSplitWin &&
1265 pImpl->nLine == pImpl->pSplitWin->GetLineCount()-1 && pImpl->pSplitWin->GetWindowCount(pImpl->nLine) == 1 )
1267 // if this window is the only one in the last line, it can't be docked as new line in the same splitwindow
1268 pImpl->nDockLine = pImpl->nLine;
1269 pImpl->nDockPos = pImpl->nPos;
1270 pImpl->bNewLine = false;
1272 else
1274 // create new line
1275 pImpl->nDockLine = pSplitWin->GetLineCount();
1276 pImpl->nDockPos = 0;
1277 pImpl->bNewLine = true;
1281 bool bChanged = pImpl->nLine != pImpl->nDockLine || pImpl->nPos != pImpl->nDockPos || eDockAlign != GetAlignment();
1282 if ( !bChanged && !IsFloatingMode() )
1284 // window only slightly moved, no change of any property
1285 rRect.SetSize( pImpl->aSplitSize );
1286 rRect.SetPos( aDockingRect.TopLeft() );
1287 return eDockAlign;
1290 // calculate new size and position
1291 Size aSize;
1292 Point aPoint = aDockingRect.TopLeft();
1293 Size aInnerSize = GetInnerRect().GetSize();
1294 if ( eDockAlign == SfxChildAlignment::LEFT || eDockAlign == SfxChildAlignment::RIGHT )
1296 if ( pImpl->bNewLine )
1298 // set height to height of free area
1299 aSize.setHeight( aInnerSize.Height() );
1300 aSize.setWidth( pImpl->nHorizontalSize );
1301 if ( eDockAlign == SfxChildAlignment::LEFT )
1303 aPoint = aInnerRect.TopLeft();
1305 else
1307 aPoint = aInnerRect.TopRight();
1308 aPoint.AdjustX( -(aSize.Width()) );
1311 else
1313 // get width from splitwindow
1314 aSize.setWidth( pSplitWin->GetLineSize(nLine) );
1315 aSize.setHeight( pImpl->aSplitSize.Height() );
1318 else
1320 if ( pImpl->bNewLine )
1322 // set width to width of free area
1323 aSize.setWidth( aInnerSize.Width() );
1324 aSize.setHeight( pImpl->nVerticalSize );
1325 if ( eDockAlign == SfxChildAlignment::TOP )
1327 aPoint = aInnerRect.TopLeft();
1329 else
1331 aPoint = aInnerRect.BottomLeft();
1332 aPoint.AdjustY( -(aSize.Height()) );
1335 else
1337 // get height from splitwindow
1338 aSize.setHeight( pSplitWin->GetLineSize(nLine) );
1339 aSize.setWidth( pImpl->aSplitSize.Width() );
1343 aDockingRect.SetSize( aSize );
1344 aDockingRect.SetPos( aPoint );
1347 rRect = aDockingRect;
1348 return eDockAlign;
1351 /** Virtual method of the SfxDockingWindow class. This method determines how
1352 the size of the DockingWindows changes depending on the alignment. The base
1353 implementation uses the floating mode, the size of the marked Floating
1354 Size. For horizontal alignment, the width will be the width of the outer
1355 DockingRectangle, with vertical alignment the height will be the height of
1356 the inner DockingRectangle (resulting from the order in which the SFX child
1357 windows are displayed). The other size is set to the current floating-size,
1358 this could changed by a to intervening derived class. The docking size must
1359 be the same for Left/Right and Top/Bottom.
1361 Size SfxDockingWindow::CalcDockingSize(SfxChildAlignment eAlign)
1363 // Note: if the resizing is also possible in the docked state, then the
1364 // Floating-size does also have to be adjusted?
1366 Size aSize = GetFloatingSize();
1367 switch (eAlign)
1369 case SfxChildAlignment::TOP:
1370 case SfxChildAlignment::BOTTOM:
1371 case SfxChildAlignment::LOWESTTOP:
1372 case SfxChildAlignment::HIGHESTTOP:
1373 case SfxChildAlignment::LOWESTBOTTOM:
1374 case SfxChildAlignment::HIGHESTBOTTOM:
1375 aSize.setWidth( aOuterRect.Right() - aOuterRect.Left() );
1376 break;
1377 case SfxChildAlignment::LEFT:
1378 case SfxChildAlignment::RIGHT:
1379 case SfxChildAlignment::FIRSTLEFT:
1380 case SfxChildAlignment::LASTLEFT:
1381 case SfxChildAlignment::FIRSTRIGHT:
1382 case SfxChildAlignment::LASTRIGHT:
1383 aSize.setHeight( aInnerRect.Bottom() - aInnerRect.Top() );
1384 break;
1385 case SfxChildAlignment::NOALIGNMENT:
1386 break;
1387 default:
1388 break;
1391 return aSize;
1394 /** Virtual method of the SfxDockingWindow class. Here a derived class can
1395 disallow certain alignments. The base implementation does not
1396 prohibit alignment.
1398 SfxChildAlignment SfxDockingWindow::CheckAlignment(SfxChildAlignment,
1399 SfxChildAlignment eAlign)
1401 return eAlign;
1404 /** The window is closed when the ChildWindow is destroyed by running the
1405 ChildWindow-slots. If this is method is overridden by a derived class
1406 method, then the SfxDockingDialogWindow: Close() must be called afterwards
1407 if the Close() was not cancelled with "return sal_False".
1409 bool SfxDockingWindow::Close()
1411 // Execute with Parameters, since Toggle is ignored by some ChildWindows.
1412 if ( !pMgr )
1413 return true;
1415 SfxBoolItem aValue( pMgr->GetType(), false);
1416 pBindings->GetDispatcher_Impl()->ExecuteList(
1417 pMgr->GetType(), SfxCallMode::RECORD | SfxCallMode::ASYNCHRON,
1418 { &aValue });
1419 return true;
1422 void SfxDockingWindow::Paint(vcl::RenderContext&, const tools::Rectangle& /*rRect*/)
1426 /** With this method, a minimal OutputSize be can set, that is queried in
1427 the Resizing()-Handler.
1429 void SfxDockingWindow::SetMinOutputSizePixel( const Size& rSize )
1431 pImpl->aMinSize = rSize;
1432 ResizableDockingWindow::SetMinOutputSizePixel( rSize );
1435 /** Set the minimum size which is returned.*/
1436 const Size& SfxDockingWindow::GetMinOutputSizePixel() const
1438 return pImpl->aMinSize;
1441 bool SfxDockingWindow::EventNotify( NotifyEvent& rEvt )
1443 if ( !pImpl )
1444 return ResizableDockingWindow::EventNotify( rEvt );
1446 if ( rEvt.GetType() == NotifyEventType::GETFOCUS )
1448 if (pMgr != nullptr)
1449 pBindings->SetActiveFrame( pMgr->GetFrame() );
1451 if ( pImpl->pSplitWin )
1452 pImpl->pSplitWin->SetActiveWindow_Impl( this );
1453 else if (pMgr != nullptr)
1454 pMgr->Activate_Impl();
1456 // In VCL EventNotify goes first to the window itself, also call the
1457 // base class, otherwise the parent learns nothing
1458 // if ( rEvt.GetWindow() == this ) PB: #i74693# not necessary any longer
1459 ResizableDockingWindow::EventNotify( rEvt );
1460 // tdf#151112 move focus into container widget hierarchy if not already there
1461 if (m_xContainer && !m_xContainer->has_child_focus())
1462 m_xContainer->child_grab_focus();
1463 return true;
1465 else if( rEvt.GetType() == NotifyEventType::KEYINPUT )
1467 // First, allow KeyInput for Dialog functions
1468 if (!DockingWindow::EventNotify(rEvt) && SfxViewShell::Current())
1470 // then also for valid global accelerators.
1471 return SfxViewShell::Current()->GlobalKeyInput_Impl( *rEvt.GetKeyEvent() );
1473 return true;
1475 else if ( rEvt.GetType() == NotifyEventType::LOSEFOCUS && !HasChildPathFocus() )
1477 pBindings->SetActiveFrame( nullptr );
1480 return ResizableDockingWindow::EventNotify( rEvt );
1483 void SfxDockingWindow::SetItemSize_Impl( const Size& rSize )
1485 pImpl->aSplitSize = rSize;
1487 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
1488 pWorkWin->ConfigChild_Impl( SfxChildIdentifier::SPLITWINDOW, SfxDockingConfig::ALIGNDOCKINGWINDOW, pMgr->GetType() );
1491 void SfxDockingWindow::Disappear_Impl()
1493 if ( pImpl->pSplitWin && pImpl->pSplitWin->IsItemValid( GetType() ) )
1494 pImpl->pSplitWin->RemoveWindow(this);
1497 void SfxDockingWindow::Reappear_Impl()
1499 if ( pImpl->pSplitWin && !pImpl->pSplitWin->IsItemValid( GetType() ) )
1501 pImpl->pSplitWin->InsertWindow( this, pImpl->aSplitSize );
1505 bool SfxDockingWindow::IsAutoHide_Impl() const
1507 if ( pImpl->pSplitWin )
1508 return !pImpl->pSplitWin->IsFadeIn();
1509 else
1510 return false;
1513 void SfxDockingWindow::AutoShow_Impl()
1515 if ( pImpl->pSplitWin )
1517 pImpl->pSplitWin->FadeIn();
1521 void SfxDockingWindow::StateChanged( StateChangedType nStateChange )
1523 if ( nStateChange == StateChangedType::InitShow )
1524 Initialize_Impl();
1526 ResizableDockingWindow::StateChanged( nStateChange );
1529 void SfxDockingWindow::Move()
1531 if ( pImpl )
1532 pImpl->aMoveIdle.Start();
1535 IMPL_LINK_NOARG(SfxDockingWindow, TimerHdl, Timer *, void)
1537 pImpl->aMoveIdle.Stop();
1538 if ( IsReallyVisible() && IsFloatingMode() )
1540 SetFloatingSize( GetOutputSizePixel() );
1541 pImpl->aWinState = GetFloatingWindow()->GetWindowState();
1542 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
1543 pWorkWin->ConfigChild_Impl( SfxChildIdentifier::SPLITWINDOW, SfxDockingConfig::ALIGNDOCKINGWINDOW, pMgr->GetType() );
1547 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */