Use COMReference to handle COM pointers in CreateShortcut
[LibreOffice.git] / sfx2 / source / dialog / splitwin.cxx
blobfcdb5a5488174335b86574fe63da04e1a82bb344
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 #ifdef __sun
21 #include <ctime>
22 #endif
24 #include <unotools/viewoptions.hxx>
25 #include <rtl/ustrbuf.hxx>
26 #include <sal/log.hxx>
27 #include <tools/debug.hxx>
29 #include <vcl/dialoghelper.hxx>
30 #include <vcl/event.hxx>
31 #include <vcl/timer.hxx>
32 #include <vcl/svapp.hxx>
34 #include <splitwin.hxx>
35 #include <workwin.hxx>
36 #include <sfx2/dockwin.hxx>
37 #include <o3tl/string_view.hxx>
39 #include <cassert>
40 #include <memory>
41 #include <vector>
42 #include <utility>
44 using namespace ::com::sun::star::uno;
46 #define VERSION 1
47 #define nPixel 30L
48 constexpr OUString USERITEM_NAME = u"UserItem"_ustr;
50 namespace {
51 // helper class to deactivate UpdateMode, if needed, for the life time of an instance
52 class DeactivateUpdateMode
54 public:
55 explicit DeactivateUpdateMode( SfxSplitWindow& rSplitWindow )
56 : mrSplitWindow( rSplitWindow )
57 , mbUpdateMode( rSplitWindow.IsUpdateMode() )
59 if ( mbUpdateMode )
61 mrSplitWindow.SetUpdateMode( false );
65 ~DeactivateUpdateMode()
67 if ( mbUpdateMode )
69 mrSplitWindow.SetUpdateMode( true );
73 private:
74 SfxSplitWindow& mrSplitWindow;
75 const bool mbUpdateMode;
79 class SfxEmptySplitWin_Impl : public SplitWindow
81 /* [Description]
83 The SfxEmptySplitWin_Impldow is an empty SplitWindow, that replaces the
84 SfxSplitWindow AutoHide mode. It only serves as a placeholder to receive
85 mouse moves and if possible blend in the true SplitWindow display.
87 friend class SfxSplitWindow;
89 VclPtr<SfxSplitWindow> pOwner;
90 bool bFadeIn;
91 bool bAutoHide;
92 bool bSplit;
93 bool bEndAutoHide;
94 Timer aTimer;
95 Point aLastPos;
96 sal_uInt16 nState;
98 public:
99 explicit SfxEmptySplitWin_Impl( SfxSplitWindow *pParent )
100 : SplitWindow( pParent->GetParent(), WinBits( WB_BORDER | WB_3DLOOK ) )
101 , pOwner( pParent )
102 , bFadeIn( false )
103 , bAutoHide( false )
104 , bSplit( false )
105 , bEndAutoHide( false )
106 , aTimer("sfx2 SfxEmptySplitWin_Impl aTimer")
107 , nState( 1 )
109 aTimer.SetInvokeHandler(
110 LINK(pOwner, SfxSplitWindow, TimerHdl ) );
111 aTimer.SetTimeout( 200 );
112 SetAlign( pOwner->GetAlign() );
113 Actualize();
114 ShowFadeInHideButton();
117 virtual ~SfxEmptySplitWin_Impl() override
118 { disposeOnce(); }
119 virtual void dispose() override
121 aTimer.Stop();
122 pOwner.clear();
123 SplitWindow::dispose();
126 virtual void FadeIn() override;
127 void Actualize();
130 void SfxEmptySplitWin_Impl::Actualize()
132 Size aSize( pOwner->GetSizePixel() );
133 switch ( pOwner->GetAlign() )
135 case WindowAlign::Left:
136 case WindowAlign::Right:
137 aSize.setWidth( GetFadeInSize() );
138 break;
139 case WindowAlign::Top:
140 case WindowAlign::Bottom:
141 aSize.setHeight( GetFadeInSize() );
142 break;
145 SetSizePixel( aSize );
148 void SfxEmptySplitWin_Impl::FadeIn()
150 if (!bAutoHide )
151 bAutoHide = IsFadeNoButtonMode();
152 pOwner->SetFadeIn_Impl( true );
153 if ( bAutoHide )
155 // Set Timer to close; the caller has to ensure themselves that the
156 // Window is not closed instantly (eg by setting the focus or a modal
157 // mode.
158 aLastPos = GetPointerPosPixel();
159 aTimer.Start();
161 else
162 pOwner->SaveConfig_Impl();
166 void SfxSplitWindow::MouseButtonDown( const MouseEvent& rMEvt )
168 if ( rMEvt.GetClicks() != 2 )
169 SplitWindow::MouseButtonDown( rMEvt );
172 SfxSplitWindow::SfxSplitWindow( vcl::Window* pParent, SfxChildAlignment eAl,
173 SfxWorkWindow *pW, bool bWithButtons )
175 /* [Description]
177 A SfxSplitWindow brings the recursive structure of the SV-SplitWindows to
178 the outside by simulating a table-like structure with rows and columns
179 (maximum recursion depth 2). Furthermore, it ensures the persistence of
180 the arrangement of the SfxDockingWindows.
183 : SplitWindow ( pParent, WB_BORDER | WB_SIZEABLE | WB_3DLOOK | WB_HIDE ),
184 eAlign(eAl),
185 pWorkWin(pW),
186 bPinned(true),
187 pEmptyWin(nullptr),
188 pActive(nullptr)
190 if (bWithButtons)
192 ShowFadeOutButton();
195 // Set SV-Alignment
196 WindowAlign eTbxAlign;
197 switch ( eAlign )
199 case SfxChildAlignment::LEFT:
200 eTbxAlign = WindowAlign::Left;
201 break;
202 case SfxChildAlignment::RIGHT:
203 eTbxAlign = WindowAlign::Right;
204 break;
205 case SfxChildAlignment::TOP:
206 eTbxAlign = WindowAlign::Top;
207 break;
208 case SfxChildAlignment::BOTTOM:
209 eTbxAlign = WindowAlign::Bottom;
210 bPinned = true;
211 break;
212 default:
213 eTbxAlign = WindowAlign::Top; // some sort of default...
214 break; // -Wall lots not handled...
217 SetAlign (eTbxAlign);
218 pEmptyWin = VclPtr<SfxEmptySplitWin_Impl>::Create( this );
219 if ( bPinned )
221 pEmptyWin->bFadeIn = true;
222 pEmptyWin->nState = 2;
225 if ( bWithButtons )
227 // Read Configuration
228 const OUString aWindowId{ "SplitWindow" + OUString::number(static_cast<sal_Int32>(eTbxAlign)) };
229 SvtViewOptions aWinOpt( EViewType::Window, aWindowId );
230 OUString aWinData;
231 Any aUserItem = aWinOpt.GetUserItem( USERITEM_NAME );
232 OUString aTemp;
233 if ( aUserItem >>= aTemp )
234 aWinData = aTemp;
235 if ( aWinData.startsWith("V") )
237 sal_Int32 nIdx{ 0 };
238 pEmptyWin->nState = static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(aWinData, 1, ',', nIdx )));
239 if ( pEmptyWin->nState & 2 )
240 pEmptyWin->bFadeIn = true;
241 bPinned = true; // always assume pinned - floating mode not used anymore
243 const sal_Int32 nCount{ o3tl::toInt32(o3tl::getToken(aWinData, 0, ',', nIdx)) };
244 for ( sal_Int32 n=0; n<nCount; ++n )
246 std::unique_ptr<SfxDock_Impl> pDock(new SfxDock_Impl);
247 pDock->pWin = nullptr;
248 pDock->bNewLine = false;
249 pDock->bHide = true;
250 pDock->nType = static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(aWinData, 0, ',', nIdx)));
251 if ( !pDock->nType )
253 // could mean NewLine
254 pDock->nType = static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(aWinData, 0, ',', nIdx)));
255 if ( !pDock->nType )
257 // Read error
258 break;
260 else
261 pDock->bNewLine = true;
264 maDockArr.insert(maDockArr.begin() + n, std::move(pDock));
268 else
270 bPinned = true;
271 pEmptyWin->bFadeIn = true;
272 pEmptyWin->nState = 2;
277 SfxSplitWindow::~SfxSplitWindow()
279 disposeOnce();
282 void SfxSplitWindow::dispose()
284 SaveConfig_Impl();
286 if ( pEmptyWin )
288 // Set pOwner to NULL, otherwise try to delete pEmptyWin once more. The
289 // window that is just being docked is always deleted from the outside.
290 pEmptyWin->pOwner = nullptr;
292 pEmptyWin.disposeAndClear();
294 maDockArr.clear();
295 pActive.clear();
296 SplitWindow::dispose();
299 void SfxSplitWindow::SaveConfig_Impl()
301 // Save configuration
302 OUStringBuffer aWinData =
304 + OUString::number(static_cast<sal_Int32>(VERSION))
305 + ","
306 + OUString::number(static_cast<sal_Int32>(pEmptyWin->nState))
307 + ",";
309 sal_uInt16 nCount = 0;
310 for ( auto const & rDock: maDockArr )
312 if ( rDock->bHide || rDock->pWin )
313 nCount++;
316 aWinData.append(static_cast<sal_Int32>(nCount));
318 for ( auto const & rDock: maDockArr )
320 if ( !rDock->bHide && !rDock->pWin )
321 continue;
322 if ( rDock->bNewLine )
323 aWinData.append(",0");
324 aWinData.append("," + OUString::number(static_cast<sal_Int32>(rDock->nType)));
327 const OUString aWindowId{ "SplitWindow" + OUString::number(static_cast<sal_Int32>(GetAlign())) };
328 SvtViewOptions aWinOpt( EViewType::Window, aWindowId );
329 aWinOpt.SetUserItem( USERITEM_NAME, Any( aWinData.makeStringAndClear() ) );
333 void SfxSplitWindow::StartSplit()
335 tools::Long nSize = 0;
336 Size aSize = GetSizePixel();
338 if ( pEmptyWin )
340 pEmptyWin->bFadeIn = true;
341 pEmptyWin->bSplit = true;
344 tools::Rectangle aRect = pWorkWin->GetFreeArea( !bPinned );
345 switch ( GetAlign() )
347 case WindowAlign::Left:
348 case WindowAlign::Right:
349 nSize = aSize.Width() + aRect.GetWidth();
350 break;
351 case WindowAlign::Top:
352 case WindowAlign::Bottom:
353 nSize = aSize.Height() + aRect.GetHeight();
354 break;
357 SetMaxSizePixel( nSize );
361 void SfxSplitWindow::SplitResize()
363 if ( bPinned )
365 pWorkWin->ArrangeChildren_Impl();
366 pWorkWin->ShowChildren_Impl();
368 else
369 pWorkWin->ArrangeAutoHideWindows( this );
373 void SfxSplitWindow::Split()
375 if ( pEmptyWin )
376 pEmptyWin->bSplit = false;
378 SplitWindow::Split();
380 std::vector< std::pair< sal_uInt16, tools::Long > > aNewOrgSizes;
382 sal_uInt16 nCount = maDockArr.size();
383 for ( sal_uInt16 n=0; n<nCount; n++ )
385 const SfxDock_Impl& rD = *maDockArr[n];
386 if ( rD.pWin )
388 const sal_uInt16 nId = rD.nType;
389 const tools::Long nSize = GetItemSize( nId, SplitWindowItemFlags::Fixed );
390 const tools::Long nSetSize = GetItemSize( GetSet( nId ) );
391 Size aSize;
393 if ( IsHorizontal() )
395 aSize.setWidth( nSize );
396 aSize.setHeight( nSetSize );
398 else
400 aSize.setWidth( nSetSize );
401 aSize.setHeight( nSize );
404 rD.pWin->SetItemSize_Impl( aSize );
406 aNewOrgSizes.emplace_back( nId, nSize );
410 // workaround insufficiency of <SplitWindow> regarding dock layouting:
411 // apply FIXED item size as 'original' item size to improve layouting of undock-dock-cycle of a window
413 DeactivateUpdateMode aDeactivateUpdateMode( *this );
414 for (const std::pair< sal_uInt16, tools::Long > & rNewOrgSize : aNewOrgSizes)
416 SetItemSize( rNewOrgSize.first, rNewOrgSize.second );
420 SaveConfig_Impl();
424 void SfxSplitWindow::InsertWindow( SfxDockingWindow* pDockWin, const Size& rSize)
427 To insert SfxDockingWindows just pass no position. The SfxSplitWindow
428 searches the last marked one to the passed SfxDockingWindow or appends a
429 new one at the end.
432 short nLine = -1; // so that the first window cab set nline to 0
433 sal_uInt16 nPos = 0;
434 bool bNewLine = true;
435 bool bSaveConfig = false;
436 SfxDock_Impl *pFoundDock=nullptr;
437 sal_uInt16 nCount = maDockArr.size();
438 for ( sal_uInt16 n=0; n<nCount; n++ )
440 SfxDock_Impl& rDock = *maDockArr[n];
441 if ( rDock.bNewLine )
443 // The window opens a new line
444 if ( pFoundDock )
445 // But after the just inserted window
446 break;
448 // New line
449 nPos = 0;
450 bNewLine = true;
453 if ( rDock.pWin )
455 // Does there exist a window now at this position
456 if ( bNewLine && !pFoundDock )
458 // Not known until now in which real line it is located
459 sal_uInt16 nL = 0;
460 [[maybe_unused]] auto const ok = GetWindowPos( rDock.pWin, nL, nPos );
461 assert(ok);
462 nLine = static_cast<short>(nL);
465 if ( !pFoundDock )
467 // The window is located before the inserted one
468 nPos++;
471 // Line is opened
472 bNewLine = false;
473 if ( pFoundDock )
474 break;
477 if ( rDock.nType == pDockWin->GetType() )
479 DBG_ASSERT( !pFoundDock && !rDock.pWin, "Window already exists!");
480 pFoundDock = &rDock;
481 if ( !bNewLine )
482 break;
483 else
485 // A new line has been created but no window was found there;
486 // continue searching for a window in this line in-order to set
487 // bNewLine correctly. While doing so nline or nPos are not
488 // to be changed!
489 nLine++;
494 if ( !pFoundDock )
496 // Not found, insert at end
497 pFoundDock = new SfxDock_Impl;
498 pFoundDock->bHide = true;
499 maDockArr.push_back( std::unique_ptr<SfxDock_Impl>(pFoundDock) );
500 pFoundDock->nType = pDockWin->GetType();
501 nLine++;
502 nPos = 0;
503 bNewLine = true;
504 pFoundDock->bNewLine = bNewLine;
505 bSaveConfig = true;
508 pFoundDock->pWin = pDockWin;
509 pFoundDock->bHide = false;
510 InsertWindow_Impl( pFoundDock, rSize, nLine, nPos, bNewLine );
511 if ( bSaveConfig )
512 SaveConfig_Impl();
516 void SfxSplitWindow::ReleaseWindow_Impl(SfxDockingWindow const *pDockWin, bool bSave)
518 // The docking window is no longer stored in the internal data.
519 sal_uInt16 nCount = maDockArr.size();
520 for ( sal_uInt16 n=0; n<nCount; n++ )
522 const SfxDock_Impl& rDock = *maDockArr[n];
523 if ( rDock.nType == pDockWin->GetType() )
525 if ( rDock.bNewLine && n<nCount-1 )
526 maDockArr[n+1]->bNewLine = true;
528 // Window has a position, this we forget
529 maDockArr.erase(maDockArr.begin() + n);
530 break;
534 if ( bSave )
535 SaveConfig_Impl();
539 void SfxSplitWindow::MoveWindow( SfxDockingWindow* pDockWin, const Size& rSize,
540 sal_uInt16 nLine, sal_uInt16 nPos, bool bNewLine)
542 /* [Description]
544 The docking window is moved within the SplitWindows.
548 sal_uInt16 nL = 0;
549 sal_uInt16 nP = 0;
550 [[maybe_unused]] auto const ok = GetWindowPos( pDockWin, nL, nP );
551 assert(ok);
553 if ( nLine > nL && GetItemCount( GetItemId( nL ) ) == 1 )
555 // If the last window is removed from its line, then everything slips
556 // one line to the front!
557 nLine--;
559 RemoveWindow( pDockWin );
560 InsertWindow( pDockWin, rSize, nLine, nPos, bNewLine );
564 void SfxSplitWindow::InsertWindow( SfxDockingWindow* pDockWin, const Size& rSize,
565 sal_uInt16 nLine, sal_uInt16 nPos, bool bNewLine)
567 /* [Description]
569 The DockingWindow that is pushed on this SplitWindow and shall hold the
570 given position and size.
573 ReleaseWindow_Impl( pDockWin, false );
574 SfxDock_Impl *pDock = new SfxDock_Impl;
575 pDock->bHide = false;
576 pDock->nType = pDockWin->GetType();
577 pDock->bNewLine = bNewLine;
578 pDock->pWin = pDockWin;
580 DBG_ASSERT( nPos==0 || !bNewLine, "Wrong Parameter!");
581 if ( bNewLine )
582 nPos = 0;
584 // The window must be inserted before the first window so that it has the
585 // same or a greater position than pDockWin.
586 sal_uInt16 nCount = maDockArr.size();
587 sal_uInt16 nLastWindowIdx(0);
589 // If no window is found, a first window is inserted
590 sal_uInt16 nInsertPos = 0;
591 for ( sal_uInt16 n=0; n<nCount; n++ )
593 SfxDock_Impl& rD = *maDockArr[n];
595 if (rD.pWin)
597 // A docked window has been found. If no suitable window behind
598 // the desired insertion point s found, then insertion is done at
599 // the end.
600 nInsertPos = nCount;
601 nLastWindowIdx = n;
602 sal_uInt16 nL=0, nP=0;
603 GetWindowPos( rD.pWin, nL, nP );
605 if ( (nL == nLine && nP == nPos) || nL > nLine )
607 DBG_ASSERT( nL == nLine || bNewLine || nPos > 0, "Wrong Parameter!" );
608 if ( nL == nLine && nPos == 0 && !bNewLine )
610 DBG_ASSERT(rD.bNewLine, "No new line?");
612 // The position is pushed to nPos==0
613 rD.bNewLine = false;
614 pDock->bNewLine = true;
617 nInsertPos = n != 0 ? nLastWindowIdx + 1 : 0; // ignore all non-windows after the last window
618 break;
622 if (nCount != 0 && nInsertPos == nCount && nLastWindowIdx != nCount - 1)
624 nInsertPos = nLastWindowIdx + 1; // ignore all non-windows after the last window
627 maDockArr.insert(maDockArr.begin() + nInsertPos, std::unique_ptr<SfxDock_Impl>(pDock));
628 InsertWindow_Impl( pDock, rSize, nLine, nPos, bNewLine );
629 SaveConfig_Impl();
633 void SfxSplitWindow::InsertWindow_Impl( SfxDock_Impl const * pDock,
634 const Size& rSize,
635 sal_uInt16 nLine, sal_uInt16 nPos, bool bNewLine)
637 /* [Description]
639 Adds a DockingWindow, and causes the recalculation of the size of
640 the SplitWindows.
644 SfxDockingWindow* pDockWin = pDock->pWin;
646 SplitWindowItemFlags nItemBits = SplitWindowItemFlags::NONE;
648 tools::Long nWinSize, nSetSize;
649 if ( IsHorizontal() )
651 nWinSize = rSize.Width();
652 nSetSize = rSize.Height();
654 else
656 nSetSize = rSize.Width();
657 nWinSize = rSize.Height();
660 std::unique_ptr<DeactivateUpdateMode> pDeactivateUpdateMode(new DeactivateUpdateMode( *this ));
662 if ( bNewLine || nLine == GetItemCount() )
664 // An existing row should not be inserted, instead a new one
665 // will be created
667 sal_uInt16 nId = 1;
668 for ( sal_uInt16 n=0; n<GetItemCount(); n++ )
670 if ( GetItemId(n) >= nId )
671 nId = GetItemId(n)+1;
674 // Create a new nLine:th line
675 SplitWindowItemFlags nBits = nItemBits;
676 if ( GetAlign() == WindowAlign::Top || GetAlign() == WindowAlign::Bottom )
677 nBits |= SplitWindowItemFlags::ColSet;
678 InsertItem( nId, nSetSize, nLine, 0, nBits );
681 // Insert the window at line with the position nline. ItemWindowSize set to
682 // "percentage" share since the SV then does the re-sizing as expected,
683 // "pixel" actually only makes sense if also items with percentage or
684 // relative sizes are present.
685 nItemBits |= SplitWindowItemFlags::PercentSize;
686 sal_uInt16 nSet = GetItemId( nLine );
687 InsertItem( pDockWin->GetType(), pDockWin, nWinSize, nPos, nSet, nItemBits );
689 // SplitWindows are once created in SFX and when inserting the first
690 // DockingWindows is made visible.
691 if ( GetItemCount() == 1 && GetItemCount( 1 ) == 1 )
693 // The Rearranging in WorkWindow and a Show() on the SplitWindow is
694 // caused by SfxDockingwindow (->SfxWorkWindow::ConfigChild_Impl)
695 if ( !bPinned && !IsFloatingMode() )
697 bPinned = true;
698 bool bFadeIn = ( pEmptyWin->nState & 2 ) != 0;
699 pEmptyWin->bFadeIn = false;
700 SetPinned_Impl( false );
701 pEmptyWin->Actualize();
702 SAL_INFO("sfx", "SfxSplitWindow::InsertWindow_Impl - registering empty Splitwindow" );
703 pWorkWin->RegisterChild_Impl( *GetSplitWindow(), eAlign )->nVisible = SfxChildVisibility::VISIBLE;
704 // tdf#113539 FadeIn will call ArrangeChildren_Impl() for us, and avoiding extra calls to that
705 // can make a different to load times because it avoids extra accessibility calcs
706 if ( bFadeIn )
707 FadeIn();
708 else
709 pWorkWin->ArrangeChildren_Impl();
711 else
713 bool bFadeIn = ( pEmptyWin->nState & 2 ) != 0;
714 pEmptyWin->bFadeIn = false;
715 pEmptyWin->Actualize();
716 if ( !bPinned || !pEmptyWin->bFadeIn )
718 SAL_INFO("sfx", "SfxSplitWindow::InsertWindow_Impl - registering empty Splitwindow" );
720 else
722 SAL_INFO("sfx", "SfxSplitWindow::InsertWindow_Impl - registering real Splitwindow" );
724 pWorkWin->RegisterChild_Impl( *GetSplitWindow(), eAlign )->nVisible = SfxChildVisibility::VISIBLE;
725 // tdf#113539 FadeIn will call ArrangeChildren_Impl() for us, and avoiding extra calls to that
726 // can make a different to load times because it avoids extra accessibility calcs
727 if ( bFadeIn )
728 FadeIn();
729 else
730 pWorkWin->ArrangeChildren_Impl();
733 pWorkWin->ShowChildren_Impl();
736 pDeactivateUpdateMode.reset();
738 // workaround insufficiency of <SplitWindow> regarding dock layouting:
739 // apply FIXED item size as 'original' item size to improve layouting of undock-dock-cycle of a window
741 std::vector< std::pair< sal_uInt16, tools::Long > > aNewOrgSizes;
742 // get FIXED item sizes
743 sal_uInt16 nCount = maDockArr.size();
744 for ( sal_uInt16 n=0; n<nCount; ++n )
746 const SfxDock_Impl& rD = *maDockArr[n];
747 if ( rD.pWin )
749 const sal_uInt16 nId = rD.nType;
750 const tools::Long nSize = GetItemSize( nId, SplitWindowItemFlags::Fixed );
751 aNewOrgSizes.emplace_back( nId, nSize );
754 // apply new item sizes
755 DeactivateUpdateMode aDeactivateUpdateMode( *this );
756 for (const std::pair< sal_uInt16, tools::Long > & rNewOrgSize : aNewOrgSizes)
758 SetItemSize( rNewOrgSize.first, rNewOrgSize.second );
764 void SfxSplitWindow::RemoveWindow( SfxDockingWindow const * pDockWin, bool bHide )
766 /* [Description]
768 Removes a DockingWindow. If it was the last one, then the SplitWindow is
769 being hidden.
772 sal_uInt16 nSet = GetSet( pDockWin->GetType() );
774 // SplitWindows are once created in SFX and is made invisible after
775 // removing the last DockingWindows.
776 if ( GetItemCount( nSet ) == 1 && GetItemCount() == 1 )
778 // The Rearranging in WorkWindow is caused by SfxDockingwindow
779 Hide();
780 pEmptyWin->aTimer.Stop();
781 sal_uInt16 nRealState = pEmptyWin->nState;
782 FadeOut_Impl();
783 pEmptyWin->Hide();
784 #ifdef DBG_UTIL
785 if ( !bPinned || !pEmptyWin->bFadeIn )
787 SAL_INFO("sfx", "SfxSplitWindow::RemoveWindow - releasing empty Splitwindow" );
789 else
791 SAL_INFO("sfx", "SfxSplitWindow::RemoveWindow - releasing real Splitwindow" );
793 #endif
794 pWorkWin->ReleaseChild_Impl( *GetSplitWindow() );
795 pEmptyWin->nState = nRealState;
796 pWorkWin->ArrangeAutoHideWindows( this );
799 sal_uInt16 nCount = maDockArr.size();
800 for ( sal_uInt16 n=0; n<nCount; n++ )
802 SfxDock_Impl& rDock = *maDockArr[n];
803 if ( rDock.nType == pDockWin->GetType() )
805 rDock.pWin = nullptr;
806 rDock.bHide = bHide;
807 break;
811 // Remove Windows, and if it was the last of the line, then also remove
812 // the line (line = itemset)
813 DeactivateUpdateMode aDeactivateUpdateMode( *this );
815 RemoveItem( pDockWin->GetType() );
817 if ( nSet && !GetItemCount( nSet ) )
818 RemoveItem( nSet );
822 bool SfxSplitWindow::GetWindowPos( const SfxDockingWindow* pWindow,
823 sal_uInt16& rLine, sal_uInt16& rPos ) const
824 /* [Description]
826 Returns the ID of the item sets and items for the DockingWindow in
827 the position passed on the old row / column-name.
831 sal_uInt16 nSet = GetSet ( pWindow->GetType() );
832 if ( nSet == SPLITWINDOW_ITEM_NOTFOUND )
833 return false;
835 rPos = GetItemPos( pWindow->GetType(), nSet );
836 rLine = GetItemPos( nSet );
837 return true;
841 bool SfxSplitWindow::GetWindowPos( const Point& rTestPos,
842 sal_uInt16& rLine, sal_uInt16& rPos ) const
843 /* [Description]
845 Returns the ID of the item sets and items for the DockingWindow in
846 the position passed on the old row / column-name.
850 sal_uInt16 nId = GetItemId( rTestPos );
851 if ( nId == 0 )
852 return false;
854 sal_uInt16 nSet = GetSet ( nId );
855 rPos = GetItemPos( nId, nSet );
856 rLine = GetItemPos( nSet );
857 return true;
861 sal_uInt16 SfxSplitWindow::GetLineCount() const
863 /* [Description]
865 Returns the number of rows = number of sub-itemsets in the root set.
868 return GetItemCount();
872 tools::Long SfxSplitWindow::GetLineSize( sal_uInt16 nLine ) const
874 /* [Description]
876 Returns the Row Height of nline itemset.
879 sal_uInt16 nId = GetItemId( nLine );
880 return GetItemSize( nId );
884 sal_uInt16 SfxSplitWindow::GetWindowCount( sal_uInt16 nLine ) const
886 /* [Description]
888 Returns the total number of windows
891 sal_uInt16 nId = GetItemId( nLine );
892 return GetItemCount( nId );
896 sal_uInt16 SfxSplitWindow::GetWindowCount() const
898 /* [Description]
900 Returns the total number of windows
903 return GetItemCount();
907 IMPL_LINK( SfxSplitWindow, TimerHdl, Timer*, pTimer, void)
909 if ( pTimer )
910 pTimer->Stop();
912 if ( CursorIsOverRect() || !pTimer )
914 // If the cursor is within the window, display the SplitWindow and set
915 // up the timer for close
916 pEmptyWin->bAutoHide = true;
917 if ( !IsVisible() )
918 pEmptyWin->FadeIn();
920 pEmptyWin->aLastPos = GetPointerPosPixel();
921 pEmptyWin->aTimer.Start();
923 else if ( pEmptyWin->bAutoHide )
925 if ( GetPointerPosPixel() != pEmptyWin->aLastPos )
927 // The mouse has moved within the running time of the timer, thus
928 // do nothing
929 pEmptyWin->aLastPos = GetPointerPosPixel();
930 pEmptyWin->aTimer.Start();
931 return;
934 // Especially for TF_AUTOSHOW_ON_MOUSEMOVE :
935 // If the window is not visible, there is nothing to do
936 // (user has simply moved the mouse over pEmptyWin)
937 if ( IsVisible() )
939 pEmptyWin->bEndAutoHide = false;
940 if ( !Application::IsInModalMode() &&
941 !vcl::IsInPopupMenuExecute() &&
942 !pEmptyWin->bSplit && !HasChildPathFocus( true ) )
944 // While a modal dialog or a popup menu is open or while the
945 // Splitting is done, in any case, do not close. Even as long
946 // as one of the Children has the focus, the window remains
947 // open.
948 pEmptyWin->bEndAutoHide = true;
951 if ( pEmptyWin->bEndAutoHide )
953 // As far as I am concerned this can be the end of AutoShow
954 // But maybe some other SfxSplitWindow will remain open,
955 // then all others remain open too.
956 if ( !pWorkWin->IsAutoHideMode( this ) )
958 FadeOut_Impl();
959 pWorkWin->ArrangeAutoHideWindows( this );
961 else
963 pEmptyWin->aLastPos = GetPointerPosPixel();
964 pEmptyWin->aTimer.Start();
967 else
969 pEmptyWin->aLastPos = GetPointerPosPixel();
970 pEmptyWin->aTimer.Start();
977 bool SfxSplitWindow::CursorIsOverRect() const
979 bool bVisible = IsVisible();
981 // Also, take the collapsed SplitWindow into account
982 Point aPos = pEmptyWin->GetParent()->OutputToScreenPixel( pEmptyWin->GetPosPixel() );
983 Size aSize = pEmptyWin->GetSizePixel();
985 tools::Rectangle aRect( aPos, aSize );
987 if ( bVisible )
989 Point aVisPos = GetPosPixel();
990 Size aVisSize = GetSizePixel();
992 // Extend with +/- a few pixels, otherwise it is too nervous
993 aVisPos.AdjustX( -(nPixel) );
994 aVisPos.AdjustY( -(nPixel) );
995 aVisSize.AdjustWidth(2 * nPixel );
996 aVisSize.AdjustHeight(2 * nPixel );
998 tools::Rectangle aVisRect( aVisPos, aVisSize );
999 aRect = aRect.GetUnion( aVisRect );
1002 return aRect.Contains( OutputToScreenPixel( static_cast<vcl::Window*>(const_cast<SfxSplitWindow *>(this))->GetPointerPosPixel() ) );
1006 SplitWindow* SfxSplitWindow::GetSplitWindow()
1008 if ( !bPinned || !pEmptyWin->bFadeIn )
1009 return pEmptyWin;
1010 return this;
1014 bool SfxSplitWindow::IsFadeIn() const
1016 return pEmptyWin->bFadeIn;
1019 bool SfxSplitWindow::IsAutoHide( bool bSelf ) const
1021 return bSelf ? pEmptyWin->bAutoHide && !pEmptyWin->bEndAutoHide : pEmptyWin->bAutoHide;
1025 void SfxSplitWindow::SetPinned_Impl( bool bOn )
1027 if ( bPinned == bOn )
1028 return;
1030 bPinned = bOn;
1031 if ( GetItemCount() == 0 )
1032 return;
1034 if ( !bOn )
1036 pEmptyWin->nState |= 1;
1037 if ( pEmptyWin->bFadeIn )
1039 // Unregister replacement windows
1040 SAL_INFO("sfx", "SfxSplitWindow::SetPinned_Impl - releasing real Splitwindow" );
1041 pWorkWin->ReleaseChild_Impl( *this );
1042 Hide();
1043 pEmptyWin->Actualize();
1044 SAL_INFO("sfx", "SfxSplitWindow::SetPinned_Impl - registering empty Splitwindow" );
1045 pWorkWin->RegisterChild_Impl( *pEmptyWin, eAlign )->nVisible = SfxChildVisibility::VISIBLE;
1048 Point aPos( GetPosPixel() );
1049 aPos = GetParent()->OutputToScreenPixel( aPos );
1050 SetFloatingPos( aPos );
1051 SetFloatingMode( true );
1052 GetFloatingWindow()->SetOutputSizePixel( GetOutputSizePixel() );
1054 if ( pEmptyWin->bFadeIn )
1055 Show();
1057 else
1059 pEmptyWin->nState &= ~1;
1060 SetOutputSizePixel( GetFloatingWindow()->GetOutputSizePixel() );
1061 SetFloatingMode(false);
1063 if ( pEmptyWin->bFadeIn )
1065 // Unregister replacement windows
1066 SAL_INFO("sfx", "SfxSplitWindow::SetPinned_Impl - releasing empty Splitwindow" );
1067 pWorkWin->ReleaseChild_Impl( *pEmptyWin );
1068 pEmptyWin->Hide();
1069 SAL_INFO("sfx", "SfxSplitWindow::SetPinned_Impl - registering real Splitwindow" );
1070 pWorkWin->RegisterChild_Impl( *this, eAlign )->nVisible = SfxChildVisibility::VISIBLE;
1075 void SfxSplitWindow::SetFadeIn_Impl( bool bOn )
1077 if ( bOn == pEmptyWin->bFadeIn )
1078 return;
1080 if ( GetItemCount() == 0 )
1081 return;
1083 pEmptyWin->bFadeIn = bOn;
1084 if ( bOn )
1086 pEmptyWin->nState |= 2;
1087 if ( IsFloatingMode() )
1089 // FloatingWindow is not visible, thus display it
1090 pWorkWin->ArrangeAutoHideWindows( this );
1091 Show();
1093 else
1095 SAL_INFO("sfx", "SfxSplitWindow::SetFadeIn_Impl - releasing empty Splitwindow" );
1096 pWorkWin->ReleaseChild_Impl( *pEmptyWin );
1097 pEmptyWin->Hide();
1098 SAL_INFO("sfx", "SfxSplitWindow::SetFadeIn_Impl - registering real Splitwindow" );
1099 pWorkWin->RegisterChild_Impl( *this, eAlign )->nVisible = SfxChildVisibility::VISIBLE;
1100 pWorkWin->ArrangeChildren_Impl();
1101 pWorkWin->ShowChildren_Impl();
1104 else
1106 pEmptyWin->bAutoHide = false;
1107 pEmptyWin->nState &= ~2;
1108 if ( !IsFloatingMode() )
1110 // The window is not "floating", should be hidden
1111 SAL_INFO("sfx", "SfxSplitWindow::SetFadeIn_Impl - releasing real Splitwindow" );
1112 pWorkWin->ReleaseChild_Impl( *this );
1113 Hide();
1114 pEmptyWin->Actualize();
1115 SAL_INFO("sfx", "SfxSplitWindow::SetFadeIn_Impl - registering empty Splitwindow" );
1116 pWorkWin->RegisterChild_Impl( *pEmptyWin, eAlign )->nVisible = SfxChildVisibility::VISIBLE;
1117 pWorkWin->ArrangeChildren_Impl();
1118 pWorkWin->ShowChildren_Impl();
1119 pWorkWin->ArrangeAutoHideWindows( this );
1121 else
1123 Hide();
1124 pWorkWin->ArrangeAutoHideWindows( this );
1129 void SfxSplitWindow::FadeOut_Impl()
1131 if ( pEmptyWin->aTimer.IsActive() )
1133 pEmptyWin->bAutoHide = false;
1134 pEmptyWin->aTimer.Stop();
1137 SetFadeIn_Impl( false );
1140 void SfxSplitWindow::FadeOut()
1142 FadeOut_Impl();
1143 SaveConfig_Impl();
1146 void SfxSplitWindow::FadeIn()
1148 SetFadeIn_Impl( true );
1151 void SfxSplitWindow::SetActiveWindow_Impl( SfxDockingWindow* pWin )
1153 pActive = pWin;
1154 pWorkWin->SetActiveChild_Impl( this );
1158 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */