/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include "workwin.hxx" #include #include #include #include #include #include "splitwin.hxx" #include "childwinimpl.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::uno; struct ResIdToResName { sal_uInt16 nId; const char* pName; }; static const ResIdToResName pToolBarResToName[] = { // OMG! hardcoded numbers that have nice (?) symbolic names // elsewhere. { 558, "fullscreenbar" }, // This 558 for instance equals RID_FULLSCREENTOOLBOX (in // value, and presumably also in semantics) from app.hrc in // this very same directory, so why RID_FULLSCREENTOOLBOX // can't be used I have no idea. { 560, "standardbar", }, // 560 is called RID_ENVTOOLBOX in app.hrc, still the same? { 18001, "formsnavigationbar" }, // Probably the rest are defined in .hrc files that are higher // up in the dependency chain and/or later in the build order, // and that is the (bad) reason why their symbolic names are // not available? Would it really be so awful to move the .hrc // files in question out from the modules where they now are? { 18002, "formsfilterbar" }, { 18003, "formtextobjectbar" }, { 18004, "formcontrols" }, { 18005, "moreformcontrols" }, { 18006, "formdesign" }, { 20050, "toolbar" }, //math { 30001, "objectbar" }, //chart { 30513, "toolbar" }, //chart { 25005, "textobjectbar" }, //calc { 25053, "drawobjectbar" }, { 25054, "graphicobjectbar" }, { 25001, "formatobjectbar" }, { 25006, "previewbar" }, { 25035, "toolbar" }, //calc { 23015, "bezierobjectbar" }, //draw/impress { 23019, "gluepointsobjectbar" }, { 23030, "graphicobjectbar" }, { 23013, "drawingobjectbar" }, //impress { 23016, "textobjectbar" }, //impress { 23028, "textobjectbar" }, //draw { 23011, "toolbar" }, //impress { 23020, "optionsbar" }, { 23021, "commontaskbar" }, { 23025, "toolbar" }, //draw { 23026, "optionsbar" }, { 23027, "drawingobjectbar" }, //draw { 23017, "outlinetoolbar" }, //impress { 23012, "slideviewtoolbar" }, { 23014, "slideviewobjectbar" }, { 23283, "bezierobjectbar" }, // RID_BEZIER_TOOLBOX { 23269, "drawingobjectbar" }, // RID_DRAW_TOOLBOX { 23270, "drawtextobjectbar" }, // RID_DRAW_TEXT_TOOLBOX { 23267, "frameobjectbar" }, // RID_FRAME_TOOLBOX { 23268, "graphicobjectbar" }, // RID_GRAFIK_TOOLBOX { 23271, "numobjectbar" }, // RID_NUM_TOOLBOX { 23272, "oleobjectbar" }, // RID_OLE_TOOLBOX { 23266, "tableobjectbar" }, // RID_TOOLS_TOOLBOX { 23265, "textobjectbar" }, // RID_TEXT_TOOLBOX { 20631, "previewobjectbar" }, //writer { 20402, "toolbar" }, //web { 20403, "textobjectbar" }, { 23273, "toolbar" }, //writer { 20408, "frameobjectbar" }, //web { 20410, "graphicobjectbar" }, { 20411, "oleobjectbar" }, { 14850, "macrobar" }, { 10987, "fontworkobjectbar" }, //global { 10986, "extrusionobjectbar" }, { 23022, "formsobjectbar" }, { 23310, "viewerbar" }, //writer (plugin) { 25000, "viewerbar" }, //calc (plugin) { 23023, "viewerbar" }, //impress(plugin) { 23024, "viewerbar" }, //draw (plugin) { 23031, "mediaobjectbar" }, //draw/impress { 25060, "mediaobjectbar" }, //calc { 23311, "mediaobjectbar" }, //writer { 23313, "navigationobjectbar" }, //writer { 0, "" } }; //SV_IMPL_OBJARR( SfxObjectBarArr_Impl, SfxObjectBar_Impl ); // Sort the Children according their alignment // The order corresponds to the enum SfxChildAlignment (->CHILDWIN.HXX). // Help to make changes to the alignment compatible! LayoutManagerListener::LayoutManagerListener( SfxWorkWindow* pWrkWin ) : m_bHasFrame( false ), m_pWrkWin( pWrkWin ), m_aLayoutManagerPropName( "LayoutManager" ) { } LayoutManagerListener::~LayoutManagerListener() { } void LayoutManagerListener::setFrame( const css::uno::Reference< css::frame::XFrame >& xFrame ) { SolarMutexGuard aGuard; if ( m_pWrkWin && !m_bHasFrame ) { m_xFrame = xFrame; m_bHasFrame = true; if ( xFrame.is() ) { css::uno::Reference< css::beans::XPropertySet > xPropSet( xFrame, UNO_QUERY ); css::uno::Reference< css::frame::XLayoutManagerEventBroadcaster > xLayoutManager; if ( xPropSet.is() ) { try { Any aValue = xPropSet->getPropertyValue( m_aLayoutManagerPropName ); aValue >>= xLayoutManager; if ( xLayoutManager.is() ) xLayoutManager->addLayoutManagerEventListener( css::uno::Reference< css::frame::XLayoutManagerListener >( static_cast< OWeakObject* >( this ), css::uno::UNO_QUERY )); xPropSet.set( xLayoutManager, UNO_QUERY ); if ( xPropSet.is() ) { aValue = xPropSet->getPropertyValue( "LockCount" ); aValue >>= m_pWrkWin->m_nLock; } } catch ( css::lang::DisposedException& ) { } catch ( const css::uno::RuntimeException& ) { throw; } catch ( css::uno::Exception& ) { } } } } } // XComponent void SAL_CALL LayoutManagerListener::addEventListener( const css::uno::Reference< css::lang::XEventListener >& ) throw (css::uno::RuntimeException, std::exception) { // do nothing, only internal class } void SAL_CALL LayoutManagerListener::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& ) throw (css::uno::RuntimeException, std::exception) { // do nothing, only internal class } void SAL_CALL LayoutManagerListener::dispose() throw( css::uno::RuntimeException, std::exception ) { SolarMutexGuard aGuard; // reset member m_pWrkWin = nullptr; css::uno::Reference< css::frame::XFrame > xFrame( m_xFrame.get(), css::uno::UNO_QUERY ); if ( xFrame.is() ) { m_xFrame.clear(); m_bHasFrame = false; css::uno::Reference< css::beans::XPropertySet > xPropSet( xFrame, css::uno::UNO_QUERY ); css::uno::Reference< css::frame::XLayoutManagerEventBroadcaster > xLayoutManager; if ( xPropSet.is() ) { try { css::uno::Any aValue = xPropSet->getPropertyValue( m_aLayoutManagerPropName ); aValue >>= xLayoutManager; // remove as listener from layout manager if ( xLayoutManager.is() ) xLayoutManager->removeLayoutManagerEventListener( css::uno::Reference< css::frame::XLayoutManagerListener >( static_cast< OWeakObject* >( this ), css::uno::UNO_QUERY )); } catch ( css::lang::DisposedException& ) { } catch ( const css::uno::RuntimeException& ) { throw; } catch ( css::uno::Exception& ) { } } } } // XEventListener void SAL_CALL LayoutManagerListener::disposing( const css::lang::EventObject& ) throw( css::uno::RuntimeException, std::exception ) { SolarMutexGuard aGuard; m_pWrkWin = nullptr; m_bHasFrame = false; m_xFrame.clear(); } // XLayoutManagerEventListener void SAL_CALL LayoutManagerListener::layoutEvent( const css::lang::EventObject&, ::sal_Int16 eLayoutEvent, const css::uno::Any& ) throw (css::uno::RuntimeException, std::exception) { SolarMutexGuard aGuard; if ( m_pWrkWin ) { if ( eLayoutEvent == css::frame::LayoutManagerEvents::VISIBLE ) { m_pWrkWin->MakeVisible_Impl( true ); m_pWrkWin->ShowChildren_Impl(); m_pWrkWin->ArrangeChildren_Impl(); } else if ( eLayoutEvent == css::frame::LayoutManagerEvents::INVISIBLE ) { m_pWrkWin->MakeVisible_Impl( false ); m_pWrkWin->HideChildren_Impl(); m_pWrkWin->ArrangeChildren_Impl(); } else if ( eLayoutEvent == css::frame::LayoutManagerEvents::LOCK ) { m_pWrkWin->Lock_Impl( true ); } else if ( eLayoutEvent == css::frame::LayoutManagerEvents::UNLOCK ) { m_pWrkWin->Lock_Impl( false ); } } } namespace { class FilledToolBarResIdToResourceURLMap { private: typedef std::unordered_map< sal_Int32, OUString > ToolBarResIdToResourceURLMap; ToolBarResIdToResourceURLMap m_aResIdToResourceURLMap; public: FilledToolBarResIdToResourceURLMap() { sal_Int32 nIndex( 0 ); while ( pToolBarResToName[nIndex].nId != 0 ) { OUString aResourceURL( OUString::createFromAscii( pToolBarResToName[nIndex].pName )); m_aResIdToResourceURLMap.insert( ToolBarResIdToResourceURLMap::value_type( sal_Int32( pToolBarResToName[nIndex].nId ), aResourceURL )); ++nIndex; } } OUString findURL(sal_uInt16 nResId) const { ToolBarResIdToResourceURLMap::const_iterator aIter = m_aResIdToResourceURLMap.find( nResId ); if ( aIter != m_aResIdToResourceURLMap.end() ) return aIter->second; return OUString(); } }; class theFilledToolBarResIdToResourceURLMap : public rtl::Static { }; } static OUString GetResourceURLFromResId( sal_uInt16 nResId ) { return theFilledToolBarResIdToResourceURLMap::get().findURL(nResId); } bool IsAppWorkWinToolbox_Impl( sal_uInt16 nPos ) { switch ( nPos ) { case SFX_OBJECTBAR_APPLICATION : case SFX_OBJECTBAR_MACRO: case SFX_OBJECTBAR_FULLSCREEN: return true; default: return false; } } sal_uInt16 TbxMatch( sal_uInt16 nPos ) { switch ( nPos ) { case SFX_OBJECTBAR_APPLICATION : return 0; case SFX_OBJECTBAR_OPTIONS: return 1; case SFX_OBJECTBAR_MACRO: return 2; case SFX_OBJECTBAR_OBJECT: return 3; case SFX_OBJECTBAR_TOOLS: return 4; case SFX_OBJECTBAR_FULLSCREEN: case SFX_OBJECTBAR_COMMONTASK: case SFX_OBJECTBAR_RECORDING: return nPos+1; default: return nPos; } } sal_uInt16 ChildAlignValue(SfxChildAlignment eAlign) { sal_uInt16 ret = 17; switch (eAlign) { case SfxChildAlignment::HIGHESTTOP: ret = 1; break; case SfxChildAlignment::LOWESTBOTTOM: ret = 2; break; case SfxChildAlignment::FIRSTLEFT: ret = 3; break; case SfxChildAlignment::LASTRIGHT: ret = 4; break; case SfxChildAlignment::LEFT: ret = 5; break; case SfxChildAlignment::RIGHT: ret = 6; break; case SfxChildAlignment::FIRSTRIGHT: ret = 7; break; case SfxChildAlignment::LASTLEFT: ret = 8; break; case SfxChildAlignment::TOP: ret = 9; break; case SfxChildAlignment::BOTTOM: ret = 10; break; case SfxChildAlignment::TOOLBOXTOP: ret = 11; break; case SfxChildAlignment::TOOLBOXBOTTOM: ret = 12; break; case SfxChildAlignment::LOWESTTOP: ret = 13; break; case SfxChildAlignment::HIGHESTBOTTOM: ret = 14; break; case SfxChildAlignment::TOOLBOXLEFT: ret = 15; break; case SfxChildAlignment::TOOLBOXRIGHT: ret = 16; break; case SfxChildAlignment::NOALIGNMENT: break; // -Wall not handled... } return ret; } void SfxWorkWindow::Sort_Impl() { aSortedList.clear(); for (size_t i = 0; i < aChildren.size(); ++i) { SfxChild_Impl *pCli = aChildren[i]; if (pCli) { sal_uInt16 k; for (k=0; keAlign ) > ChildAlignValue(pCli->eAlign)) break; aSortedList.insert( aSortedList.begin() + k, i ); } } bSorted = true; } // constructor for workwin of a Frame SfxFrameWorkWin_Impl::SfxFrameWorkWin_Impl( vcl::Window *pWin, SfxFrame *pFrm, SfxFrame* pMaster ) : SfxWorkWindow( pWin, pFrm->GetCurrentViewFrame()->GetBindings(), pFrm->GetParentFrame() ? pFrm->GetParentFrame()->GetWorkWindow_Impl() : nullptr ) , pMasterFrame( pMaster ) , pFrame( pFrm ) { pConfigShell = pFrm->GetCurrentViewFrame(); if ( pConfigShell && pConfigShell->GetObjectShell() ) { bShowStatusBar = ( !pConfigShell->GetObjectShell()->IsInPlaceActive() ); bDockingAllowed = true; bInternalDockingAllowed = true; } // The required split windows (one for each side) can be created for ( sal_uInt16 n=0; n pSplitWin = VclPtr::Create(pWorkWin, eAlign, this, pParent==nullptr ); pSplit[n] = pSplitWin; } nOrigMode = SFX_VISIBILITY_STANDARD; nUpdateMode = SFX_VISIBILITY_STANDARD; } // Constructor of the base class SfxWorkWindow::SfxWorkWindow( vcl::Window *pWin, SfxBindings& rB, SfxWorkWindow* pParentWorkwin ) : pParent( pParentWorkwin ), pBindings(&rB), pWorkWin (pWin), pConfigShell( nullptr ), pActiveChild( nullptr ), nUpdateMode(SFX_VISIBILITY_STANDARD), nChildren( 0 ), nOrigMode( 0 ), bSorted( true ), bDockingAllowed(true), bInternalDockingAllowed(true), bAllChildrenVisible(true), #if HAVE_FEATURE_DESKTOP bIsFullScreen( false ), bShowStatusBar( true ), #else bIsFullScreen( sal_True ), bShowStatusBar( sal_False ), #endif m_nLock( 0 ), m_aStatusBarResName( "private:resource/statusbar/statusbar" ), m_aLayoutManagerPropName( "LayoutManager" ), m_aTbxTypeName( "private:resource/toolbar/" ), m_aProgressBarResName( "private:resource/progressbar/progressbar" ) { DBG_ASSERT (pBindings, "No Bindings!"); pBindings->SetWorkWindow_Impl( this ); // For the ObjectBars a integral place in the Childlist is reserved, // so that they always come in a defined order. aChildren.insert( aChildren.begin(), SFX_OBJECTBAR_MAX, nullptr ); // create and initialize layout manager listener Reference< css::frame::XFrame > xFrame = GetFrameInterface(); LayoutManagerListener* pLayoutManagerListener = new LayoutManagerListener( this ); m_xLayoutManagerListener.set( static_cast< cppu::OWeakObject* >( pLayoutManagerListener ), css::uno::UNO_QUERY ); pLayoutManagerListener->setFrame( xFrame ); } // Destructor SfxWorkWindow::~SfxWorkWindow() { // Delete SplitWindows for (VclPtr & p : pSplit) { if (p->GetWindowCount()) ReleaseChild_Impl(*p); p.disposeAndClear(); } // Delete help structure for Child-Windows DBG_ASSERT( aChildren.empty(), "dangling children" ); if ( m_xLayoutManagerListener.is() ) m_xLayoutManagerListener->dispose(); } void SfxWorkWindow::Lock_Impl( bool bLock ) { if ( bLock ) m_nLock++; else --m_nLock; if ( m_nLock<0 ) { OSL_FAIL("Lock count underflow!"); m_nLock = 0; } if ( !m_nLock ) ArrangeChildren_Impl(); } // Helper method to release the child lists. Should the destructor not be // called after this, instead work continues, then space for the object bars // and split windows has to be reserved in the same way as in the constructor // of SfxWorkWindow. void SfxWorkWindow::DeleteControllers_Impl() { // Lock SplitWindows (which means suppressing the Resize-Reaction of the // DockingWindows) sal_uInt16 n; for ( n=0; nGetWindowCount()) p->Lock(); } // Delete Child-Windows for ( n=0; npWin; if (pChild) { pChild->Hide(); // If the child window is a direct child window and not in a // SplitWindow, cancel it at the workwindow. // After TH a cancellation on the SplitWindow is not necessary // since this window is also destroyed (see below). if (pCW->pCli) ReleaseChild_Impl(*pChild->GetWindow()); pCW->pWin = nullptr; pWorkWin->GetSystemWindow()->GetTaskPaneList()->RemoveWindow( pChild->GetWindow() ); pChild->Destroy(); } delete pCW; // ATTENTION: The array itself is cleared after this loop!! // Therefore we have to set every array entry to zero as it could be // accessed by calling pChild->Destroy(). // Window::NotifyAllChildren() calls SfxWorkWindow::DataChanged_Impl for // 8-bit displays (WM_QUERYPALETTECHANGED message due to focus change)!! } Reference< css::frame::XFrame > xFrame = GetFrameInterface(); Reference< css::beans::XPropertySet > xPropSet( xFrame, UNO_QUERY ); Reference< css::frame::XLayoutManager > xLayoutManager; if ( xPropSet.is() ) { try { Any aValue = xPropSet->getPropertyValue( m_aLayoutManagerPropName ); aValue >>= xLayoutManager; } catch ( Exception& ) { } } if ( xLayoutManager.is() ) { xLayoutManager->reset(); // Delete StatusBar ResetStatusBar_Impl(); // Delete ObjectBars (this is done last, so that aChildren does not // receive dead Pointers) for (SfxObjectBar_Impl & i : aObjBarList) { // Not every position must be occupied sal_uInt16 nId = i.nId; if ( nId ) i.nId = 0; } } // ObjectBars are all released at once, since they occupy a // fixed contiguous area in the array pChild aChildren.clear(); bSorted = false; nChildren = 0; } // Virtual method for placing the child window. void SfxWorkWindow::ArrangeChildren_Impl( bool /*bForce*/) { Arrange_Impl(); } void SfxFrameWorkWin_Impl::ArrangeChildren_Impl( bool bForce ) { if ( pFrame->IsClosing_Impl() || ( m_nLock && !bForce )) return; SfxInPlaceClient *pClient = nullptr; SfxViewFrame *pF = pFrame->GetCurrentViewFrame(); if ( pF && pF->GetViewShell() ) pClient = pF->GetViewShell()->GetIPClient(); if ( pClient ) return; aClientArea = GetTopRect_Impl(); if ( aClientArea.IsEmpty() ) return; SvBorder aBorder; if ( nChildren ) { if ( IsVisible_Impl() ) aBorder = Arrange_Impl(); } // If the current application document contains a IPClient, then the // object through SetTopToolFramePixel has to be assigned the available // space. The object will then point to its UITools and sets the app border // (-> SfxInPlaceEnv_Impl:: ArrangeChildren_Impl ()). Otherwise the // app border is set here directly to possibly overwrite the Border that // was set by an object from another document. The object does not set // the SetAppBorder when it removes its UI tools so that no-dithering // ObjectBar arises. // (->SfxInPlaceEnv_Impl::ArrangeChildren_Impl()) pMasterFrame->SetToolSpaceBorderPixel_Impl( aBorder ); ArrangeAutoHideWindows( nullptr ); } SvBorder SfxWorkWindow::Arrange_Impl() /* [Description] This method organizes all visible child windows so that the docked window sorted in order from the outside to the inside are placed after one another. If a visible window does not fit anymore into the free ClientArea, it is set to "not visible". */ { aClientArea = GetTopRect_Impl(); aUpperClientArea = aClientArea; SvBorder aBorder; if ( !nChildren ) return aBorder; if (!bSorted) Sort_Impl(); Point aPos; Size aSize; Rectangle aTmp( aClientArea ); for (sal_uInt16 n : aSortedList) { SfxChild_Impl* pCli = aChildren[n]; if ( !pCli->pWin ) continue; // First, we assume that there is room for the window. pCli->nVisible |= SfxChildVisibility::FITS_IN; // Skip invisible windows if (pCli->nVisible != SfxChildVisibility::VISIBLE) continue; if ( pCli->bResize ) aSize = pCli->aSize; else aSize = pCli->pWin->GetSizePixel(); SvBorder aTemp = aBorder; bool bAllowHiding = true; switch ( pCli->eAlign ) { case SfxChildAlignment::HIGHESTTOP: case SfxChildAlignment::TOP: case SfxChildAlignment::TOOLBOXTOP: case SfxChildAlignment::LOWESTTOP: aSize.Width() = aTmp.GetWidth(); if ( pCli->pWin->GetType() == WINDOW_SPLITWINDOW ) aSize = static_cast(pCli->pWin.get())->CalcLayoutSizePixel( aSize ); bAllowHiding = false; aBorder.Top() += aSize.Height(); aPos = aTmp.TopLeft(); aTmp.Top() += aSize.Height(); if ( pCli->eAlign == SfxChildAlignment::HIGHESTTOP ) aUpperClientArea.Top() += aSize.Height(); break; case SfxChildAlignment::LOWESTBOTTOM: case SfxChildAlignment::BOTTOM: case SfxChildAlignment::TOOLBOXBOTTOM: case SfxChildAlignment::HIGHESTBOTTOM: aSize.Width() = aTmp.GetWidth(); if ( pCli->pWin->GetType() == WINDOW_SPLITWINDOW ) aSize = static_cast(pCli->pWin.get())->CalcLayoutSizePixel( aSize ); aBorder.Bottom() += aSize.Height(); aPos = aTmp.BottomLeft(); aPos.Y() -= (aSize.Height()-1); aTmp.Bottom() -= aSize.Height(); if ( pCli->eAlign == SfxChildAlignment::LOWESTBOTTOM ) aUpperClientArea.Bottom() -= aSize.Height(); break; case SfxChildAlignment::FIRSTLEFT: case SfxChildAlignment::LEFT: case SfxChildAlignment::LASTLEFT: case SfxChildAlignment::TOOLBOXLEFT: aSize.Height() = aTmp.GetHeight(); if ( pCli->pWin->GetType() == WINDOW_SPLITWINDOW ) aSize = static_cast(pCli->pWin.get())->CalcLayoutSizePixel( aSize ); bAllowHiding = false; aBorder.Left() += aSize.Width(); aPos = aTmp.TopLeft(); aTmp.Left() += aSize.Width(); if ( pCli->eAlign != SfxChildAlignment::TOOLBOXLEFT ) aUpperClientArea.Left() += aSize.Width(); break; case SfxChildAlignment::FIRSTRIGHT: case SfxChildAlignment::RIGHT: case SfxChildAlignment::LASTRIGHT: case SfxChildAlignment::TOOLBOXRIGHT: aSize.Height() = aTmp.GetHeight(); if ( pCli->pWin->GetType() == WINDOW_SPLITWINDOW ) aSize = static_cast(pCli->pWin.get())->CalcLayoutSizePixel( aSize ); aBorder.Right() += aSize.Width(); aPos = aTmp.TopRight(); aPos.X() -= (aSize.Width()-1); aTmp.Right() -= aSize.Width(); if ( pCli->eAlign != SfxChildAlignment::TOOLBOXRIGHT ) aUpperClientArea.Right() -= aSize.Width(); break; default: pCli->aSize = pCli->pWin->GetSizePixel(); pCli->bResize = false; continue; } pCli->pWin->SetPosSizePixel( aPos, aSize ); pCli->bResize = false; pCli->aSize = aSize; if( bAllowHiding && !RequestTopToolSpacePixel_Impl( aBorder ) ) { pCli->nVisible ^= SfxChildVisibility::FITS_IN; aBorder = aTemp; } } if ( aClientArea.GetWidth() >= aBorder.Left() + aBorder.Right() ) { aClientArea.Left() += aBorder.Left(); aClientArea.Right() -= aBorder.Right(); } else { aBorder.Left() = aClientArea.Left(); aBorder.Right() = aClientArea.Right(); aClientArea.Right() = aClientArea.Left() = aTmp.Left(); } if ( aClientArea.GetHeight() >= aBorder.Top() + aBorder.Bottom() ) { aClientArea.Top() += aBorder.Top(); aClientArea.Bottom() -= aBorder.Bottom(); } else { aBorder.Top() = aClientArea.Top(); aBorder.Bottom() = aClientArea.Bottom(); aClientArea.Top() = aClientArea.Bottom() = aTmp.Top(); } return IsDockingAllowed() ? aBorder : SvBorder(); } bool SfxWorkWindow::PrepareClose_Impl() { for (SfxChildWin_Impl* pCW : aChildWins) { SfxChildWindow *pChild = pCW->pWin; if ( pChild && !pChild->QueryClose() ) return false; } return true; } SfxChild_Impl* SfxWorkWindow::RegisterChild_Impl( vcl::Window& rWindow, SfxChildAlignment eAlign, bool bCanGetFocus ) { DBG_ASSERT( aChildren.size() < 255, "too many children" ); DBG_ASSERT( SfxChildAlignValid(eAlign), "invalid align" ); DBG_ASSERT( !FindChild_Impl(rWindow), "child registered more than once" ); if ( rWindow.GetParent() != pWorkWin ) rWindow.SetParent( pWorkWin ); SfxChild_Impl *pChild = new SfxChild_Impl(rWindow, rWindow.GetSizePixel(), eAlign, rWindow.IsVisible()); pChild->bCanGetFocus = bCanGetFocus; aChildren.push_back(pChild); bSorted = false; nChildren++; return aChildren.back(); } void SfxWorkWindow::ReleaseChild_Impl( vcl::Window& rWindow ) { SfxChild_Impl *pChild = nullptr; sal_uInt16 nPos; for ( nPos = 0; nPos < aChildren.size(); ++nPos ) { pChild = aChildren[nPos]; if ( pChild && pChild->pWin == &rWindow ) break; } if ( nPos < aChildren.size() ) { bSorted = false; nChildren--; aChildren.erase(aChildren.begin() + nPos); delete pChild; } else { OSL_FAIL( "releasing unregistered child" ); } } SfxChild_Impl* SfxWorkWindow::FindChild_Impl( const vcl::Window& rWindow ) const { sal_uInt16 nCount = aChildren.size(); for ( sal_uInt16 nPos = 0; nPos < nCount; ++nPos ) { SfxChild_Impl *pChild = aChildren[nPos]; if ( pChild && pChild->pWin == &rWindow ) return pChild; } return nullptr; } void SfxWorkWindow::ShowChildren_Impl() { bool bInvisible = ( !IsVisible_Impl() || ( !pWorkWin->IsReallyVisible() && !pWorkWin->IsReallyShown() )); for (SfxChild_Impl* pCli : aChildren) { SfxChildWin_Impl* pCW = nullptr; if ( pCli && pCli->pWin ) { // We have to find the SfxChildWin_Impl to retrieve the // SFX_CHILDWIN flags that can influence visibility. for (SfxChildWin_Impl* pCWin : aChildWins) { SfxChild_Impl* pChild = pCWin->pCli; if ( pChild == pCli ) { pCW = pCWin; break; } } bool bVisible( !bInvisible ); if ( pCW ) { // Check flag SFX_CHILDWIN_NEVERHIDE that forces us to show // the child window even in situations where no child window is // visible. SfxChildWindowFlags nFlags = pCW->aInfo.nFlags; bVisible = !bInvisible || ( nFlags & SfxChildWindowFlags::NEVERHIDE ); } if ( SfxChildVisibility::VISIBLE == (pCli->nVisible & SfxChildVisibility::VISIBLE) && bVisible ) { ShowFlags nFlags = pCli->bSetFocus ? ShowFlags::NONE : ShowFlags::NoFocusChange | ShowFlags::NoActivate; pCli->pWin->Show(true, nFlags); pCli->bSetFocus = false; } else { pCli->pWin->Hide(); } } } } void SfxWorkWindow::HideChildren_Impl() { for ( sal_uInt16 nPos = aChildren.size(); nPos > 0; --nPos ) { SfxChild_Impl *pChild = aChildren[nPos-1]; if (pChild && pChild->pWin) pChild->pWin->Hide(); } } void SfxWorkWindow::ResetObjectBars_Impl() { sal_uInt16 n; for ( n = 0; n < aObjBarList.size(); n++ ) aObjBarList[n].bDestroy = true; for ( n = 0; n < aChildWins.size(); ++n ) aChildWins[n]->nId = 0; } void SfxWorkWindow::SetObjectBar_Impl(sal_uInt16 nPos, sal_uInt32 nResId, SfxInterface* pIFace) { DBG_ASSERT( (nPos & SFX_POSITION_MASK) < SFX_OBJECTBAR_MAX, "object bar position overflow" ); sal_uInt16 nRealPos = nPos & SFX_POSITION_MASK; if ( pParent && IsAppWorkWinToolbox_Impl( nRealPos ) ) { pParent->SetObjectBar_Impl(nPos, nResId, pIFace); return; } SfxObjectBar_Impl aObjBar; aObjBar.pIFace = pIFace; aObjBar.nId = sal::static_int_cast(nResId); aObjBar.nPos = nRealPos; aObjBar.nMode = (nPos & SFX_VISIBILITY_MASK); for (SfxObjectBar_Impl & rBar : aObjBarList) { if ( rBar.nId == aObjBar.nId ) { rBar = aObjBar; return; } } aObjBarList.push_back( aObjBar ); } bool SfxWorkWindow::KnowsObjectBar_Impl( sal_uInt16 nPos ) const /* [Description] Determines if a object list is available at the position in question. This is independent for the fact whether it is actually turned on or off. */ { sal_uInt16 nRealPos = nPos & SFX_POSITION_MASK; if ( pParent && IsAppWorkWinToolbox_Impl( nRealPos ) ) return pParent->KnowsObjectBar_Impl( nPos ); for (const SfxObjectBar_Impl& rBar : aObjBarList) { if ( rBar.nPos == nRealPos ) return true; } return false; } bool SfxWorkWindow::IsVisible_Impl( sal_uInt16 nMode ) const { switch( nUpdateMode ) { case SFX_VISIBILITY_STANDARD: return true; case SFX_VISIBILITY_UNVISIBLE: return false; case SFX_VISIBILITY_CLIENT: case SFX_VISIBILITY_SERVER: return !!(nMode & nUpdateMode); default: return !!(nMode & nOrigMode ) || nOrigMode == SFX_VISIBILITY_STANDARD; } } void SfxFrameWorkWin_Impl::UpdateObjectBars_Impl() { if ( pFrame->IsClosing_Impl() ) return; SfxWorkWindow *pWork = pParent; while ( pWork ) { pWork->SfxWorkWindow::UpdateObjectBars_Impl(); pWork = pWork->GetParent_Impl(); } SfxWorkWindow::UpdateObjectBars_Impl(); { pWork = pParent; while ( pWork ) { pWork->ArrangeChildren_Impl(); pWork = pWork->GetParent_Impl(); } ArrangeChildren_Impl( false ); pWork = pParent; while ( pWork ) { pWork->ShowChildren_Impl(); pWork = pWork->GetParent_Impl(); } ShowChildren_Impl(); } ShowChildren_Impl(); } Reference< css::task::XStatusIndicator > SfxWorkWindow::GetStatusIndicator() { Reference< css::beans::XPropertySet > xPropSet( GetFrameInterface(), UNO_QUERY ); Reference< css::frame::XLayoutManager > xLayoutManager; Reference< css::task::XStatusIndicator > xStatusIndicator; if ( xPropSet.is() ) { Any aValue = xPropSet->getPropertyValue( m_aLayoutManagerPropName ); aValue >>= xLayoutManager; if ( xLayoutManager.is() ) { xLayoutManager->createElement( m_aProgressBarResName ); xLayoutManager->showElement( m_aProgressBarResName ); Reference< css::ui::XUIElement > xProgressBar = xLayoutManager->getElement( m_aProgressBarResName ); if ( xProgressBar.is() ) { xStatusIndicator.set( xProgressBar->getRealInterface(), UNO_QUERY ); } } } return xStatusIndicator; } bool SfxWorkWindow::IsPluginMode( SfxObjectShell* pObjShell ) { if ( pObjShell && pObjShell->GetMedium() ) { const SfxBoolItem* pViewOnlyItem = SfxItemSet::GetItem(pObjShell->GetMedium()->GetItemSet(), SID_VIEWONLY, false); if ( pViewOnlyItem && pViewOnlyItem->GetValue() ) return true; } return false; } css::uno::Reference< css::frame::XFrame > SfxWorkWindow::GetFrameInterface() { css::uno::Reference< css::frame::XFrame > xFrame; SfxDispatcher* pDispatcher( GetBindings().GetDispatcher() ); if ( pDispatcher ) { SfxViewFrame* pFrame = pDispatcher->GetFrame(); if ( pFrame ) xFrame = pFrame->GetFrame().GetFrameInterface(); } return xFrame; } void SfxWorkWindow::UpdateObjectBars_Impl() { // Lock SplitWindows (which means suppressing the Resize-Reaction of the // DockingWindows) sal_uInt16 n; for ( n=0; nGetWindowCount()) p->Lock(); } // you realize what is needed often (saves Code and execution time) SfxGetpApp(); Reference< css::beans::XPropertySet > xPropSet( GetFrameInterface(), UNO_QUERY ); Reference< css::frame::XLayoutManager > xLayoutManager; if ( xPropSet.is() ) { Any aValue = xPropSet->getPropertyValue( m_aLayoutManagerPropName ); aValue >>= xLayoutManager; } if ( !xLayoutManager.is() ) return; bool bPluginMode( false ); SfxDispatcher* pDispatcher( GetBindings().GetDispatcher() ); if ( pDispatcher ) { SfxViewFrame* pFrame = pDispatcher->GetFrame(); if ( pFrame ) bPluginMode = IsPluginMode( pFrame->GetObjectShell() ); } // Iterate over all Toolboxes xLayoutManager->lock(); for ( n = 0; n < aObjBarList.size(); ++n ) { sal_uInt16 nId = aObjBarList[n].nId; bool bDestroy = aObjBarList[n].bDestroy; // Determine the valid mode for the ToolBox sal_uInt16 nTbxMode = aObjBarList[n].nMode; bool bFullScreenTbx = SFX_VISIBILITY_FULLSCREEN == ( nTbxMode & SFX_VISIBILITY_FULLSCREEN ); nTbxMode &= ~SFX_VISIBILITY_FULLSCREEN; nTbxMode &= ~SFX_VISIBILITY_VIEWER; // Is a ToolBox required in this context ? bool bModesMatching = ( nUpdateMode && ( nTbxMode & nUpdateMode) == nUpdateMode ); if ( bDestroy ) { OUString aTbxId( m_aTbxTypeName ); aTbxId += GetResourceURLFromResId( aObjBarList[n].nId ); xLayoutManager->destroyElement( aTbxId ); } else if ( nId != 0 && ( ( bModesMatching && !bIsFullScreen ) || ( bIsFullScreen && bFullScreenTbx ) ) ) { OUString aTbxId( m_aTbxTypeName ); aTbxId += GetResourceURLFromResId( aObjBarList[n].nId ); if ( !IsDockingAllowed() && !xLayoutManager->isElementFloating( aTbxId )) xLayoutManager->destroyElement( aTbxId ); else { xLayoutManager->requestElement( aTbxId ); if ( bPluginMode ) xLayoutManager->lockWindow( aTbxId ); } } else if ( nId != 0 ) { // Delete the Toolbox at this Position if possible OUString aTbxId( m_aTbxTypeName ); aTbxId += GetResourceURLFromResId( aObjBarList[n].nId ); xLayoutManager->destroyElement( aTbxId ); } } UpdateStatusBar_Impl(); // unlocking automatically forces Layout xLayoutManager->unlock(); UpdateChildWindows_Impl(); // Unlock the SplitWindows again for ( n=0; nGetWindowCount()) p->Lock(false); } } void SfxWorkWindow::UpdateChildWindows_Impl() { // any current or in the context available Childwindows for (SfxChildWin_Impl* pCW : aChildWins) { SfxChildWindow *pChildWin = pCW->pWin; bool bCreate = false; if ( pCW->nId && (pCW->aInfo.nFlags & SfxChildWindowFlags::ALWAYSAVAILABLE || IsVisible_Impl( pCW->nVisibility ) ) ) { // In the context is an appropriate ChildWindow allowed; // it is also turned on? if ( pChildWin == nullptr && pCW->bCreate ) { // Internal docking is only used for embedding into another // container. We force the floating state of all floatable // child windows. if ( !bInternalDockingAllowed ) { // Special case for all non-floatable child windows. We have // to prevent the creation here! bCreate = !( pCW->aInfo.nFlags & SfxChildWindowFlags::FORCEDOCK ); } else if ( !IsDockingAllowed() || bIsFullScreen ) // || !bInternalDocking ) { // In Presentation mode or FullScreen only FloatingWindows SfxChildAlignment eAlign; if ( pCW->aInfo.GetExtraData_Impl( &eAlign ) ) bCreate = ( eAlign == SfxChildAlignment::NOALIGNMENT ); } else bCreate = true; // Currently, no window here, but it is enabled; windows // Create window and if possible theContext if ( bCreate ) CreateChildWin_Impl( pCW, false ); if ( !bAllChildrenVisible ) { if ( pCW->pCli ) pCW->pCli->nVisible &= ~SfxChildVisibility::ACTIVE; } } else if ( pChildWin ) { // Window already exists, it should also be visible? if ( ( !bIsFullScreen || pChildWin->GetAlignment() == SfxChildAlignment::NOALIGNMENT ) && bAllChildrenVisible ) { // Update Mode is compatible; definitely enable it bCreate = true; if ( pCW->pCli ) { // The window is a direct Child if ( bAllChildrenVisible && ( (IsDockingAllowed() && bInternalDockingAllowed) || pCW->pCli->eAlign == SfxChildAlignment::NOALIGNMENT ) ) pCW->pCli->nVisible |= SfxChildVisibility::NOT_HIDDEN; } else { if ( pCW->bCreate && IsDockingAllowed() && bInternalDockingAllowed ) // The window ia within a SplitWindow static_cast(pChildWin->GetWindow())->Reappear_Impl(); } if ( pCW->nInterfaceId != pChildWin->GetContextId() ) pChildWin->CreateContext( pCW->nInterfaceId, GetBindings() ); } } } if ( pChildWin && !bCreate ) { if ( !pChildWin->QueryClose() || pChildWin->IsHideNotDelete() || Application::IsUICaptured() ) { if ( pCW->pCli ) { if ( pCW->pCli->nVisible & SfxChildVisibility::NOT_HIDDEN ) pCW->pCli->nVisible ^= SfxChildVisibility::NOT_HIDDEN; } else static_cast(pChildWin->GetWindow())->Disappear_Impl(); } else RemoveChildWin_Impl( pCW ); } } } void SfxWorkWindow::CreateChildWin_Impl( SfxChildWin_Impl *pCW, bool bSetFocus ) { pCW->aInfo.bVisible = true; SfxChildWindow *pChildWin = SfxChildWindow::CreateChildWindow( pCW->nId, pWorkWin, &GetBindings(), pCW->aInfo); if (pChildWin) { if ( bSetFocus ) bSetFocus = pChildWin->WantsFocus(); pChildWin->SetWorkWindow_Impl( this ); // At least the extra string is changed during the evaluation, // also get it anewed SfxChildWinInfo aInfo = pChildWin->GetInfo(); pCW->aInfo.aExtraString = aInfo.aExtraString; pCW->aInfo.bVisible = aInfo.bVisible; pCW->aInfo.nFlags |= aInfo.nFlags; // The creation was successful GetBindings().Invalidate(pCW->nId); sal_uInt16 nPos = pChildWin->GetPosition(); if (nPos != CHILDWIN_NOPOS) { DBG_ASSERT(nPos < SFX_OBJECTBAR_MAX, "Illegal objectbar position!"); if ( aChildren[TbxMatch(nPos)] )// && { // ChildWindow replaces ObjectBar aChildren[TbxMatch(nPos)]->nVisible ^= SfxChildVisibility::NOT_HIDDEN; } } // make childwin keyboard accessible pWorkWin->GetSystemWindow()->GetTaskPaneList()->AddWindow( pChildWin->GetWindow() ); pCW->pWin = pChildWin; if ( pChildWin->GetAlignment() == SfxChildAlignment::NOALIGNMENT || pChildWin->GetWindow()->GetParent() == pWorkWin) { // The window is not docked or docked outside of one split windows // and must therefore be registered explicitly as a Child pCW->pCli = RegisterChild_Impl(*(pChildWin->GetWindow()), pChildWin->GetAlignment(), pChildWin->CanGetFocus()); pCW->pCli->nVisible = SfxChildVisibility::VISIBLE; if ( pChildWin->GetAlignment() != SfxChildAlignment::NOALIGNMENT && bIsFullScreen ) pCW->pCli->nVisible ^= SfxChildVisibility::ACTIVE; pCW->pCli->bSetFocus = bSetFocus; } else { // A docked window which parent is not a WorkingWindow, must lie // in a SplitWindow and thus not be explicitly registered. // This happens already in the initialization of SfxDockingWindows! } if ( pCW->nInterfaceId != pChildWin->GetContextId() ) pChildWin->CreateContext( pCW->nInterfaceId, GetBindings() ); // Save the information in the INI file SaveStatus_Impl(pChildWin, pCW->aInfo); } } void SfxWorkWindow::RemoveChildWin_Impl( SfxChildWin_Impl *pCW ) { sal_uInt16 nId = pCW->nSaveId; SfxChildWindow *pChildWin = pCW->pWin; // Save the information in the INI file SfxChildWindowFlags nFlags = pCW->aInfo.nFlags; pCW->aInfo = pChildWin->GetInfo(); pCW->aInfo.nFlags |= nFlags; SaveStatus_Impl(pChildWin, pCW->aInfo); pChildWin->Hide(); if ( pCW->pCli ) { // Child window is a direct child window and must therefore unregister // itself from the WorkWindow pCW->pCli = nullptr; ReleaseChild_Impl(*pChildWin->GetWindow()); } else { // ChildWindow is within a SplitWindow and unregister itself in // the destructor. } pWorkWin->GetSystemWindow()->GetTaskPaneList()->RemoveWindow( pChildWin->GetWindow() ); pCW->pWin = nullptr; pChildWin->Destroy(); GetBindings().Invalidate( nId ); } void SfxWorkWindow::ResetStatusBar_Impl() { aStatBar.nId = 0; } void SfxWorkWindow::SetStatusBar_Impl( sal_uInt32 nResId, SfxShell*, SfxBindings& ) { if ( nResId && bShowStatusBar && IsVisible_Impl() ) aStatBar.nId = sal::static_int_cast(nResId); } void SfxWorkWindow::UpdateStatusBar_Impl() { Reference< css::beans::XPropertySet > xPropSet( GetFrameInterface(), UNO_QUERY ); Reference< css::frame::XLayoutManager > xLayoutManager; Any aValue = xPropSet->getPropertyValue( m_aLayoutManagerPropName ); aValue >>= xLayoutManager; // No status bar, if no ID is required or when in FullScreenView or // if disabled if ( aStatBar.nId && IsDockingAllowed() && bInternalDockingAllowed && bShowStatusBar && !bIsFullScreen ) { // Id has changed, thus create a suitable Statusbarmanager, this takes // over the current status bar; if ( xLayoutManager.is() ) xLayoutManager->requestElement( m_aStatusBarResName ); } else { // Destroy the current StatusBar // The Manager only creates the Status bar, does not destroy it. if ( xLayoutManager.is() ) xLayoutManager->destroyElement( m_aStatusBarResName ); } } void SfxWorkWindow::MakeVisible_Impl( bool bVis ) { if ( bVis ) nOrigMode = SFX_VISIBILITY_STANDARD; else nOrigMode = SFX_VISIBILITY_UNVISIBLE; if ( nOrigMode != nUpdateMode) nUpdateMode = nOrigMode; } bool SfxWorkWindow::IsVisible_Impl() { return nOrigMode != SFX_VISIBILITY_UNVISIBLE; } void SfxWorkWindow::HidePopups_Impl(bool bHide, bool bParent, sal_uInt16 nId ) { for (SfxChildWin_Impl* i : aChildWins) { SfxChildWindow *pCW = i->pWin; if (pCW && pCW->GetAlignment() == SfxChildAlignment::NOALIGNMENT && pCW->GetType() != nId) { vcl::Window *pWin = pCW->GetWindow(); SfxChild_Impl *pChild = FindChild_Impl(*pWin); if (bHide) { pChild->nVisible &= ~SfxChildVisibility::ACTIVE; pCW->Hide(); } else { pChild->nVisible |= SfxChildVisibility::ACTIVE; if ( SfxChildVisibility::VISIBLE == (pChild->nVisible & SfxChildVisibility::VISIBLE) ) pCW->Show( ShowFlags::NoFocusChange | ShowFlags::NoActivate ); } } } if ( bParent && pParent ) pParent->HidePopups_Impl( bHide, bParent, nId ); } void SfxWorkWindow::ConfigChild_Impl(SfxChildIdentifier eChild, SfxDockingConfig eConfig, sal_uInt16 nId) { SfxDockingWindow* pDockWin=nullptr; sal_uInt16 nPos = USHRT_MAX; vcl::Window *pWin=nullptr; SfxChildWin_Impl *pCW = nullptr; if ( eChild == SfxChildIdentifier::OBJECTBAR ) return; // configure direct childwindow for (SfxChildWin_Impl* i : aChildWins) { pCW = i; SfxChildWindow *pChild = pCW->pWin; if ( pChild && (pChild->GetType() == nId )) { if (SfxDockingWindow* pSfxDockingWindow = dynamic_cast(pChild->GetWindow())) { // it's a DockingWindow pDockWin = pSfxDockingWindow; } else { // FloatingWindow or ModelessDialog pWin = pChild->GetWindow(); } break; } } if ( pDockWin ) { if ( eChild == SfxChildIdentifier::DOCKINGWINDOW || pDockWin->GetAlignment() == SfxChildAlignment::NOALIGNMENT ) { if ( eChild == SfxChildIdentifier::SPLITWINDOW && eConfig == SfxDockingConfig::TOGGLEFLOATMODE) { // DockingWindow was dragged out of a SplitWindow pCW->pCli = RegisterChild_Impl(*pDockWin, pDockWin->GetAlignment(), pCW->pWin->CanGetFocus()); pCW->pCli->nVisible = SfxChildVisibility::VISIBLE; } pWin = pDockWin; } else { SfxSplitWindow *pSplitWin = GetSplitWindow_Impl(pDockWin->GetAlignment()); // configure DockingWindow inside a SplitWindow if ( eConfig == SfxDockingConfig::TOGGLEFLOATMODE) { // DockingWindow was dragged into a SplitWindow pCW->pCli = nullptr; ReleaseChild_Impl(*pDockWin); } pWin = pSplitWin->GetSplitWindow(); if ( pSplitWin->GetWindowCount() == 1 ) static_cast(pWin)->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate ); } } DBG_ASSERT( pCW, "Unknown window!" ); if ( !pCW && pParent ) { pParent->ConfigChild_Impl( eChild, eConfig, nId ); return; } if ( !bSorted ) // windows may have been registered and released without an update until now Sort_Impl(); sal_uInt16 n; for ( n=0; npWin == pWin ) break; } if ( n < aSortedList.size() ) // sometimes called while toggeling float mode nPos = aSortedList[n]; switch ( eConfig ) { case SfxDockingConfig::SETDOCKINGRECTS : { if (nPos == USHRT_MAX || !pDockWin) return; Rectangle aOuterRect( GetTopRect_Impl() ); aOuterRect.SetPos( pWorkWin->OutputToScreenPixel( aOuterRect.TopLeft() )); Rectangle aInnerRect( aOuterRect ); // The current affected window is included in the calculation of // the inner rectangle! for (sal_uInt16 i : aSortedList) { SfxChild_Impl* pCli = aChildren[i]; if ( pCli && pCli->nVisible == SfxChildVisibility::VISIBLE && pCli->pWin ) { switch ( pCli->eAlign ) { case SfxChildAlignment::TOP: // Objekt-Toolboxes come always last aInnerRect.Top() += pCli->aSize.Height(); break; case SfxChildAlignment::HIGHESTTOP: // Always performed first aInnerRect.Top() += pCli->aSize.Height(); break; case SfxChildAlignment::LOWESTTOP: // Is only counted if it is the current window if ( i == nPos ) aInnerRect.Top() += pCli->aSize.Height(); break; case SfxChildAlignment::BOTTOM: // Objekt-Toolboxes come always last aInnerRect.Bottom() -= pCli->aSize.Height(); break; case SfxChildAlignment::LOWESTBOTTOM: // Always performed first aInnerRect.Bottom() -= pCli->aSize.Height(); break; case SfxChildAlignment::HIGHESTBOTTOM: // Is only counted if it is the current window if ( i == nPos ) aInnerRect.Bottom() -= pCli->aSize.Height(); break; case SfxChildAlignment::LEFT: // Toolboxes come always last aInnerRect.Left() += pCli->aSize.Width(); break; case SfxChildAlignment::FIRSTLEFT: // Always performed first aInnerRect.Left() += pCli->aSize.Width(); break; case SfxChildAlignment::LASTLEFT: // Is only counted if it is the current window if (i == nPos) aInnerRect.Left() += pCli->aSize.Width(); break; case SfxChildAlignment::RIGHT: // Toolboxes come always last aInnerRect.Right() -= pCli->aSize.Width(); break; case SfxChildAlignment::FIRSTRIGHT: // Is only counted if it is the current window if (i == nPos) aInnerRect.Right() -= pCli->aSize.Width(); break; case SfxChildAlignment::LASTRIGHT: // Always performed first aInnerRect.Right() -= pCli->aSize.Width(); break; default: break; } } } pDockWin->SetDockingRects(aOuterRect, aInnerRect); break; } case SfxDockingConfig::MOVEDOCKINGWINDOW : case SfxDockingConfig::ALIGNDOCKINGWINDOW : case SfxDockingConfig::TOGGLEFLOATMODE: { if ( nPos == USHRT_MAX && !pCW ) return; SfxChildAlignment eAlign = SfxChildAlignment::NOALIGNMENT; SfxChild_Impl *pCli = ( nPos != USHRT_MAX ) ? aChildren[nPos] : nullptr; if ( pCli && pDockWin ) { eAlign = pDockWin->GetAlignment(); if ( eChild == SfxChildIdentifier::DOCKINGWINDOW || eAlign == SfxChildAlignment::NOALIGNMENT) { // configuration inside the SplitWindow, no change for the SplitWindows' configuration pCli->bResize = true; pCli->aSize = pDockWin->GetSizePixel(); } } if ( pCli ) { if( pCli->eAlign != eAlign ) { bSorted = false; pCli->eAlign = eAlign; } ArrangeChildren_Impl(); ShowChildren_Impl(); } if ( pCW && pCW->pWin ) { // store changed configuration SfxChildWindowFlags nFlags = pCW->aInfo.nFlags; pCW->aInfo = pCW->pWin->GetInfo(); pCW->aInfo.nFlags |= nFlags; if ( eConfig != SfxDockingConfig::MOVEDOCKINGWINDOW ) SaveStatus_Impl( pCW->pWin, pCW->aInfo); } break; } } } void SfxWorkWindow::SetChildWindowVisible_Impl( sal_uInt32 lId, bool bEnabled, sal_uInt16 nMode ) { sal_uInt16 nInter = (sal_uInt16) ( lId >> 16 ); sal_uInt16 nId = (sal_uInt16) ( lId & 0xFFFF ); SfxChildWin_Impl *pCW=nullptr; SfxWorkWindow *pWork = pParent; // Get the top parent, child windows are always registered at the // task of the WorkWindow for example the frame or on AppWorkWindow while ( pWork && pWork->pParent ) pWork = pWork->pParent; if ( pWork ) { // The Parent already known? sal_uInt16 nCount = pWork->aChildWins.size(); for (sal_uInt16 n=0; naChildWins[n]->nSaveId == nId) { pCW = pWork->aChildWins[n]; break; } } if ( !pCW ) { // If no Parent or the Parent us still unknown, then search here sal_uInt16 nCount = aChildWins.size(); for (sal_uInt16 n=0; nnSaveId == nId) { pCW = aChildWins[n]; break; } } if ( !pCW ) { // If new, then initialize, add this here depending on the flag or // the Parent pCW = new SfxChildWin_Impl( lId ); pCW->nId = nId; InitializeChild_Impl( pCW ); if ( pWork && !( pCW->aInfo.nFlags & SfxChildWindowFlags::TASK ) ) pWork->aChildWins.push_back( pCW ); else aChildWins.push_back( pCW ); } pCW->nId = nId; if ( nInter ) pCW->nInterfaceId = nInter; pCW->nVisibility = nMode; pCW->bEnable = bEnabled; pCW->nVisibility = nMode; } // The on/off status of a ChildWindow is switched void SfxWorkWindow::ToggleChildWindow_Impl(sal_uInt16 nId, bool bSetFocus) { sal_uInt16 nCount = aChildWins.size(); sal_uInt16 n; for (n=0; nnId == nId) break; if ( npWin; bool bCreationAllowed( true ); if ( !bInternalDockingAllowed ) { // Special case for all non-floatable child windows. We have // to prevent the creation here! bCreationAllowed = !( pCW->aInfo.nFlags & SfxChildWindowFlags::FORCEDOCK ); } if ( bCreationAllowed ) { if ( pCW->bCreate ) { if ( pChild ) { if ( pChild->QueryClose() ) { pCW->bCreate = false; // The Window should be switched off pChild->SetVisible_Impl( false ); RemoveChildWin_Impl( pCW ); } } else { // no actual Window exists, yet => just remember the "switched off" state pCW->bCreate = false; } } else { pCW->bCreate = true; if ( pChild ) { ShowChildWindow_Impl( nId, true, bSetFocus ); } else { // create actual Window CreateChildWin_Impl( pCW, bSetFocus ); if ( !pCW->pWin ) // no success pCW->bCreate = false; } } } ArrangeChildren_Impl(); ShowChildren_Impl(); if ( pCW->bCreate && bCreationAllowed ) { if ( !pCW->pCli ) { SfxDockingWindow *pDock = static_cast( pCW->pWin->GetWindow() ); if ( pDock->IsAutoHide_Impl() ) pDock->AutoShow_Impl(); } } return; } else if ( pParent ) { pParent->ToggleChildWindow_Impl( nId, bSetFocus ); return; } #ifdef DBG_UTIL nCount = aChildWins.size(); for (n=0; nnSaveId == nId) break; if ( n < nCount ) { OSL_FAIL("The ChildWindow is not in context!"); } else { OSL_FAIL("The ChildWindow is not registered!"); } #endif } bool SfxWorkWindow::HasChildWindow_Impl(sal_uInt16 nId) { sal_uInt16 nCount = aChildWins.size(); sal_uInt16 n; for (n=0; nnSaveId == nId) break; if (npWin; return ( pChild && pCW->bCreate ); } if ( pParent ) return pParent->HasChildWindow_Impl( nId ); return false; } bool SfxWorkWindow::IsFloating( sal_uInt16 nId ) { SfxChildWin_Impl *pCW=nullptr; SfxWorkWindow *pWork = pParent; // Get the top parent, child windows are always registered at the // task of the WorkWindow for example the frame or on AppWorkWindow while ( pWork && pWork->pParent ) pWork = pWork->pParent; if ( pWork ) { // The Parent already known? sal_uInt16 nCount = pWork->aChildWins.size(); for (sal_uInt16 n=0; naChildWins[n]->nSaveId == nId) { pCW = pWork->aChildWins[n]; break; } } if ( !pCW ) { // If no Parent or the Parent us still unknown, then search here sal_uInt16 nCount = aChildWins.size(); for (sal_uInt16 n=0; nnSaveId == nId) { pCW = aChildWins[n]; break; } } if ( !pCW ) { // If new, then initialize, add this here depending on the flag or // the Parent pCW = new SfxChildWin_Impl( nId ); pCW->bEnable = false; pCW->nId = 0; pCW->nVisibility = 0; InitializeChild_Impl( pCW ); if ( pWork && !( pCW->aInfo.nFlags & SfxChildWindowFlags::TASK ) ) pWork->aChildWins.push_back( pCW ); else aChildWins.push_back( pCW ); } SfxChildAlignment eAlign; if ( pCW->aInfo.GetExtraData_Impl( &eAlign ) ) return( eAlign == SfxChildAlignment::NOALIGNMENT ); else return true; } bool SfxWorkWindow::KnowsChildWindow_Impl(sal_uInt16 nId) { SfxChildWin_Impl *pCW=nullptr; sal_uInt16 nCount = aChildWins.size(); sal_uInt16 n; for (n=0; nnSaveId == nId) break; } if (naInfo.nFlags & SfxChildWindowFlags::ALWAYSAVAILABLE) && !IsVisible_Impl( pCW->nVisibility ) ) return false; return pCW->bEnable; } else if ( pParent ) return pParent->KnowsChildWindow_Impl( nId ); else return false; } void SfxWorkWindow::SetChildWindow_Impl(sal_uInt16 nId, bool bOn, bool bSetFocus) { SfxChildWin_Impl *pCW=nullptr; SfxWorkWindow *pWork = pParent; // Get the top parent, child windows are always registered at the // task of the WorkWindow for example the frame or on AppWorkWindow while ( pWork && pWork->pParent ) pWork = pWork->pParent; if ( pWork ) { // The Parent already known? sal_uInt16 nCount = pWork->aChildWins.size(); for (sal_uInt16 n=0; naChildWins[n]->nSaveId == nId) { pCW = pWork->aChildWins[n]; break; } } if ( !pCW ) { // If no Parent or the Parent us still unknown, then search here sal_uInt16 nCount = aChildWins.size(); for (sal_uInt16 n=0; nnSaveId == nId) { pCW = aChildWins[n]; pWork = this; break; } } if ( !pCW ) { // If new, then initialize, add this here depending on the flag or // the Parent pCW = new SfxChildWin_Impl( nId ); InitializeChild_Impl( pCW ); if ( !pWork || pCW->aInfo.nFlags & SfxChildWindowFlags::TASK ) pWork = this; pWork->aChildWins.push_back( pCW ); } if ( pCW->bCreate != bOn ) pWork->ToggleChildWindow_Impl(nId,bSetFocus); } void SfxWorkWindow::ShowChildWindow_Impl(sal_uInt16 nId, bool bVisible, bool bSetFocus) { sal_uInt16 nCount = aChildWins.size(); SfxChildWin_Impl* pCW=nullptr; sal_uInt16 n; for (n=0; nnId == nId) break; } if ( npWin; if ( pChildWin ) { if ( bVisible ) { if ( pCW->pCli ) { pCW->pCli->bSetFocus = bSetFocus; pCW->pCli->nVisible = SfxChildVisibility::VISIBLE; pChildWin->Show( bSetFocus && pChildWin->WantsFocus() ? ShowFlags::NONE : ShowFlags::NoFocusChange | ShowFlags::NoActivate ); } else static_cast(pChildWin->GetWindow())->Reappear_Impl(); } else { if ( pCW->pCli ) { pCW->pCli->nVisible = SfxChildVisibility::VISIBLE ^ SfxChildVisibility::NOT_HIDDEN; pCW->pWin->Hide(); } else static_cast(pChildWin->GetWindow())->Disappear_Impl(); } ArrangeChildren_Impl(); ShowChildren_Impl(); } else if ( bVisible ) { SetChildWindow_Impl( nId, true, bSetFocus ); pChildWin = pCW->pWin; } if ( pChildWin ) { pChildWin->SetVisible_Impl( bVisible ); SfxChildWindowFlags nFlags = pCW->aInfo.nFlags; pCW->aInfo = pChildWin->GetInfo(); pCW->aInfo.nFlags |= nFlags; if ( !pCW->bCreate ) SaveStatus_Impl( pChildWin, pCW->aInfo ); } return; } if ( pParent ) { pParent->ShowChildWindow_Impl( nId, bVisible, bSetFocus ); return; } #ifdef DBG_UTIL nCount = aChildWins.size(); for (n=0; nnSaveId == nId) break; if ( nnSaveId == nId) break; if (npWin; else if ( pParent ) return pParent->GetChildWindow_Impl( nId ); return nullptr; } void SfxWorkWindow::ResetChildWindows_Impl() { for (SfxChildWin_Impl* pChildWin : aChildWins) { pChildWin->nId = 0; pChildWin->bEnable = false; } } // Virtual method that returns the size of the area (client area) of the // parent windows, in which the ChildWindow can be fitted. Rectangle SfxWorkWindow::GetTopRect_Impl() { return Rectangle (Point(), pWorkWin->GetOutputSizePixel() ); } // Virtual method that returns the size of the area (client area) of the // parent windows, in which the ChildWindow can be fitted. Rectangle SfxFrameWorkWin_Impl::GetTopRect_Impl() { return pMasterFrame->GetTopOuterRectPixel_Impl(); } // Virtual method to find out if there is room for a ChildWindow in the // client area of the parent. bool SfxWorkWindow::RequestTopToolSpacePixel_Impl( SvBorder aBorder ) { if ( !IsDockingAllowed() || aClientArea.GetWidth() < aBorder.Left() + aBorder.Right() || aClientArea.GetHeight() < aBorder.Top() + aBorder.Bottom() ) return false; else return true; } void SfxWorkWindow::SaveStatus_Impl(SfxChildWindow *pChild, const SfxChildWinInfo &rInfo) { // The Status of the Presentation mode is not saved if ( IsDockingAllowed() && bInternalDockingAllowed ) pChild->SaveStatus(rInfo); } void SfxWorkWindow::InitializeChild_Impl(SfxChildWin_Impl *pCW) { SfxDispatcher *pDisp = pBindings->GetDispatcher_Impl(); SfxViewFrame *pFrame = pDisp ? pDisp->GetFrame() :nullptr; SfxModule *pMod = pFrame ? SfxModule::GetActiveModule(pFrame) :nullptr; OUString sModule; if (pFrame) { try { using namespace ::com::sun::star; uno::Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(::comphelper::getProcessComponentContext())); sModule = xModuleManager->identify(pFrame->GetFrame().GetFrameInterface()); SvtModuleOptions::EFactory eFac = SvtModuleOptions::ClassifyFactoryByServiceName(sModule); sModule = SvtModuleOptions::GetFactoryShortName(eFac); } catch (...) { } } SfxChildWinFactory* pFact=nullptr; SfxApplication *pApp = SfxGetpApp(); { SfxChildWinFactArr_Impl &rFactories = pApp->GetChildWinFactories_Impl(); for ( size_t nFactory = 0; nFactory < rFactories.size(); ++nFactory ) { pFact = &rFactories[nFactory]; if ( pFact->nId == pCW->nSaveId ) { pCW->aInfo = pFact->aInfo; pCW->aInfo.aModule = sModule; SfxChildWindow::InitializeChildWinFactory_Impl( pCW->nSaveId, pCW->aInfo); pCW->bCreate = pCW->aInfo.bVisible; SfxChildWindowFlags nFlags = pFact->aInfo.nFlags; if ( nFlags & SfxChildWindowFlags::TASK ) pCW->aInfo.nFlags |= SfxChildWindowFlags::TASK; if ( nFlags & SfxChildWindowFlags::CANTGETFOCUS ) pCW->aInfo.nFlags |= SfxChildWindowFlags::CANTGETFOCUS; if ( nFlags & SfxChildWindowFlags::FORCEDOCK ) pCW->aInfo.nFlags |= SfxChildWindowFlags::FORCEDOCK; pFact->aInfo = pCW->aInfo; return; } } } if ( pMod ) { SfxChildWinFactArr_Impl *pFactories = pMod->GetChildWinFactories_Impl(); if ( pFactories ) { SfxChildWinFactArr_Impl &rFactories = *pFactories; for ( size_t nFactory = 0; nFactory < rFactories.size(); ++nFactory ) { pFact = &rFactories[nFactory]; if ( pFact->nId == pCW->nSaveId ) { pCW->aInfo = pFact->aInfo; pCW->aInfo.aModule = sModule; SfxChildWindow::InitializeChildWinFactory_Impl( pCW->nSaveId, pCW->aInfo); pCW->bCreate = pCW->aInfo.bVisible; SfxChildWindowFlags nFlags = pFact->aInfo.nFlags; if ( nFlags & SfxChildWindowFlags::TASK ) pCW->aInfo.nFlags |= SfxChildWindowFlags::TASK; if ( nFlags & SfxChildWindowFlags::CANTGETFOCUS ) pCW->aInfo.nFlags |= SfxChildWindowFlags::CANTGETFOCUS; if ( nFlags & SfxChildWindowFlags::FORCEDOCK ) pCW->aInfo.nFlags |= SfxChildWindowFlags::FORCEDOCK; if ( nFlags & SfxChildWindowFlags::ALWAYSAVAILABLE ) pCW->aInfo.nFlags |= SfxChildWindowFlags::ALWAYSAVAILABLE; pFact->aInfo = pCW->aInfo; return; } } } } } SfxSplitWindow* SfxWorkWindow::GetSplitWindow_Impl( SfxChildAlignment eAlign ) { switch ( eAlign ) { case SfxChildAlignment::TOP: return pSplit[2]; case SfxChildAlignment::BOTTOM: return pSplit[3]; case SfxChildAlignment::LEFT: return pSplit[0]; case SfxChildAlignment::RIGHT: return pSplit[1]; default: return nullptr; } } void SfxWorkWindow::MakeChildrenVisible_Impl( bool bVis ) { if ( pParent ) pParent->MakeChildrenVisible_Impl( bVis ); bAllChildrenVisible = bVis; if ( bVis ) { if ( !bSorted ) Sort_Impl(); for (sal_uInt16 n : aSortedList) { SfxChild_Impl* pCli = aChildren[n]; if ( (pCli->eAlign == SfxChildAlignment::NOALIGNMENT) || (IsDockingAllowed() && bInternalDockingAllowed) ) pCli->nVisible |= SfxChildVisibility::ACTIVE; } } else { if ( !bSorted ) Sort_Impl(); for (sal_uInt16 n : aSortedList) { SfxChild_Impl* pCli = aChildren[n]; pCli->nVisible &= ~SfxChildVisibility::ACTIVE; } } } bool SfxWorkWindow::IsAutoHideMode( const SfxSplitWindow *pSplitWin ) { for (VclPtr & pWin : pSplit) { if ( pWin.get() != pSplitWin && pWin->IsAutoHide( true ) ) return true; } return false; } void SfxWorkWindow::EndAutoShow_Impl( Point aPos ) { if ( pParent ) pParent->EndAutoShow_Impl( aPos ); for (VclPtr & p : pSplit) { if ( p && p->IsAutoHide() ) { Point aLocalPos = p->ScreenToOutputPixel( aPos ); Point aEmptyPoint; Rectangle aRect( aEmptyPoint, p->GetSizePixel() ); if ( !aRect.IsInside( aLocalPos ) ) p->FadeOut(); } } } void SfxWorkWindow::ArrangeAutoHideWindows( SfxSplitWindow *pActSplitWin ) { if ( m_nLock ) return; if ( pParent ) pParent->ArrangeAutoHideWindows( pActSplitWin ); Rectangle aArea( aUpperClientArea ); for ( sal_uInt16 n=0; nIsFadeIn(); vcl::Window *pDummy = pSplitWin->GetSplitWindow(); vcl::Window *pWin = bDummyWindow ? pDummy : pSplitWin; if ( (pSplitWin->IsPinned() && !bDummyWindow) || (!pWin->IsVisible() && pActSplitWin != pSplitWin) ) continue; // Width and position of the dummy window as a starting point Size aSize = pDummy->GetSizePixel(); Point aPos = pDummy->GetPosPixel(); switch ( n ) { case 0 : { // Left SplitWindow // Get the width of the Window yourself, if no DummyWindow if ( !bDummyWindow ) aSize.Width() = pSplitWin->GetSizePixel().Width(); // If a Window is visible to the left, then the free region // starts to the right from it, for example at the Client area long nLeft = aPos.X() + aSize.Width(); if ( nLeft > aArea.Left() ) aArea.Left() = nLeft; break; } case 1 : { // Right SplitWindow // Position to correct the difference of the widths aPos.X() += aSize.Width(); // Get the width of the Window yourself, if no DummyWindow if ( !bDummyWindow ) aSize.Width() = pSplitWin->GetSizePixel().Width(); aPos.X() -= aSize.Width(); // If already a window is opened at the left side, then the // right is not allowed to overlap this one. if ( aPos.X() < aArea.Left() ) { aPos.X() = aArea.Left(); aSize.Width() = aArea.GetWidth(); } // If a Window is visible to the right, then the free region // starts to the left from it, for example at the Client area long nRight = aPos.X(); if ( nRight < aArea.Right() ) aArea.Right() = nRight; break; } case 2 : { // Top SplitWindow // Get the height of the Window yourself, if no DummyWindow if ( !bDummyWindow ) aSize.Height() = pSplitWin->GetSizePixel().Height(); // Adjust width with regard to if a Window is already open // to the left or right aPos.X() = aArea.Left(); aSize.Width() = aArea.GetWidth(); // If a Window is visible at the top, then the free region // starts beneath it, for example at the Client area long nTop = aPos.Y() + aSize.Height(); if ( nTop > aArea.Top() ) aArea.Top() = nTop; break; } case 3 : { // The bottom SplitWindow // Position to correct the difference of the heights aPos.Y() += aSize.Height(); // Get the height of the Window yourself, if no DummyWindow if ( !bDummyWindow ) aSize.Height() = pSplitWin->GetSizePixel().Height(); aPos.Y() -= aSize.Height(); // Adjust width with regard to if a Window is already open // to the left or right. aPos.X() = aArea.Left(); aSize.Width() = aArea.GetWidth(); // If already a window is opened at the top, then the // bottom one is not allowed to overlap this one. if ( aPos.Y() < aArea.Top() ) { aPos.Y() = aArea.Top(); aSize.Height() = aArea.GetHeight(); } break; } } if ( !bDummyWindow ) // the FadeIn-Window is a Floating window, which coordinates are // set in Screen coordinates. pSplitWin->SetPosSizePixel( pWorkWin->OutputToScreenPixel(aPos), aSize ); else // the docked DummyWindow pDummy->SetPosSizePixel( aPos, aSize ); } } Rectangle SfxWorkWindow::GetFreeArea( bool bAutoHide ) const { if ( bAutoHide ) { Rectangle aArea( aClientArea ); for ( sal_uInt16 n=0; nIsPinned() || !pSplit[n]->IsVisible() ) continue; Size aSize = pSplit[n]->GetSizePixel(); switch ( n ) { case 0 : aArea.Left() += aSize.Width(); break; case 1 : aArea.Right() -= aSize.Width(); break; case 2 : aArea.Top() += aSize.Height(); break; case 3 : aArea.Bottom() -= aSize.Height(); break; } } return aArea; } else return aClientArea; } void SfxWorkWindow::SetActiveChild_Impl( vcl::Window *pChild ) { pActiveChild = pChild; } void SfxWorkWindow::DataChanged_Impl( const DataChangedEvent& ) { sal_uInt16 n; sal_uInt16 nCount = aChildWins.size(); for (n=0; npWin ) pCW->pWin->GetWindow()->UpdateSettings( Application::GetSettings() ); } ArrangeChildren_Impl(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */