nss: upgrade to release 3.73
[LibreOffice.git] / sfx2 / source / dialog / dockwin.cxx
blob24e9b527385d69f218b86286f4a412ebed5e9368
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/layout.hxx>
24 #include <vcl/settings.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/timer.hxx>
28 #include <vcl/idle.hxx>
29 #include <o3tl/safeint.hxx>
30 #include <osl/diagnose.h>
31 #include <rtl/instance.hxx>
32 #include <toolkit/helper/vclunohelper.hxx>
33 #include <tools/debug.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <comphelper/propertysequence.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 | WB_ROLLABLE);
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 auto pFact = std::make_unique<SfxChildWinFactory>( SfxDockingWrapper::CreateImpl, nID, 0xffff );
221 pFact->aInfo.nFlags |= nFlags;
222 pFact->aInfo.bVisible = bVis;
223 SfxChildWindow::RegisterChildWindow(pMod, std::move(pFact));
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 namespace
294 struct ChildrenRegisteredMap : public rtl::Static< bool, ChildrenRegisteredMap > {};
297 static bool lcl_checkDockingWindowID( sal_uInt16 nID )
299 return nID >= SID_DOCKWIN_START && nID < o3tl::make_unsigned(SID_DOCKWIN_START+NUM_OF_DOCKINGWINDOWS);
302 static SfxWorkWindow* lcl_getWorkWindowFromXFrame( const uno::Reference< frame::XFrame >& rFrame )
304 // We need to find the corresponding SfxFrame of our XFrame
305 SfxFrame* pFrame = SfxFrame::GetFirst();
306 SfxFrame* pXFrame = nullptr;
307 while ( pFrame )
309 uno::Reference< frame::XFrame > xViewShellFrame( pFrame->GetFrameInterface() );
310 if ( xViewShellFrame == rFrame )
312 pXFrame = pFrame;
313 break;
315 else
316 pFrame = SfxFrame::GetNext( *pFrame );
319 // If we have a SfxFrame we can retrieve the work window (Sfx layout manager for docking windows)
320 if ( pXFrame )
321 return pXFrame->GetWorkWindow_Impl();
322 else
323 return nullptr;
326 /** Factory function used by the framework layout manager to "create" a docking window with a special name.
327 The string rDockingWindowName MUST BE a valid ID! The ID is pre-defined by a certain slot range located
328 in sfxsids.hrc (currently SID_DOCKWIN_START = 9800).
330 void SfxDockingWindowFactory( const uno::Reference< frame::XFrame >& rFrame, const OUString& rDockingWindowName )
332 SolarMutexGuard aGuard;
333 sal_uInt16 nID = sal_uInt16(rDockingWindowName.toInt32());
335 // Check the range of the provided ID otherwise nothing will happen
336 if ( !lcl_checkDockingWindowID( nID ))
337 return;
339 SfxWorkWindow* pWorkWindow = lcl_getWorkWindowFromXFrame( rFrame );
340 if ( pWorkWindow )
342 SfxChildWindow* pChildWindow = pWorkWindow->GetChildWindow_Impl(nID);
343 if ( !pChildWindow )
345 // Register window at the workwindow child window list
346 pWorkWindow->SetChildWindow_Impl( nID, true, false );
351 /** Function used by the framework layout manager to determine the visibility state of a docking window with
352 a special name. The string rDockingWindowName MUST BE a valid ID! The ID is pre-defined by a certain slot
353 range located in sfxsids.hrc (currently SID_DOCKWIN_START = 9800).
355 bool IsDockingWindowVisible( const uno::Reference< frame::XFrame >& rFrame, const OUString& rDockingWindowName )
357 SolarMutexGuard aGuard;
359 sal_uInt16 nID = sal_uInt16(rDockingWindowName.toInt32());
361 // Check the range of the provided ID otherwise nothing will happen
362 if ( lcl_checkDockingWindowID( nID ))
364 SfxWorkWindow* pWorkWindow = lcl_getWorkWindowFromXFrame( rFrame );
365 if ( pWorkWindow )
367 SfxChildWindow* pChildWindow = pWorkWindow->GetChildWindow_Impl(nID);
368 if ( pChildWindow )
369 return true;
373 return false;
376 class SfxDockingWindow_Impl
378 friend class SfxDockingWindow;
380 SfxChildAlignment eLastAlignment;
381 SfxChildAlignment eDockAlignment;
382 bool bConstructed;
383 Size aMinSize;
384 VclPtr<SfxSplitWindow> pSplitWin;
385 Idle aMoveIdle;
387 // The following members are only valid in the time from startDocking to
388 // EndDocking:
389 Size aSplitSize;
390 tools::Long nHorizontalSize;
391 tools::Long nVerticalSize;
392 sal_uInt16 nLine;
393 sal_uInt16 nPos;
394 sal_uInt16 nDockLine;
395 sal_uInt16 nDockPos;
396 bool bNewLine;
397 bool bDockingPrevented;
398 OString aWinState;
400 explicit SfxDockingWindow_Impl(SfxDockingWindow *pBase);
401 SfxChildAlignment GetLastAlignment() const
402 { return eLastAlignment; }
403 void SetLastAlignment(SfxChildAlignment eAlign)
404 { eLastAlignment = eAlign; }
405 SfxChildAlignment GetDockAlignment() const
406 { return eDockAlignment; }
407 void SetDockAlignment(SfxChildAlignment eAlign)
408 { eDockAlignment = eAlign; }
411 SfxDockingWindow_Impl::SfxDockingWindow_Impl(SfxDockingWindow* pBase)
412 :eLastAlignment(SfxChildAlignment::NOALIGNMENT)
413 ,eDockAlignment(SfxChildAlignment::NOALIGNMENT)
414 ,bConstructed(false)
415 ,pSplitWin(nullptr)
416 ,nHorizontalSize(0)
417 ,nVerticalSize(0)
418 ,nLine(0)
419 ,nPos(0)
420 ,nDockLine(0)
421 ,nDockPos(0)
422 ,bNewLine(false)
423 ,bDockingPrevented(false)
425 aMoveIdle.SetPriority(TaskPriority::RESIZE);
426 aMoveIdle.SetInvokeHandler(LINK(pBase,SfxDockingWindow,TimerHdl));
427 aMoveIdle.SetDebugName( "sfx::SfxDockingWindow_Impl aMoveIdle" );
430 /* [Description]
432 This virtual method of the class FloatingWindow keeps track of changes in
433 FloatingSize. If this method is overridden by a derived class,
434 then the FloatingWindow: Resize() must also be called.
436 void SfxDockingWindow::Resize()
438 DockingWindow::Resize();
439 Invalidate();
440 if ( !pImpl || !pImpl->bConstructed || !pMgr )
441 return;
443 if ( IsFloatingMode() )
445 // start timer for saving window status information
446 pImpl->aMoveIdle.Start();
448 else
450 Size aSize( GetSizePixel() );
451 switch ( pImpl->GetDockAlignment() )
453 case SfxChildAlignment::LEFT:
454 case SfxChildAlignment::FIRSTLEFT:
455 case SfxChildAlignment::LASTLEFT:
456 case SfxChildAlignment::RIGHT:
457 case SfxChildAlignment::FIRSTRIGHT:
458 case SfxChildAlignment::LASTRIGHT:
459 pImpl->nHorizontalSize = aSize.Width();
460 pImpl->aSplitSize = aSize;
461 break;
462 case SfxChildAlignment::TOP:
463 case SfxChildAlignment::LOWESTTOP:
464 case SfxChildAlignment::HIGHESTTOP:
465 case SfxChildAlignment::BOTTOM:
466 case SfxChildAlignment::HIGHESTBOTTOM:
467 case SfxChildAlignment::LOWESTBOTTOM:
468 pImpl->nVerticalSize = aSize.Height();
469 pImpl->aSplitSize = aSize;
470 break;
471 default:
472 break;
477 /* [Description]
479 This virtual method of the class DockingWindow makes it possible to
480 intervene in the switching of the floating mode.
481 If this method is overridden by a derived class,
482 then the SfxDockingWindow::PrepareToggleFloatingMode() must be called
483 afterwards, if not FALSE is returned.
485 bool SfxDockingWindow::PrepareToggleFloatingMode()
487 if (!pImpl || !pImpl->bConstructed)
488 return true;
490 if ( (Application::IsInModalMode() && IsFloatingMode()) || !pMgr )
491 return false;
493 if ( pImpl->bDockingPrevented )
494 return false;
496 if (!IsFloatingMode())
498 // Test, if FloatingMode is permitted.
499 if ( CheckAlignment(GetAlignment(),SfxChildAlignment::NOALIGNMENT) != SfxChildAlignment::NOALIGNMENT )
500 return false;
502 if ( pImpl->pSplitWin )
504 // The DockingWindow is inside a SplitWindow and will be teared of.
505 pImpl->pSplitWin->RemoveWindow(this/*, sal_False*/);
506 pImpl->pSplitWin = nullptr;
509 else if ( pMgr )
511 pImpl->aWinState = GetFloatingWindow()->GetWindowState();
513 // Test if it is allowed to dock,
514 if (CheckAlignment(GetAlignment(),pImpl->GetLastAlignment()) == SfxChildAlignment::NOALIGNMENT)
515 return false;
517 // Test, if the Workwindow allows for docking at the moment.
518 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
519 if ( !pWorkWin->IsDockingAllowed() || !pWorkWin->IsInternalDockingAllowed() )
520 return false;
523 return true;
526 /* [Description]
528 This virtual method of the DockingWindow class sets the internal data of
529 the SfxDockingWindow and ensures the correct alignment on the parent window.
530 Through PrepareToggleFloatMode and Initialize it is ensured that
531 pImpl-> GetLastAlignment() always delivers an allowed alignment. If this
532 method is overridden by a derived class, then first the
533 SfxDockingWindow::ToggleFloatingMode() must be called.
535 void SfxDockingWindow::ToggleFloatingMode()
537 if ( !pImpl || !pImpl->bConstructed || !pMgr )
538 return; // No Handler call
540 // Remember old alignment and then switch.
541 // SV has already switched, but the alignment SfxDockingWindow is still
542 // the old one. What I was before?
543 SfxChildAlignment eLastAlign = GetAlignment();
545 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
547 if (IsFloatingMode())
549 SetAlignment(SfxChildAlignment::NOALIGNMENT);
550 if ( !pImpl->aWinState.isEmpty() )
551 GetFloatingWindow()->SetWindowState( pImpl->aWinState );
552 else
553 GetFloatingWindow()->SetOutputSizePixel( GetFloatingSize() );
555 else
557 if (pImpl->GetDockAlignment() == eLastAlign)
559 // If ToggleFloatingMode was called, but the DockAlignment still
560 // is unchanged, then this means that it must have been a toggling
561 // through DClick, so use last alignment
562 SetAlignment (pImpl->GetLastAlignment());
564 else
567 // Toggling was triggered by dragging
568 pImpl->nLine = pImpl->nDockLine;
569 pImpl->nPos = pImpl->nDockPos;
570 SetAlignment (pImpl->GetDockAlignment());
573 // The DockingWindow is now in a SplitWindow
574 pImpl->pSplitWin = pWorkWin->GetSplitWindow_Impl(GetAlignment());
576 // The LastAlignment is still the last docked
577 SfxSplitWindow *pSplit = pWorkWin->GetSplitWindow_Impl(pImpl->GetLastAlignment());
579 DBG_ASSERT( pSplit, "LastAlignment is not correct!" );
580 if ( pSplit && pSplit != pImpl->pSplitWin )
581 pSplit->ReleaseWindow_Impl(this);
582 if ( pImpl->GetDockAlignment() == eLastAlign )
583 pImpl->pSplitWin->InsertWindow( this, pImpl->aSplitSize );
584 else
585 pImpl->pSplitWin->InsertWindow( this, pImpl->aSplitSize, pImpl->nLine, pImpl->nPos, pImpl->bNewLine );
586 if ( !pImpl->pSplitWin->IsFadeIn() )
587 pImpl->pSplitWin->FadeIn();
590 // Keep the old alignment for the next toggle; set it only now due to the
591 // unregister SplitWindow!
592 pImpl->SetLastAlignment(eLastAlign);
594 // Reset DockAlignment, if EndDocking is still called
595 pImpl->SetDockAlignment(GetAlignment());
597 // Dock or undock SfxChildWindow correctly.
598 pWorkWin->ConfigChild_Impl( SfxChildIdentifier::SPLITWINDOW, SfxDockingConfig::TOGGLEFLOATMODE, pMgr->GetType() );
601 /* [Description]
603 This virtual method of the DockingWindow class takes the inner and outer
604 docking rectangle from the parent window. If this method is overridden by
605 a derived class, then SfxDockingWindow:StartDocking() has to be called at
606 the end.
608 void SfxDockingWindow::StartDocking()
610 if ( !pImpl || !pImpl->bConstructed || !pMgr )
611 return;
612 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
613 pWorkWin->ConfigChild_Impl( SfxChildIdentifier::SPLITWINDOW, SfxDockingConfig::SETDOCKINGRECTS, pMgr->GetType() );
614 pImpl->SetDockAlignment(GetAlignment());
616 if ( pImpl->pSplitWin )
618 // Get the current docking data
619 pImpl->pSplitWin->GetWindowPos(this, pImpl->nLine, pImpl->nPos);
620 pImpl->nDockLine = pImpl->nLine;
621 pImpl->nDockPos = pImpl->nPos;
622 pImpl->bNewLine = false;
626 /* [Description]
628 This virtual method of the DockingWindow class calculates the current
629 tracking rectangle. For this purpose the method CalcAlignment(RPOs, rRect)
630 is used, the behavior can be influenced by the derived classes (see below).
631 This method should if possible not be overwritten.
633 bool SfxDockingWindow::Docking( const Point& rPos, tools::Rectangle& rRect )
635 if ( Application::IsInModalMode() )
636 return true;
638 if ( !pImpl || !pImpl->bConstructed || !pMgr )
640 rRect.SetSize( Size() );
641 return IsFloatingMode();
644 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
645 if ( pImpl->bDockingPrevented || !pWorkWin->IsInternalDockingAllowed() )
646 return false;
648 bool bFloatMode = false;
650 if ( GetOuterRect().IsInside( rPos ) )
652 // Mouse within OuterRect: calculate Alignment and Rectangle
653 SfxChildAlignment eAlign = CalcAlignment(rPos, rRect);
654 if (eAlign == SfxChildAlignment::NOALIGNMENT)
655 bFloatMode = true;
656 pImpl->SetDockAlignment(eAlign);
658 else
660 // Mouse is not within OuterRect: must be FloatingWindow
661 // Is this allowed?
662 if (CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::NOALIGNMENT) != SfxChildAlignment::NOALIGNMENT)
663 return false;
664 bFloatMode = true;
665 if ( SfxChildAlignment::NOALIGNMENT != pImpl->GetDockAlignment() )
667 // Due to a bug the rRect may only be changed when the
668 // alignment is changed!
669 pImpl->SetDockAlignment(SfxChildAlignment::NOALIGNMENT);
670 rRect.SetSize(CalcDockingSize(SfxChildAlignment::NOALIGNMENT));
674 return bFloatMode;
677 /** Virtual method of the DockingWindow class ensures the correct alignment on
678 the parent window. If this method is overridden by a derived class, then
679 SfxDockingWindow::EndDocking() must be called first.
681 void SfxDockingWindow::EndDocking( const tools::Rectangle& rRect, bool bFloatMode )
683 if ( !pImpl || !pImpl->bConstructed || IsDockingCanceled() || !pMgr )
684 return;
686 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
688 // If the alignment changes and the window is in a docked state in a
689 // SplitWindow, then it must be re-registered. If it is docked again,
690 // PrepareToggleFloatingMode() and ToggleFloatingMode() perform the
691 // re-registered
692 bool bReArrange = !bFloatMode;
694 if ( bReArrange )
696 if ( GetAlignment() != pImpl->GetDockAlignment() )
698 // before Show() is called must the reassignment have been made,
699 // therefore the base class can not be called
700 if ( IsFloatingMode() )
701 Show( false, ShowFlags::NoFocusChange );
703 // Set the size for toggling.
704 pImpl->aSplitSize = rRect.GetSize();
705 if ( IsFloatingMode() )
707 SetFloatingMode( bFloatMode );
708 if ( IsFloatingMode() )
709 Show( true, ShowFlags::NoFocusChange );
711 else
713 pImpl->pSplitWin->RemoveWindow(this,false);
714 pImpl->nLine = pImpl->nDockLine;
715 pImpl->nPos = pImpl->nDockPos;
716 pImpl->pSplitWin->ReleaseWindow_Impl(this);
717 pImpl->pSplitWin = pWorkWin->GetSplitWindow_Impl(pImpl->GetDockAlignment());
718 pImpl->pSplitWin->InsertWindow( this, pImpl->aSplitSize, pImpl->nDockLine, pImpl->nDockPos, pImpl->bNewLine );
719 if ( !pImpl->pSplitWin->IsFadeIn() )
720 pImpl->pSplitWin->FadeIn();
723 else if ( pImpl->nLine != pImpl->nDockLine || pImpl->nPos != pImpl->nDockPos || pImpl->bNewLine )
725 // Moved within Splitwindows
726 if ( pImpl->nLine != pImpl->nDockLine )
727 pImpl->aSplitSize = rRect.GetSize();
728 pImpl->pSplitWin->MoveWindow( this, pImpl->aSplitSize, pImpl->nDockLine, pImpl->nDockPos, pImpl->bNewLine );
731 else
733 DockingWindow::EndDocking(rRect, bFloatMode);
736 SetAlignment( IsFloatingMode() ? SfxChildAlignment::NOALIGNMENT : pImpl->GetDockAlignment() );
739 /* [Description]
741 Virtual method of the DockingWindow class. Here, the interactive resize in
742 FloatingMode can be influenced, for example by only allowing for discrete
743 values for width and / or height. The base implementation prevents that the
744 output size is smaller than one set with SetMinOutputSizePixel().
746 void SfxDockingWindow::Resizing( Size& /*rSize*/ )
751 /* [Description]
753 Constructor for the SfxDockingWindow class. A SfxChildWindow will be
754 required because the docking is implemented in Sfx through SfxChildWindows.
756 SfxDockingWindow::SfxDockingWindow( SfxBindings *pBindinx, SfxChildWindow *pCW,
757 vcl::Window* pParent, WinBits nWinBits) :
758 DockingWindow (pParent, nWinBits),
759 pBindings(pBindinx),
760 pMgr(pCW)
762 pImpl.reset(new SfxDockingWindow_Impl(this));
765 /** Constructor for the SfxDockingWindow class. A SfxChildWindow will be
766 required because the docking is implemented in Sfx through SfxChildWindows.
768 SfxDockingWindow::SfxDockingWindow( SfxBindings *pBindinx, SfxChildWindow *pCW,
769 vcl::Window* pParent, const OString& rID, const OUString& rUIXMLDescription)
770 : DockingWindow(pParent, "DockingWindow", "sfx/ui/dockingwindow.ui")
771 , pBindings(pBindinx)
772 , pMgr(pCW)
774 m_xVclContentArea = VclPtr<VclVBox>::Create(this);
775 m_xVclContentArea->Show();
776 m_xBuilder.reset(Application::CreateInterimBuilder(m_xVclContentArea, rUIXMLDescription, true));
777 m_xContainer = m_xBuilder->weld_container(rID);
779 pImpl.reset(new SfxDockingWindow_Impl(this));
782 /** Initialization of the SfxDockingDialog class via a SfxChildWinInfo.
783 The initialization is done only in a 2nd step after the constructor, this
784 constructor should be called from the derived class or from the
785 SfxChildWindows.
787 void SfxDockingWindow::Initialize(SfxChildWinInfo *pInfo)
789 if ( !pMgr )
791 pImpl->SetDockAlignment( SfxChildAlignment::NOALIGNMENT );
792 pImpl->bConstructed = true;
793 return;
796 if (pInfo && (pInfo->nFlags & SfxChildWindowFlags::FORCEDOCK))
797 pImpl->bDockingPrevented = true;
799 pImpl->aSplitSize = GetOutputSizePixel();
800 if ( !GetFloatingSize().Width() )
802 Size aMinSize( GetMinOutputSizePixel() );
803 SetFloatingSize( pImpl->aSplitSize );
804 if ( pImpl->aSplitSize.Width() < aMinSize.Width() )
805 pImpl->aSplitSize.setWidth( aMinSize.Width() );
806 if ( pImpl->aSplitSize.Height() < aMinSize.Height() )
807 pImpl->aSplitSize.setHeight( aMinSize.Height() );
810 bool bVertHorzRead( false );
811 if (pInfo && !pInfo->aExtraString.isEmpty())
813 // get information about alignment, split size and position in SplitWindow
814 OUString aStr;
815 sal_Int32 nPos = pInfo->aExtraString.indexOf("AL:");
816 if ( nPos != -1 )
818 // alignment information
819 sal_Int32 n1 = pInfo->aExtraString.indexOf('(', nPos);
820 if ( n1 != -1 )
822 sal_Int32 n2 = pInfo->aExtraString.indexOf(')', n1);
823 if ( n2 != -1 )
825 // extract alignment information from extrastring
826 aStr = pInfo->aExtraString.copy(nPos, n2 - nPos + 1);
827 pInfo->aExtraString = pInfo->aExtraString.replaceAt(nPos, n2 - nPos + 1, "");
828 aStr = aStr.replaceAt(nPos, n1-nPos+1, "");
833 if ( !aStr.isEmpty() )
835 // accept window state only if alignment is also set
836 pImpl->aWinState = pInfo->aWinState;
838 // check for valid alignment
839 SfxChildAlignment eLocalAlignment = static_cast<SfxChildAlignment>(static_cast<sal_uInt16>(aStr.toInt32()));
840 bool bIgnoreFloatConfig = (eLocalAlignment == SfxChildAlignment::NOALIGNMENT &&
841 !StyleSettings::GetDockingFloatsSupported());
842 if (pImpl->bDockingPrevented || bIgnoreFloatConfig)
843 // docking prevented, ignore old configuration and take alignment from default
844 aStr.clear();
845 else
846 SetAlignment( eLocalAlignment );
848 SfxChildAlignment eAlign = CheckAlignment(GetAlignment(),GetAlignment());
849 if ( eAlign != GetAlignment() )
851 OSL_FAIL("Invalid Alignment!");
852 SetAlignment( eAlign );
853 aStr.clear();
856 // get last alignment (for toggling)
857 nPos = aStr.indexOf(',');
858 if ( nPos != -1 )
860 aStr = aStr.copy(nPos+1);
861 pImpl->SetLastAlignment( static_cast<SfxChildAlignment>(static_cast<sal_uInt16>(aStr.toInt32())) );
864 nPos = aStr.indexOf(',');
865 if ( nPos != -1 )
867 // get split size and position in SplitWindow
868 Point aPos;
869 aStr = aStr.copy(nPos+1);
870 if ( GetPosSizeFromString( aStr, aPos, pImpl->aSplitSize ) )
872 pImpl->nLine = pImpl->nDockLine = static_cast<sal_uInt16>(aPos.X());
873 pImpl->nPos = pImpl->nDockPos = static_cast<sal_uInt16>(aPos.Y());
874 pImpl->nVerticalSize = pImpl->aSplitSize.Height();
875 pImpl->nHorizontalSize = pImpl->aSplitSize.Width();
876 if ( GetSplitSizeFromString( aStr, pImpl->aSplitSize ))
877 bVertHorzRead = true;
881 else {
882 OSL_FAIL( "Information is missing!" );
886 if ( !bVertHorzRead )
888 pImpl->nVerticalSize = pImpl->aSplitSize.Height();
889 pImpl->nHorizontalSize = pImpl->aSplitSize.Width();
892 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
893 if ( GetAlignment() != SfxChildAlignment::NOALIGNMENT )
895 // check if SfxWorkWindow is able to allow docking at its border
896 if (
897 !pWorkWin->IsDockingAllowed() ||
898 !pWorkWin->IsInternalDockingAllowed() ||
899 ( (GetFloatStyle() & WB_STANDALONE) && Application::IsInModalMode()) )
901 SetAlignment( SfxChildAlignment::NOALIGNMENT );
905 // detect floating mode
906 // toggling mode will not execute code in handlers, because pImpl->bConstructed is not set yet
907 bool bFloatMode = IsFloatingMode();
908 if ( bFloatMode != (GetAlignment() == SfxChildAlignment::NOALIGNMENT) )
910 bFloatMode = !bFloatMode;
911 SetFloatingMode( bFloatMode );
912 if ( bFloatMode )
914 if ( !pImpl->aWinState.isEmpty() )
915 GetFloatingWindow()->SetWindowState( pImpl->aWinState );
916 else
917 GetFloatingWindow()->SetOutputSizePixel( GetFloatingSize() );
921 if ( IsFloatingMode() )
923 // validate last alignment
924 SfxChildAlignment eLastAlign = pImpl->GetLastAlignment();
925 if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
926 eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::LEFT);
927 if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
928 eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::RIGHT);
929 if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
930 eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::TOP);
931 if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
932 eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::BOTTOM);
933 pImpl->SetLastAlignment(eLastAlign);
935 else
937 // docked window must have NOALIGNMENT as last alignment
938 pImpl->SetLastAlignment(SfxChildAlignment::NOALIGNMENT);
940 pImpl->pSplitWin = pWorkWin->GetSplitWindow_Impl(GetAlignment());
941 pImpl->pSplitWin->InsertWindow(this, pImpl->aSplitSize);
944 // save alignment
945 pImpl->SetDockAlignment( GetAlignment() );
948 void SfxDockingWindow::Initialize_Impl()
950 if ( !pMgr )
952 pImpl->bConstructed = true;
953 return;
956 FloatingWindow* pFloatWin = GetFloatingWindow();
957 bool bSet = false;
958 if ( pFloatWin )
960 bSet = !pFloatWin->IsDefaultPos();
962 else
964 Point aPos = GetFloatingPos();
965 if ( aPos != Point() )
966 bSet = true;
969 if ( !bSet)
971 SfxViewFrame *pFrame = pBindings->GetDispatcher_Impl()->GetFrame();
972 vcl::Window* pEditWin = pFrame->GetViewShell()->GetWindow();
973 Point aPos = pEditWin->OutputToScreenPixel( pEditWin->GetPosPixel() );
974 aPos = GetParent()->ScreenToOutputPixel( aPos );
975 SetFloatingPos( aPos );
978 if ( pFloatWin )
980 // initialize floating window
981 if ( pImpl->aWinState.isEmpty() )
982 // window state never set before, get if from defaults
983 pImpl->aWinState = pFloatWin->GetWindowState();
985 // trick: use VCL method SetWindowState to adjust position and size
986 pFloatWin->SetWindowState( pImpl->aWinState );
987 Size aSize(pFloatWin->GetSizePixel());
989 // remember floating size for calculating alignment and tracking rectangle
990 SetFloatingSize(aSize);
994 // allow calling of docking handlers
995 pImpl->bConstructed = true;
998 /** Fills a SfxChildWinInfo with specific data from SfxDockingWindow,
999 so that it can be written in the INI file. It is assumed that rinfo
1000 receives all other possible relevant data in the ChildWindow class.
1001 Insertions are marked with size and the ZoomIn flag.
1002 If this method is overridden, the base implementation must be called first.
1004 void SfxDockingWindow::FillInfo(SfxChildWinInfo& rInfo) const
1006 if (!pMgr || !pImpl)
1007 return;
1009 if (GetFloatingWindow() && pImpl->bConstructed)
1010 pImpl->aWinState = GetFloatingWindow()->GetWindowState();
1012 rInfo.aWinState = pImpl->aWinState;
1013 rInfo.aExtraString = "AL:(";
1014 rInfo.aExtraString += OUString::number(static_cast<sal_uInt16>(GetAlignment()));
1015 rInfo.aExtraString += ",";
1016 rInfo.aExtraString += OUString::number (static_cast<sal_uInt16>(pImpl->GetLastAlignment()));
1018 Point aPos(pImpl->nLine, pImpl->nPos);
1019 rInfo.aExtraString += ",";
1020 rInfo.aExtraString += OUString::number( aPos.X() );
1021 rInfo.aExtraString += "/";
1022 rInfo.aExtraString += OUString::number( aPos.Y() );
1023 rInfo.aExtraString += "/";
1024 rInfo.aExtraString += OUString::number( pImpl->nHorizontalSize );
1025 rInfo.aExtraString += "/";
1026 rInfo.aExtraString += OUString::number( pImpl->nVerticalSize );
1027 rInfo.aExtraString += ",";
1028 rInfo.aExtraString += OUString::number( pImpl->aSplitSize.Width() );
1029 rInfo.aExtraString += ";";
1030 rInfo.aExtraString += OUString::number( pImpl->aSplitSize.Height() );
1032 rInfo.aExtraString += ")";
1035 SfxDockingWindow::~SfxDockingWindow()
1037 disposeOnce();
1040 void SfxDockingWindow::dispose()
1042 ReleaseChildWindow_Impl();
1043 pImpl.reset();
1044 m_xContainer.reset();
1045 m_xBuilder.reset();
1046 m_xVclContentArea.disposeAndClear();
1047 DockingWindow::dispose();
1050 void SfxDockingWindow::ReleaseChildWindow_Impl()
1052 if ( pMgr && pMgr->GetFrame() == pBindings->GetActiveFrame() )
1053 pBindings->SetActiveFrame( nullptr );
1055 if ( pMgr && pImpl->pSplitWin && pImpl->pSplitWin->IsItemValid( GetType() ) )
1056 pImpl->pSplitWin->RemoveWindow(this);
1058 pMgr=nullptr;
1061 /** This method calculates a resulting alignment for the given mouse position
1062 and tracking rectangle. When changing the alignment it can also be that
1063 the tracking rectangle is changed, so that an altered rectangle is
1064 returned. The user of this class can influence behaviour of this method,
1065 and thus the behavior of his DockinWindow class when docking where the
1066 called virtual method:
1068 SfxDockingWindow::CalcDockingSize (SfxChildAlignment eAlign)
1070 is overridden (see below).
1072 SfxChildAlignment SfxDockingWindow::CalcAlignment(const Point& rPos, tools::Rectangle& rRect)
1074 // calculate hypothetical sizes for different modes
1075 Size aFloatingSize(CalcDockingSize(SfxChildAlignment::NOALIGNMENT));
1077 // check if docking is permitted
1078 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
1079 if ( !pWorkWin->IsDockingAllowed() )
1081 rRect.SetSize( aFloatingSize );
1082 return pImpl->GetDockAlignment();
1085 // calculate borders to shrink inner area before checking for intersection with tracking rectangle
1086 tools::Long nLRBorder, nTBBorder;
1088 // take the smaller size of docked and floating mode
1089 Size aBorderTmp = pImpl->aSplitSize;
1090 if ( GetFloatingSize().Height() < aBorderTmp.Height() )
1091 aBorderTmp.setHeight( GetFloatingSize().Height() );
1092 if ( GetFloatingSize().Width() < aBorderTmp.Width() )
1093 aBorderTmp.setWidth( GetFloatingSize().Width() );
1095 nLRBorder = aBorderTmp.Width();
1096 nTBBorder = aBorderTmp.Height();
1098 // limit border to predefined constant values
1099 if ( nLRBorder > MAX_TOGGLEAREA_WIDTH )
1100 nLRBorder = MAX_TOGGLEAREA_WIDTH;
1101 if ( nTBBorder > MAX_TOGGLEAREA_WIDTH )
1102 nTBBorder = MAX_TOGGLEAREA_WIDTH;
1104 // shrink area for floating mode if possible
1105 tools::Rectangle aInRect = GetInnerRect();
1106 if ( aInRect.GetWidth() > nLRBorder )
1107 aInRect.AdjustLeft(nLRBorder/2 );
1108 if ( aInRect.GetWidth() > nLRBorder )
1109 aInRect.AdjustRight( -(nLRBorder/2) );
1110 if ( aInRect.GetHeight() > nTBBorder )
1111 aInRect.AdjustTop(nTBBorder/2 );
1112 if ( aInRect.GetHeight() > nTBBorder )
1113 aInRect.AdjustBottom( -(nTBBorder/2) );
1115 // calculate alignment resulting from docking rectangle
1116 bool bBecomesFloating = false;
1117 SfxChildAlignment eDockAlign = pImpl->GetDockAlignment();
1118 tools::Rectangle aDockingRect( rRect );
1119 if ( !IsFloatingMode() )
1121 // don't use tracking rectangle for alignment check, because it will be too large
1122 // to get a floating mode as result - switch to floating size
1123 // so the calculation only depends on the position of the rectangle, not the current
1124 // docking state of the window
1125 aDockingRect.SetSize( GetFloatingSize() );
1127 // in this mode docking is never done by keyboard, so it's OK to use the mouse position
1128 aDockingRect.SetPos( pWorkWin->GetWindow()->OutputToScreenPixel( pWorkWin->GetWindow()->GetPointerPosPixel() ) );
1131 Point aPos = aDockingRect.TopLeft();
1132 tools::Rectangle aIntersect = GetOuterRect().GetIntersection( aDockingRect );
1133 if ( aIntersect.IsEmpty() )
1134 // docking rectangle completely outside docking area -> floating mode
1135 bBecomesFloating = true;
1136 else
1138 // create a small test rect around the mouse position and use this one
1139 // instead of the passed rRect to not dock too easily or by accident
1140 tools::Rectangle aSmallDockingRect;
1141 aSmallDockingRect.SetSize( Size( MAX_TOGGLEAREA_WIDTH, MAX_TOGGLEAREA_HEIGHT ) );
1142 Point aNewPos(rPos);
1143 aNewPos.AdjustX( -(aSmallDockingRect.GetWidth()/2) );
1144 aNewPos.AdjustY( -(aSmallDockingRect.GetHeight()/2) );
1145 aSmallDockingRect.SetPos(aNewPos);
1146 tools::Rectangle aIntersectRect = aInRect.GetIntersection( aSmallDockingRect );
1147 if ( aIntersectRect == aSmallDockingRect )
1148 // docking rectangle completely inside (shrunk) inner area -> floating mode
1149 bBecomesFloating = true;
1152 if ( bBecomesFloating )
1154 eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::NOALIGNMENT);
1156 else
1158 // docking rectangle is in the "sensible area"
1159 Point aInPosTL( aPos.X()-aInRect.Left(), aPos.Y()-aInRect.Top() );
1160 Point aInPosBR( aPos.X()-aInRect.Left() + aDockingRect.GetWidth(), aPos.Y()-aInRect.Top() + aDockingRect.GetHeight() );
1161 Size aInSize = aInRect.GetSize();
1162 bool bNoChange = false;
1164 // check if alignment is still unchanged
1165 switch ( GetAlignment() )
1167 case SfxChildAlignment::LEFT:
1168 case SfxChildAlignment::FIRSTLEFT:
1169 case SfxChildAlignment::LASTLEFT:
1170 if (aInPosTL.X() <= 0)
1172 eDockAlign = GetAlignment();
1173 bNoChange = true;
1175 break;
1176 case SfxChildAlignment::TOP:
1177 case SfxChildAlignment::LOWESTTOP:
1178 case SfxChildAlignment::HIGHESTTOP:
1179 if ( aInPosTL.Y() <= 0)
1181 eDockAlign = GetAlignment();
1182 bNoChange = true;
1184 break;
1185 case SfxChildAlignment::RIGHT:
1186 case SfxChildAlignment::FIRSTRIGHT:
1187 case SfxChildAlignment::LASTRIGHT:
1188 if ( aInPosBR.X() >= aInSize.Width())
1190 eDockAlign = GetAlignment();
1191 bNoChange = true;
1193 break;
1194 case SfxChildAlignment::BOTTOM:
1195 case SfxChildAlignment::LOWESTBOTTOM:
1196 case SfxChildAlignment::HIGHESTBOTTOM:
1197 if ( aInPosBR.Y() >= aInSize.Height())
1199 eDockAlign = GetAlignment();
1200 bNoChange = true;
1202 break;
1203 default:
1204 break;
1207 if ( !bNoChange )
1209 // alignment will change, test alignment according to distance of the docking rectangles edges
1210 bool bForbidden = true;
1211 if ( aInPosTL.X() <= 0)
1213 eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::LEFT);
1214 bForbidden = ( eDockAlign != SfxChildAlignment::LEFT &&
1215 eDockAlign != SfxChildAlignment::FIRSTLEFT &&
1216 eDockAlign != SfxChildAlignment::LASTLEFT );
1219 if ( bForbidden && aInPosTL.Y() <= 0)
1221 eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::TOP);
1222 bForbidden = ( eDockAlign != SfxChildAlignment::TOP &&
1223 eDockAlign != SfxChildAlignment::HIGHESTTOP &&
1224 eDockAlign != SfxChildAlignment::LOWESTTOP );
1227 if ( bForbidden && aInPosBR.X() >= aInSize.Width())
1229 eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::RIGHT);
1230 bForbidden = ( eDockAlign != SfxChildAlignment::RIGHT &&
1231 eDockAlign != SfxChildAlignment::FIRSTRIGHT &&
1232 eDockAlign != SfxChildAlignment::LASTRIGHT );
1235 if ( bForbidden && aInPosBR.Y() >= aInSize.Height())
1237 eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::BOTTOM);
1238 bForbidden = ( eDockAlign != SfxChildAlignment::BOTTOM &&
1239 eDockAlign != SfxChildAlignment::HIGHESTBOTTOM &&
1240 eDockAlign != SfxChildAlignment::LOWESTBOTTOM );
1243 // the calculated alignment was rejected by the window -> take floating mode
1244 if ( bForbidden )
1245 eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::NOALIGNMENT);
1249 if ( eDockAlign == SfxChildAlignment::NOALIGNMENT )
1251 // In the FloatingMode the tracking rectangle will get the floating
1252 // size. Due to a bug the rRect may only be changed when the
1253 // alignment is changed!
1254 if ( eDockAlign != pImpl->GetDockAlignment() )
1255 aDockingRect.SetSize( aFloatingSize );
1257 else
1259 sal_uInt16 nLine, nPos;
1260 SfxSplitWindow *pSplitWin = pWorkWin->GetSplitWindow_Impl(eDockAlign);
1261 aPos = pSplitWin->ScreenToOutputPixel( aPos );
1262 if ( pSplitWin->GetWindowPos( aPos, nLine, nPos ) )
1264 // mouse over splitwindow, get line and position
1265 pImpl->nDockLine = nLine;
1266 pImpl->nDockPos = nPos;
1267 pImpl->bNewLine = false;
1269 else
1271 // mouse touches inner border -> create new line
1272 if ( eDockAlign == GetAlignment() && pImpl->pSplitWin &&
1273 pImpl->nLine == pImpl->pSplitWin->GetLineCount()-1 && pImpl->pSplitWin->GetWindowCount(pImpl->nLine) == 1 )
1275 // if this window is the only one in the last line, it can't be docked as new line in the same splitwindow
1276 pImpl->nDockLine = pImpl->nLine;
1277 pImpl->nDockPos = pImpl->nPos;
1278 pImpl->bNewLine = false;
1280 else
1282 // create new line
1283 pImpl->nDockLine = pSplitWin->GetLineCount();
1284 pImpl->nDockPos = 0;
1285 pImpl->bNewLine = true;
1289 bool bChanged = pImpl->nLine != pImpl->nDockLine || pImpl->nPos != pImpl->nDockPos || eDockAlign != GetAlignment();
1290 if ( !bChanged && !IsFloatingMode() )
1292 // window only slightly moved, no change of any property
1293 rRect.SetSize( pImpl->aSplitSize );
1294 rRect.SetPos( aDockingRect.TopLeft() );
1295 return eDockAlign;
1298 // calculate new size and position
1299 Size aSize;
1300 Point aPoint = aDockingRect.TopLeft();
1301 Size aInnerSize = GetInnerRect().GetSize();
1302 if ( eDockAlign == SfxChildAlignment::LEFT || eDockAlign == SfxChildAlignment::RIGHT )
1304 if ( pImpl->bNewLine )
1306 // set height to height of free area
1307 aSize.setHeight( aInnerSize.Height() );
1308 aSize.setWidth( pImpl->nHorizontalSize );
1309 if ( eDockAlign == SfxChildAlignment::LEFT )
1311 aPoint = aInnerRect.TopLeft();
1313 else
1315 aPoint = aInnerRect.TopRight();
1316 aPoint.AdjustX( -(aSize.Width()) );
1319 else
1321 // get width from splitwindow
1322 aSize.setWidth( pSplitWin->GetLineSize(nLine) );
1323 aSize.setHeight( pImpl->aSplitSize.Height() );
1326 else
1328 if ( pImpl->bNewLine )
1330 // set width to width of free area
1331 aSize.setWidth( aInnerSize.Width() );
1332 aSize.setHeight( pImpl->nVerticalSize );
1333 if ( eDockAlign == SfxChildAlignment::TOP )
1335 aPoint = aInnerRect.TopLeft();
1337 else
1339 aPoint = aInnerRect.BottomLeft();
1340 aPoint.AdjustY( -(aSize.Height()) );
1343 else
1345 // get height from splitwindow
1346 aSize.setHeight( pSplitWin->GetLineSize(nLine) );
1347 aSize.setWidth( pImpl->aSplitSize.Width() );
1351 aDockingRect.SetSize( aSize );
1352 aDockingRect.SetPos( aPoint );
1355 rRect = aDockingRect;
1356 return eDockAlign;
1359 /** Virtual method of the SfxDockingWindow class. This method determines how
1360 the size of the DockingWindows changes depending on the alignment. The base
1361 implementation uses the floating mode, the size of the marked Floating
1362 Size. For horizontal alignment, the width will be the width of the outer
1363 DockingRectangle, with vertical alignment the height will be the height of
1364 the inner DockingRectangle (resulting from the order in which the SFX child
1365 windows are displayed). The other size is set to the current floating-size,
1366 this could changed by a to intervening derived class. The docking size must
1367 be the same for Left/Right and Top/Bottom.
1369 Size SfxDockingWindow::CalcDockingSize(SfxChildAlignment eAlign)
1371 // Note: if the resizing is also possible in the docked state, then the
1372 // Floating-size does also have to be adjusted?
1374 Size aSize = GetFloatingSize();
1375 switch (eAlign)
1377 case SfxChildAlignment::TOP:
1378 case SfxChildAlignment::BOTTOM:
1379 case SfxChildAlignment::LOWESTTOP:
1380 case SfxChildAlignment::HIGHESTTOP:
1381 case SfxChildAlignment::LOWESTBOTTOM:
1382 case SfxChildAlignment::HIGHESTBOTTOM:
1383 aSize.setWidth( aOuterRect.Right() - aOuterRect.Left() );
1384 break;
1385 case SfxChildAlignment::LEFT:
1386 case SfxChildAlignment::RIGHT:
1387 case SfxChildAlignment::FIRSTLEFT:
1388 case SfxChildAlignment::LASTLEFT:
1389 case SfxChildAlignment::FIRSTRIGHT:
1390 case SfxChildAlignment::LASTRIGHT:
1391 aSize.setHeight( aInnerRect.Bottom() - aInnerRect.Top() );
1392 break;
1393 case SfxChildAlignment::NOALIGNMENT:
1394 break;
1395 default:
1396 break;
1399 return aSize;
1402 /** Virtual method of the SfxDockingWindow class. Here a derived class can
1403 disallow certain alignments. The base implementation does not
1404 prohibit alignment.
1406 SfxChildAlignment SfxDockingWindow::CheckAlignment(SfxChildAlignment,
1407 SfxChildAlignment eAlign)
1409 return eAlign;
1412 /** The window is closed when the ChildWindow is destroyed by running the
1413 ChildWindow-slots. If this is method is overridden by a derived class
1414 method, then the SfxDockingDialogWindow: Close() must be called afterwards
1415 if the Close() was not cancelled with "return sal_False".
1417 bool SfxDockingWindow::Close()
1419 // Execute with Parameters, since Toggle is ignored by some ChildWindows.
1420 if ( !pMgr )
1421 return true;
1423 SfxBoolItem aValue( pMgr->GetType(), false);
1424 pBindings->GetDispatcher_Impl()->ExecuteList(
1425 pMgr->GetType(), SfxCallMode::RECORD | SfxCallMode::ASYNCHRON,
1426 { &aValue });
1427 return true;
1430 void SfxDockingWindow::Paint(vcl::RenderContext&, const tools::Rectangle& /*rRect*/)
1434 /** With this method, a minimal OutputSize be can set, that is queried in
1435 the Resizing()-Handler.
1437 void SfxDockingWindow::SetMinOutputSizePixel( const Size& rSize )
1439 pImpl->aMinSize = rSize;
1440 DockingWindow::SetMinOutputSizePixel( rSize );
1443 /** Set the minimum size which is returned.*/
1444 const Size& SfxDockingWindow::GetMinOutputSizePixel() const
1446 return pImpl->aMinSize;
1449 bool SfxDockingWindow::EventNotify( NotifyEvent& rEvt )
1451 if ( !pImpl )
1452 return DockingWindow::EventNotify( rEvt );
1454 if ( rEvt.GetType() == MouseNotifyEvent::GETFOCUS )
1456 if (pMgr != nullptr)
1457 pBindings->SetActiveFrame( pMgr->GetFrame() );
1459 if ( pImpl->pSplitWin )
1460 pImpl->pSplitWin->SetActiveWindow_Impl( this );
1461 else if (pMgr != nullptr)
1462 pMgr->Activate_Impl();
1464 // In VCL EventNotify goes first to the window itself, also call the
1465 // base class, otherwise the parent learns nothing
1466 // if ( rEvt.GetWindow() == this ) PB: #i74693# not necessary any longer
1467 DockingWindow::EventNotify( rEvt );
1468 return true;
1470 else if( rEvt.GetType() == MouseNotifyEvent::KEYINPUT )
1472 // First, allow KeyInput for Dialog functions
1473 if (!DockingWindow::EventNotify(rEvt) && SfxViewShell::Current())
1475 // then also for valid global accelerators.
1476 return SfxViewShell::Current()->GlobalKeyInput_Impl( *rEvt.GetKeyEvent() );
1478 return true;
1480 else if ( rEvt.GetType() == MouseNotifyEvent::LOSEFOCUS && !HasChildPathFocus() )
1482 pBindings->SetActiveFrame( nullptr );
1485 return DockingWindow::EventNotify( rEvt );
1489 void SfxDockingWindow::SetItemSize_Impl( const Size& rSize )
1491 pImpl->aSplitSize = rSize;
1493 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
1494 pWorkWin->ConfigChild_Impl( SfxChildIdentifier::SPLITWINDOW, SfxDockingConfig::ALIGNDOCKINGWINDOW, pMgr->GetType() );
1497 void SfxDockingWindow::Disappear_Impl()
1499 if ( pImpl->pSplitWin && pImpl->pSplitWin->IsItemValid( GetType() ) )
1500 pImpl->pSplitWin->RemoveWindow(this);
1503 void SfxDockingWindow::Reappear_Impl()
1505 if ( pImpl->pSplitWin && !pImpl->pSplitWin->IsItemValid( GetType() ) )
1507 pImpl->pSplitWin->InsertWindow( this, pImpl->aSplitSize );
1511 bool SfxDockingWindow::IsAutoHide_Impl() const
1513 if ( pImpl->pSplitWin )
1514 return !pImpl->pSplitWin->IsFadeIn();
1515 else
1516 return false;
1519 void SfxDockingWindow::AutoShow_Impl()
1521 if ( pImpl->pSplitWin )
1523 pImpl->pSplitWin->FadeIn();
1527 void SfxDockingWindow::StateChanged( StateChangedType nStateChange )
1529 if ( nStateChange == StateChangedType::InitShow )
1530 Initialize_Impl();
1532 DockingWindow::StateChanged( nStateChange );
1535 void SfxDockingWindow::Move()
1537 if ( pImpl )
1538 pImpl->aMoveIdle.Start();
1541 IMPL_LINK_NOARG(SfxDockingWindow, TimerHdl, Timer *, void)
1543 pImpl->aMoveIdle.Stop();
1544 if ( IsReallyVisible() && IsFloatingMode() )
1546 if( !GetFloatingWindow()->IsRollUp() )
1547 SetFloatingSize( GetOutputSizePixel() );
1548 pImpl->aWinState = GetFloatingWindow()->GetWindowState();
1549 SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
1550 pWorkWin->ConfigChild_Impl( SfxChildIdentifier::SPLITWINDOW, SfxDockingConfig::ALIGNDOCKINGWINDOW, pMgr->GetType() );
1554 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */