Files
libreoffice/vcl/source/window/dockmgr.cxx
Stephan Bergmann f853ec317f Extend loplugin:external to warn about classes
...following up on 314f15bff0 "Extend
loplugin:external to warn about enums".

Cases where free functions were moved into an unnamed namespace along with a
class, to not break ADL, are in:

  filter/source/svg/svgexport.cxx
  sc/source/filter/excel/xelink.cxx
  sc/source/filter/excel/xilink.cxx
  svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx

All other free functions mentioning moved classes appear to be harmless and not
give rise to (silent, even) ADL breakage.  (One remaining TODO in
compilerplugins/clang/external.cxx is that derived classes are not covered by
computeAffectedTypes, even though they could also be affected by ADL-breakage---
but don't seem to be in any acutal case across the code base.)

For friend declarations using elaborate type specifiers, like

  class C1 {};
  class C2 { friend class C1; };

* If C2 (but not C1) is moved into an unnamed namespace, the friend declaration
must be changed to not use an elaborate type specifier (i.e., "friend C1;"; see
C++17 [namespace.memdef]/3: "If the name in a friend declaration is neither
qualified nor a template-id and the declaration is a function or an
elaborated-type-specifier, the lookup to determine whether the entity has been
previously declared shall not consider any scopes outside the innermost
enclosing namespace.")

* If C1 (but not C2) is moved into an unnamed namespace, the friend declaration
must be changed too, see <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71882>
"elaborated-type-specifier friend not looked up in unnamed namespace".

Apart from that, to keep changes simple and mostly mechanical (which should help
avoid regressions), out-of-line definitions of class members have been left in
the enclosing (named) namespace.  But explicit specializations of class
templates had to be moved into the unnamed namespace to appease
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92598> "explicit specialization of
template from unnamed namespace using unqualified-id in enclosing namespace".

Also, accompanying declarations (of e.g. typedefs or static variables) that
could arguably be moved into the unnamed namespace too have been left alone.

And in some cases, mention of affected types in blacklists in other loplugins
needed to be adapted.

And sc/qa/unit/mark_test.cxx uses a hack of including other .cxx, one of which
is sc/source/core/data/segmenttree.cxx where e.g. ScFlatUInt16SegmentsImpl is
not moved into an unnamed namespace (because it is declared in
sc/inc/segmenttree.hxx), but its base ScFlatSegmentsImpl is.  GCC warns about
such combinations with enabled-by-default -Wsubobject-linkage, but "The compiler
doesn’t give this warning for types defined in the main .C file, as those are
unlikely to have multiple definitions."
(<https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/Warning-Options.html>)  The
warned-about classes also don't have multiple definitions in the given test, so
disable the warning when including the .cxx.

Change-Id: Ib694094c0d8168be68f8fe90dfd0acbb66a3f1e4
Reviewed-on: https://gerrit.libreoffice.org/83239
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2019-11-22 12:57:32 +01:00

1060 lines
37 KiB
C++

/* -*- 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 <tools/time.hxx>
#include <sal/log.hxx>
#include <o3tl/deleter.hxx>
#include <brdwin.hxx>
#include <svdata.hxx>
#include <window.h>
#include <vcl/event.hxx>
#include <vcl/floatwin.hxx>
#include <vcl/dockwin.hxx>
#include <vcl/toolbox.hxx>
#include <vcl/svapp.hxx>
#include <vcl/timer.hxx>
#include <vcl/settings.hxx>
#define DOCKWIN_FLOATSTYLES (WB_SIZEABLE | WB_MOVEABLE | WB_CLOSEABLE | WB_STANDALONE | WB_ROLLABLE )
namespace {
class ImplDockFloatWin2 : public FloatingWindow
{
private:
ImplDockingWindowWrapper* mpDockWin;
sal_uInt64 const mnLastTicks;
Timer m_aDockTimer;
Timer m_aEndDockTimer;
Point maDockPos;
tools::Rectangle maDockRect;
bool mbInMove;
ImplSVEvent * mnLastUserEvent;
DECL_LINK(DockingHdl, void *, void);
DECL_LINK(DockTimerHdl, Timer *, void);
DECL_LINK(EndDockTimerHdl, Timer *, void);
public:
ImplDockFloatWin2( vcl::Window* pParent, WinBits nWinBits,
ImplDockingWindowWrapper* pDockingWin );
virtual ~ImplDockFloatWin2() override;
virtual void dispose() override;
virtual void Move() override;
virtual void Resize() override;
virtual void TitleButtonClick( TitleButton nButton ) override;
virtual void Resizing( Size& rSize ) override;
virtual bool Close() override;
};
}
ImplDockFloatWin2::ImplDockFloatWin2( vcl::Window* pParent, WinBits nWinBits,
ImplDockingWindowWrapper* pDockingWin ) :
FloatingWindow( pParent, nWinBits ),
mpDockWin( pDockingWin ),
mnLastTicks( tools::Time::GetSystemTicks() ),
mbInMove( false ),
mnLastUserEvent( nullptr )
{
// copy state of DockingWindow
if ( pDockingWin )
{
SetSettings( pDockingWin->GetWindow()->GetSettings() );
Enable( pDockingWin->GetWindow()->IsEnabled(), false );
EnableInput( pDockingWin->GetWindow()->IsInputEnabled(), false );
AlwaysEnableInput( pDockingWin->GetWindow()->IsAlwaysEnableInput(), false );
EnableAlwaysOnTop( pDockingWin->GetWindow()->IsAlwaysOnTopEnabled() );
SetActivateMode( pDockingWin->GetWindow()->GetActivateMode() );
}
SetBackground( GetSettings().GetStyleSettings().GetFaceColor() );
m_aDockTimer.SetInvokeHandler( LINK( this, ImplDockFloatWin2, DockTimerHdl ) );
m_aDockTimer.SetPriority( TaskPriority::HIGH_IDLE );
m_aDockTimer.SetTimeout( 50 );
m_aDockTimer.SetDebugName( "vcl::ImplDockFloatWin2 m_aDockTimer" );
m_aEndDockTimer.SetInvokeHandler( LINK( this, ImplDockFloatWin2, EndDockTimerHdl ) );
m_aEndDockTimer.SetPriority( TaskPriority::HIGH_IDLE );
m_aEndDockTimer.SetTimeout( 50 );
m_aEndDockTimer.SetDebugName( "vcl::ImplDockFloatWin2 m_aEndDockTimer" );
}
ImplDockFloatWin2::~ImplDockFloatWin2()
{
disposeOnce();
}
void ImplDockFloatWin2::dispose()
{
if( mnLastUserEvent )
Application::RemoveUserEvent( mnLastUserEvent );
FloatingWindow::dispose();
}
IMPL_LINK_NOARG(ImplDockFloatWin2, DockTimerHdl, Timer *, void)
{
SAL_WARN_IF( !mpDockWin->IsFloatingMode(), "vcl", "docktimer called but not floating" );
PointerState aState = GetPointerState();
if( aState.mnState & KEY_MOD1 )
{
// i43499 CTRL disables docking now
mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking();
if( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) )
m_aDockTimer.Start();
}
else if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) )
{
mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking();
mpDockWin->EndDocking( maDockRect, false );
}
else
{
mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, ShowTrackFlags::Big | ShowTrackFlags::TrackWindow );
m_aDockTimer.Start();
}
}
IMPL_LINK_NOARG(ImplDockFloatWin2, EndDockTimerHdl, Timer *, void)
{
SAL_WARN_IF( !mpDockWin->IsFloatingMode(), "vcl", "enddocktimer called but not floating" );
PointerState aState = GetPointerState();
if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) )
{
mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking();
mpDockWin->EndDocking( maDockRect, true );
}
else
m_aEndDockTimer.Start();
}
IMPL_LINK_NOARG(ImplDockFloatWin2, DockingHdl, void*, void)
{
// called during move of a floating window
mnLastUserEvent = nullptr;
vcl::Window *pDockingArea = mpDockWin->GetWindow()->GetParent();
PointerState aState = pDockingArea->GetPointerState();
bool bRealMove = true;
if( GetStyle() & WB_OWNERDRAWDECORATION )
{
// for windows with ownerdraw decoration
// we allow docking only when the window was moved
// by dragging its caption
// and ignore move request due to resizing
vcl::Window *pBorder = GetWindow( GetWindowType::Border );
if( pBorder != this )
{
tools::Rectangle aBorderRect( Point(), pBorder->GetSizePixel() );
sal_Int32 nLeft, nTop, nRight, nBottom;
GetBorder( nLeft, nTop, nRight, nBottom );
// limit borderrect to the caption part only and without the resizing borders
aBorderRect.SetBottom( aBorderRect.Top() + nTop );
aBorderRect.AdjustLeft(nLeft );
aBorderRect.AdjustRight( -nRight );
PointerState aBorderState = pBorder->GetPointerState();
bRealMove = aBorderRect.IsInside( aBorderState.maPos );
}
}
if( mpDockWin->GetWindow()->IsVisible() &&
(tools::Time::GetSystemTicks() - mnLastTicks > 500) &&
( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) &&
!(aState.mnState & KEY_MOD1) && // i43499 CTRL disables docking now
bRealMove )
{
maDockPos = pDockingArea->OutputToScreenPixel( pDockingArea->AbsoluteScreenToOutputPixel( OutputToAbsoluteScreenPixel( Point() ) ) );
maDockRect = tools::Rectangle( maDockPos, mpDockWin->GetSizePixel() );
// mouse pos in screen pixels
Point aMousePos = pDockingArea->OutputToScreenPixel( aState.maPos );
if( ! mpDockWin->IsDocking() )
mpDockWin->StartDocking( aMousePos, maDockRect );
bool bFloatMode = mpDockWin->Docking( aMousePos, maDockRect );
if( ! bFloatMode )
{
// indicates that the window could be docked at maDockRect
maDockRect.SetPos( mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ScreenToOutputPixel(
maDockRect.TopLeft() ) );
mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, ShowTrackFlags::Big | ShowTrackFlags::TrackWindow );
m_aEndDockTimer.Stop();
m_aDockTimer.Invoke();
}
else
{
mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking();
m_aDockTimer.Stop();
m_aEndDockTimer.Invoke();
}
}
mbInMove = false;
}
void ImplDockFloatWin2::Move()
{
if( mbInMove )
return;
mbInMove = true;
FloatingWindow::Move();
mpDockWin->GetWindow()->Move();
/*
* note: the window should only dock if KEY_MOD1 is pressed
* and the user releases all mouse buttons. The real problem here
* is that we don't get mouse events (at least not on X)
* if the mouse is on the decoration. So we have to start an
* awkward timer based process that polls the modifier/buttons
* to see whether they are in the right condition shortly after the
* last Move message.
*/
if( ! mnLastUserEvent )
mnLastUserEvent = Application::PostUserEvent( LINK( this, ImplDockFloatWin2, DockingHdl ), nullptr, true );
}
void ImplDockFloatWin2::Resize()
{
// forwarding of resize only required if we have no borderwindow ( GetWindow() then returns 'this' )
if( GetWindow( GetWindowType::Border ) == this )
{
FloatingWindow::Resize();
Size aSize( GetSizePixel() );
mpDockWin->GetWindow()->ImplPosSizeWindow( 0, 0, aSize.Width(), aSize.Height(), PosSizeFlags::PosSize ); // TODO: is this needed ???
}
}
void ImplDockFloatWin2::TitleButtonClick( TitleButton nButton )
{
FloatingWindow::TitleButtonClick( nButton );
mpDockWin->TitleButtonClick( nButton );
}
void ImplDockFloatWin2::Resizing( Size& rSize )
{
FloatingWindow::Resizing( rSize );
mpDockWin->Resizing( rSize );
}
bool ImplDockFloatWin2::Close()
{
return true;
}
DockingManager::DockingManager()
{
}
DockingManager::~DockingManager()
{
}
ImplDockingWindowWrapper* DockingManager::GetDockingWindowWrapper( const vcl::Window *pWindow )
{
for( const auto& xWrapper : mvDockingWindows )
{
if( xWrapper->mpDockingWindow == pWindow )
return xWrapper.get();
}
return nullptr;
}
bool DockingManager::IsDockable( const vcl::Window *pWindow )
{
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
/*
if( pWindow->HasDockingHandler() )
return true;
*/
return (pWrapper != nullptr);
}
bool DockingManager::IsFloating( const vcl::Window *pWindow )
{
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
if( pWrapper )
return pWrapper->IsFloatingMode();
else
return false;
}
bool DockingManager::IsLocked( const vcl::Window *pWindow )
{
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
return pWrapper && pWrapper->IsLocked();
}
void DockingManager::Lock( const vcl::Window *pWindow )
{
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
if( pWrapper )
pWrapper->Lock();
}
void DockingManager::Unlock( const vcl::Window *pWindow )
{
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
if( pWrapper )
pWrapper->Unlock();
}
void DockingManager::SetFloatingMode( const vcl::Window *pWindow, bool bFloating )
{
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
if( pWrapper )
pWrapper->SetFloatingMode( bFloating );
}
void DockingManager::StartPopupMode( const vcl::Window *pWindow, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags )
{
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
if( pWrapper )
pWrapper->StartPopupMode( rRect, nFlags );
}
void DockingManager::StartPopupMode( ToolBox *pParentToolBox, const vcl::Window *pWindow, FloatWinPopupFlags nFlags )
{
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
if( pWrapper )
pWrapper->StartPopupMode( pParentToolBox, nFlags );
}
void DockingManager::StartPopupMode( ToolBox *pParentToolBox, const vcl::Window *pWindow )
{
StartPopupMode( pParentToolBox, pWindow, FloatWinPopupFlags::AllowTearOff |
FloatWinPopupFlags::AllMouseButtonClose |
FloatWinPopupFlags::NoMouseUpClose );
}
bool DockingManager::IsInPopupMode( const vcl::Window *pWindow )
{
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
return pWrapper && pWrapper->IsInPopupMode();
}
void DockingManager::EndPopupMode( const vcl::Window *pWin )
{
ImplDockingWindowWrapper *pWrapper = GetDockingWindowWrapper( pWin );
if( pWrapper && pWrapper->GetFloatingWindow() && pWrapper->GetFloatingWindow()->IsInPopupMode() )
pWrapper->GetFloatingWindow()->EndPopupMode();
}
void DockingManager::AddWindow( const vcl::Window *pWindow )
{
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
if( pWrapper )
return;
mvDockingWindows.emplace_back( new ImplDockingWindowWrapper( pWindow ) );
}
void DockingManager::RemoveWindow( const vcl::Window *pWindow )
{
for( auto it = mvDockingWindows.begin(); it != mvDockingWindows.end(); ++it )
{
if( (*it)->mpDockingWindow == pWindow )
{
mvDockingWindows.erase( it );
break;
}
}
}
void DockingManager::SetPosSizePixel( vcl::Window const *pWindow, long nX, long nY,
long nWidth, long nHeight,
PosSizeFlags nFlags )
{
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
if( pWrapper )
pWrapper->setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
}
tools::Rectangle DockingManager::GetPosSizePixel( const vcl::Window *pWindow )
{
tools::Rectangle aRect;
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
if( pWrapper )
aRect = tools::Rectangle( pWrapper->GetPosPixel(), pWrapper->GetSizePixel() );
return aRect;
}
class ImplPopupFloatWin : public FloatingWindow
{
private:
bool const mbToolBox;
public:
ImplPopupFloatWin( vcl::Window* pParent, bool bToolBox );
virtual ~ImplPopupFloatWin() override;
virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override;
};
ImplPopupFloatWin::ImplPopupFloatWin( vcl::Window* pParent, bool bToolBox ) :
FloatingWindow( pParent, bToolBox ? WB_BORDER | WB_POPUP | WB_SYSTEMWINDOW | WB_NOSHADOW : WB_STDPOPUP ),
mbToolBox( bToolBox )
{
if ( bToolBox )
{
// indicate window type, required for accessibility
// which should not see this window as a toplevel window
mpWindowImpl->mbToolbarFloatingWindow = true;
}
}
ImplPopupFloatWin::~ImplPopupFloatWin()
{
disposeOnce();
}
css::uno::Reference< css::accessibility::XAccessible > ImplPopupFloatWin::CreateAccessible()
{
if ( !mbToolBox )
return FloatingWindow::CreateAccessible();
// switch off direct accessibility support for this window
// this is to avoid appearance of this window as standalone window in the accessibility hierarchy
// as this window is only used as a helper for subtoolbars that are not teared-off, the parent toolbar
// has to provide accessibility support (as implemented in the toolkit)
// so the contained toolbar should appear as child of the corresponding toolbar item of the parent toolbar
return css::uno::Reference< css::accessibility::XAccessible >();
}
ImplDockingWindowWrapper::ImplDockingWindowWrapper( const vcl::Window *pWindow )
: mpDockingWindow(const_cast<vcl::Window*>(pWindow))
, mpFloatWin(nullptr)
, mpOldBorderWin(nullptr)
, mpParent(pWindow->GetParent())
, maMaxOutSize( SHRT_MAX, SHRT_MAX )
, mnTrackX(0)
, mnTrackY(0)
, mnTrackWidth(0)
, mnTrackHeight(0)
, mnDockLeft(0)
, mnDockTop(0)
, mnDockRight(0)
, mnDockBottom(0)
, mnFloatBits(WB_BORDER | WB_CLOSEABLE | WB_SIZEABLE | (pWindow->GetStyle() & DOCKWIN_FLOATSTYLES))
, mbDockCanceled(false)
, mbDocking(false)
, mbLastFloatMode(false)
, mbRollUp(false)
, mbDockBtn(false)
, mbHideBtn(false)
// must be enabled in Window::Notify to prevent permanent docking during mouse move
, mbStartDockingEnabled(false)
, mbLocked(false)
{
DockingWindow *pDockWin = dynamic_cast< DockingWindow* > ( mpDockingWindow.get() );
if( pDockWin )
mnFloatBits = pDockWin->GetFloatStyle();
}
ImplDockingWindowWrapper::~ImplDockingWindowWrapper()
{
if ( IsFloatingMode() )
{
GetWindow()->Show( false, ShowFlags::NoFocusChange );
SetFloatingMode(false);
}
}
void ImplDockingWindowWrapper::ImplStartDocking( const Point& rPos )
{
if( !mbStartDockingEnabled )
return;
maMouseOff = rPos;
mbDocking = true;
mbLastFloatMode = IsFloatingMode();
// calculate FloatingBorder
VclPtr<FloatingWindow> pWin;
if ( mpFloatWin )
pWin = mpFloatWin;
else
pWin = VclPtr<ImplDockFloatWin2>::Create( mpParent, mnFloatBits, nullptr );
pWin->GetBorder( mnDockLeft, mnDockTop, mnDockRight, mnDockBottom );
if ( !mpFloatWin )
pWin.disposeAndClear();
Point aPos = GetWindow()->ImplOutputToFrame( Point() );
Size aSize = GetWindow()->GetOutputSizePixel();
mnTrackX = aPos.X();
mnTrackY = aPos.Y();
mnTrackWidth = aSize.Width();
mnTrackHeight = aSize.Height();
if ( mbLastFloatMode )
{
maMouseOff.AdjustX(mnDockLeft );
maMouseOff.AdjustY(mnDockTop );
mnTrackX -= mnDockLeft;
mnTrackY -= mnDockTop;
mnTrackWidth += mnDockLeft+mnDockRight;
mnTrackHeight += mnDockTop+mnDockBottom;
}
vcl::Window *pDockingArea = GetWindow()->GetParent();
vcl::Window::PointerState aState = pDockingArea->GetPointerState();
// mouse pos in screen pixels
Point aMousePos = pDockingArea->OutputToScreenPixel( aState.maPos );
Point aDockPos = pDockingArea->AbsoluteScreenToOutputPixel( GetWindow()->OutputToAbsoluteScreenPixel( GetWindow()->GetPosPixel() ) );
tools::Rectangle aDockRect( aDockPos, GetWindow()->GetSizePixel() );
StartDocking( aMousePos, aDockRect );
GetWindow()->ImplUpdateAll();
GetWindow()->ImplGetFrameWindow()->ImplUpdateAll();
GetWindow()->StartTracking( StartTrackingFlags::KeyMod );
}
void ImplDockingWindowWrapper::Tracking( const TrackingEvent& rTEvt )
{
// used during docking of a currently docked window
if ( mbDocking )
{
if ( rTEvt.IsTrackingEnded() )
{
mbDocking = false;
GetWindow()->HideTracking();
if ( rTEvt.IsTrackingCanceled() )
{
mbDockCanceled = true;
EndDocking( tools::Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode );
mbDockCanceled = false;
}
else
EndDocking( tools::Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode );
}
// Docking only upon non-synthetic MouseEvents
else if ( !rTEvt.GetMouseEvent().IsSynthetic() || rTEvt.GetMouseEvent().IsModifierChanged() )
{
Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
Point aFrameMousePos = GetWindow()->ImplOutputToFrame( aMousePos );
Size aFrameSize = GetWindow()->ImplGetFrameWindow()->GetOutputSizePixel();
if ( aFrameMousePos.X() < 0 )
aFrameMousePos.setX( 0 );
if ( aFrameMousePos.Y() < 0 )
aFrameMousePos.setY( 0 );
if ( aFrameMousePos.X() > aFrameSize.Width()-1 )
aFrameMousePos.setX( aFrameSize.Width()-1 );
if ( aFrameMousePos.Y() > aFrameSize.Height()-1 )
aFrameMousePos.setY( aFrameSize.Height()-1 );
aMousePos = GetWindow()->ImplFrameToOutput( aFrameMousePos );
aMousePos.AdjustX( -(maMouseOff.X()) );
aMousePos.AdjustY( -(maMouseOff.Y()) );
Point aPos = GetWindow()->ImplOutputToFrame( aMousePos );
tools::Rectangle aTrackRect( aPos, Size( mnTrackWidth, mnTrackHeight ) );
tools::Rectangle aCompRect = aTrackRect;
aPos.AdjustX(maMouseOff.X() );
aPos.AdjustY(maMouseOff.Y() );
bool bFloatMode = Docking( aPos, aTrackRect );
if ( mbLastFloatMode != bFloatMode )
{
if ( bFloatMode )
{
aTrackRect.AdjustLeft( -mnDockLeft );
aTrackRect.AdjustTop( -mnDockTop );
aTrackRect.AdjustRight(mnDockRight );
aTrackRect.AdjustBottom(mnDockBottom );
}
else
{
if ( aCompRect == aTrackRect )
{
aTrackRect.AdjustLeft(mnDockLeft );
aTrackRect.AdjustTop(mnDockTop );
aTrackRect.AdjustRight( -mnDockRight );
aTrackRect.AdjustBottom( -mnDockBottom );
}
}
mbLastFloatMode = bFloatMode;
}
ShowTrackFlags nTrackStyle;
if ( bFloatMode )
nTrackStyle = ShowTrackFlags::Object;
else
nTrackStyle = ShowTrackFlags::Big;
tools::Rectangle aShowTrackRect = aTrackRect;
aShowTrackRect.SetPos( GetWindow()->ImplFrameToOutput( aShowTrackRect.TopLeft() ) );
GetWindow()->ShowTracking( aShowTrackRect, nTrackStyle );
// calculate mouse offset again, as the rectangle was changed
maMouseOff.setX( aPos.X() - aTrackRect.Left() );
maMouseOff.setY( aPos.Y() - aTrackRect.Top() );
mnTrackX = aTrackRect.Left();
mnTrackY = aTrackRect.Top();
mnTrackWidth = aTrackRect.GetWidth();
mnTrackHeight = aTrackRect.GetHeight();
}
}
}
void ImplDockingWindowWrapper::StartDocking( const Point& rPoint, tools::Rectangle const & rRect )
{
DockingData data( rPoint, rRect, IsFloatingMode() );
GetWindow()->CallEventListeners( VclEventId::WindowStartDocking, &data );
mbDocking = true;
}
bool ImplDockingWindowWrapper::Docking( const Point& rPoint, tools::Rectangle& rRect )
{
DockingData data( rPoint, rRect, IsFloatingMode() );
GetWindow()->CallEventListeners( VclEventId::WindowDocking, &data );
rRect = data.maTrackRect;
return data.mbFloating;
}
void ImplDockingWindowWrapper::EndDocking( const tools::Rectangle& rRect, bool bFloatMode )
{
tools::Rectangle aRect( rRect );
bool bOrigDockCanceled = mbDockCanceled;
if (bFloatMode && !StyleSettings::GetDockingFloatsSupported())
mbDockCanceled = true;
if ( !IsDockingCanceled() )
{
bool bShow = false;
if ( bFloatMode != IsFloatingMode() )
{
GetWindow()->Show( false, ShowFlags::NoFocusChange );
SetFloatingMode( bFloatMode );
bShow = true;
if ( bFloatMode )
{
// #i44800# always use outputsize - as in all other places
mpFloatWin->SetOutputSizePixel( aRect.GetSize() );
mpFloatWin->SetPosPixel( aRect.TopLeft() );
}
}
if ( !bFloatMode )
{
Point aPos = aRect.TopLeft();
aPos = GetWindow()->GetParent()->ScreenToOutputPixel( aPos );
GetWindow()->SetPosSizePixel( aPos, aRect.GetSize() );
}
if ( bShow )
GetWindow()->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
}
EndDockingData data( aRect, IsFloatingMode(), IsDockingCanceled() );
GetWindow()->CallEventListeners( VclEventId::WindowEndDocking, &data );
mbDocking = false;
// must be enabled in Window::Notify to prevent permanent docking during mouse move
mbStartDockingEnabled = false;
mbDockCanceled = bOrigDockCanceled;
}
bool ImplDockingWindowWrapper::PrepareToggleFloatingMode()
{
bool bFloating = true;
GetWindow()->CallEventListeners( VclEventId::WindowPrepareToggleFloating, &bFloating );
return bFloating;
}
void ImplDockingWindowWrapper::ToggleFloatingMode()
{
// notify dockingwindow/toolbox
// note: this must be done *before* notifying the
// listeners to have the toolbox in the proper state
if( GetWindow()->IsDockingWindow() )
static_cast<DockingWindow*>(GetWindow())->ToggleFloatingMode();
// now notify listeners
GetWindow()->CallEventListeners( VclEventId::WindowToggleFloating );
// must be enabled in Window::Notify to prevent permanent docking during mouse move
mbStartDockingEnabled = false;
}
void ImplDockingWindowWrapper::TitleButtonClick( TitleButton nType )
{
if( nType == TitleButton::Menu )
{
ToolBox *pToolBox = dynamic_cast< ToolBox* >( GetWindow() );
if( pToolBox )
{
pToolBox->ExecuteCustomMenu();
}
}
if( nType == TitleButton::Docking )
{
SetFloatingMode( !IsFloatingMode() );
}
}
void ImplDockingWindowWrapper::Resizing( Size& rSize )
{
// TODO: add virtual Resizing() to class Window, so we can get rid of class DockingWindow
DockingWindow *pDockingWindow = dynamic_cast< DockingWindow* >( GetWindow() );
if( pDockingWindow )
pDockingWindow->Resizing( rSize );
}
void ImplDockingWindowWrapper::ShowTitleButton( TitleButton nButton, bool bVisible )
{
if ( mpFloatWin )
mpFloatWin->ShowTitleButton( nButton, bVisible );
else
{
if ( nButton == TitleButton::Docking )
mbDockBtn = bVisible;
else // if ( nButton == TitleButton::Hide )
mbHideBtn = bVisible;
}
}
void ImplDockingWindowWrapper::ImplPreparePopupMode()
{
GetWindow()->Show( false, ShowFlags::NoFocusChange );
// prepare reparenting
vcl::Window* pRealParent = GetWindow()->GetWindow( GetWindowType::Parent );
mpOldBorderWin = GetWindow()->GetWindow( GetWindowType::Border );
if( mpOldBorderWin.get() == GetWindow() )
mpOldBorderWin = nullptr; // no border window found
// the new parent for popup mode
VclPtrInstance<ImplPopupFloatWin> pWin( mpParent, GetWindow()->GetType() == WindowType::TOOLBOX );
pWin->SetPopupModeEndHdl( LINK( this, ImplDockingWindowWrapper, PopupModeEnd ) );
// At least for DockingWindow, GetText() has a side effect of setting deferred
// properties. This must be done before setting the border window (see below),
// so that the border width will end up in mpWindowImpl->mnBorderWidth, not in
// the border window (See DockingWindow::setPosSizeOnContainee() and
// DockingWindow::GetOptimalSize()).
pWin->SetText( GetWindow()->GetText() );
pWin->SetOutputSizePixel( GetWindow()->GetSizePixel() );
GetWindow()->mpWindowImpl->mpBorderWindow = nullptr;
GetWindow()->mpWindowImpl->mnLeftBorder = 0;
GetWindow()->mpWindowImpl->mnTopBorder = 0;
GetWindow()->mpWindowImpl->mnRightBorder = 0;
GetWindow()->mpWindowImpl->mnBottomBorder = 0;
// reparent borderwindow and window
if ( mpOldBorderWin )
mpOldBorderWin->SetParent( pWin );
GetWindow()->SetParent( pWin );
// correct border window pointers
GetWindow()->mpWindowImpl->mpBorderWindow = pWin;
pWin->mpWindowImpl->mpClientWindow = GetWindow();
GetWindow()->mpWindowImpl->mpRealParent = pRealParent;
// set mpFloatWin not until all window positioning is done !!!
// (SetPosPixel etc. check for valid mpFloatWin pointer)
mpFloatWin = pWin;
}
void ImplDockingWindowWrapper::StartPopupMode( ToolBox *pParentToolBox, FloatWinPopupFlags nFlags )
{
// do nothing if window is floating
if( IsFloatingMode() )
return;
ImplPreparePopupMode();
// don't allow tearoff, if globally disabled
if( !StyleSettings::GetDockingFloatsSupported() ||
( GetWindow()->GetType() == WindowType::TOOLBOX && ToolBox::AlwaysLocked() ) )
nFlags &= ~FloatWinPopupFlags::AllowTearOff;
// if the subtoolbar was opened via keyboard make sure that key events
// will go into subtoolbar
if( pParentToolBox->IsKeyEvent() )
nFlags |= FloatWinPopupFlags::GrabFocus;
mpFloatWin->StartPopupMode( pParentToolBox, nFlags );
GetWindow()->Show();
if( pParentToolBox->IsKeyEvent() )
{
// send HOME key to subtoolbar in order to select first item
KeyEvent aEvent( 0, vcl::KeyCode( KEY_HOME ) );
GetWindow()->KeyInput(aEvent);
}
}
void ImplDockingWindowWrapper::StartPopupMode( const tools::Rectangle& rRect, FloatWinPopupFlags nFlags )
{
// do nothing if window is floating
if( IsFloatingMode() )
return;
ImplPreparePopupMode();
mpFloatWin->StartPopupMode( rRect, nFlags );
GetWindow()->Show();
}
IMPL_LINK_NOARG(ImplDockingWindowWrapper, PopupModeEnd, FloatingWindow*, void)
{
GetWindow()->Show( false, ShowFlags::NoFocusChange );
// set parameter for handler before destroying floating window
EndPopupModeData aData( mpFloatWin->GetWindow( GetWindowType::Border )->GetPosPixel(), mpFloatWin->IsPopupModeTearOff() );
// before deleting change parent back, so we can delete the floating window alone
vcl::Window* pRealParent = GetWindow()->GetWindow( GetWindowType::Parent );
GetWindow()->mpWindowImpl->mpBorderWindow = nullptr;
if ( mpOldBorderWin )
{
GetWindow()->SetParent( mpOldBorderWin );
static_cast<ImplBorderWindow*>(mpOldBorderWin.get())->GetBorder(
GetWindow()->mpWindowImpl->mnLeftBorder, GetWindow()->mpWindowImpl->mnTopBorder,
GetWindow()->mpWindowImpl->mnRightBorder, GetWindow()->mpWindowImpl->mnBottomBorder );
mpOldBorderWin->Resize();
}
GetWindow()->mpWindowImpl->mpBorderWindow = mpOldBorderWin;
GetWindow()->SetParent( pRealParent );
GetWindow()->mpWindowImpl->mpRealParent = pRealParent;
mpFloatWin.disposeAndClear();
// call handler - which will destroy the window and thus the wrapper as well !
GetWindow()->CallEventListeners( VclEventId::WindowEndPopupMode, &aData );
}
bool ImplDockingWindowWrapper::IsInPopupMode() const
{
if( GetFloatingWindow() )
return GetFloatingWindow()->IsInPopupMode();
else
return false;
}
void ImplDockingWindowWrapper::SetFloatingMode( bool bFloatMode )
{
// do nothing if window is docked and locked
if( !IsFloatingMode() && IsLocked() )
return;
if ( IsFloatingMode() != bFloatMode )
{
if ( PrepareToggleFloatingMode() )
{
bool bVisible = GetWindow()->IsVisible();
if ( bFloatMode )
{
GetWindow()->Show( false, ShowFlags::NoFocusChange );
maDockPos = GetWindow()->GetPosPixel();
vcl::Window* pRealParent = GetWindow()->GetWindow( GetWindowType::Parent );
mpOldBorderWin = GetWindow()->GetWindow( GetWindowType::Border );
if( mpOldBorderWin == mpDockingWindow )
mpOldBorderWin = nullptr; // no border window found
VclPtrInstance<ImplDockFloatWin2> pWin(
mpParent,
mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ?
mnFloatBits | WB_SYSTEMWINDOW
| WB_OWNERDRAWDECORATION
: mnFloatBits,
this );
// At least for DockingWindow, GetText() has a side effect of setting deferred
// properties. This must be done before setting the border window (see below),
// so that the border width will end up in mpWindowImpl->mnBorderWidth, not in
// the border window (See DockingWindow::setPosSizeOnContainee() and
// DockingWindow::GetOptimalSize()).
pWin->SetText( GetWindow()->GetText() );
GetWindow()->mpWindowImpl->mpBorderWindow = nullptr;
GetWindow()->mpWindowImpl->mnLeftBorder = 0;
GetWindow()->mpWindowImpl->mnTopBorder = 0;
GetWindow()->mpWindowImpl->mnRightBorder = 0;
GetWindow()->mpWindowImpl->mnBottomBorder = 0;
// if the parent gets destroyed, we also have to reset the parent of the BorderWindow
if ( mpOldBorderWin )
mpOldBorderWin->SetParent( pWin );
GetWindow()->SetParent( pWin );
pWin->SetPosPixel( Point() );
GetWindow()->mpWindowImpl->mpBorderWindow = pWin;
pWin->mpWindowImpl->mpClientWindow = mpDockingWindow;
GetWindow()->mpWindowImpl->mpRealParent = pRealParent;
pWin->SetOutputSizePixel( GetWindow()->GetSizePixel() );
pWin->SetPosPixel( maFloatPos );
// pass on DockingData to FloatingWindow
pWin->ShowTitleButton( TitleButton::Docking, mbDockBtn );
pWin->ShowTitleButton( TitleButton::Hide, mbHideBtn );
if ( mbRollUp )
pWin->RollUp();
else
pWin->RollDown();
pWin->SetRollUpOutputSizePixel( maRollUpOutSize );
pWin->SetMinOutputSizePixel( maMinOutSize );
pWin->SetMaxOutputSizePixel( maMaxOutSize );
mpFloatWin = pWin;
if ( bVisible )
GetWindow()->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
ToggleFloatingMode();
}
else
{
GetWindow()->Show( false, ShowFlags::NoFocusChange );
// store FloatingData in FloatingWindow
maFloatPos = mpFloatWin->GetPosPixel();
mbDockBtn = mpFloatWin->IsTitleButtonVisible( TitleButton::Docking );
mbHideBtn = mpFloatWin->IsTitleButtonVisible( TitleButton::Hide );
mbRollUp = mpFloatWin->IsRollUp();
maRollUpOutSize = mpFloatWin->GetRollUpOutputSizePixel();
maMinOutSize = mpFloatWin->GetMinOutputSizePixel();
maMaxOutSize = mpFloatWin->GetMaxOutputSizePixel();
vcl::Window* pRealParent = GetWindow()->GetWindow( GetWindowType::Parent ); //mpWindowImpl->mpRealParent;
GetWindow()->mpWindowImpl->mpBorderWindow = nullptr;
if ( mpOldBorderWin )
{
GetWindow()->SetParent( mpOldBorderWin );
static_cast<ImplBorderWindow*>(mpOldBorderWin.get())->GetBorder(
GetWindow()->mpWindowImpl->mnLeftBorder, GetWindow()->mpWindowImpl->mnTopBorder,
GetWindow()->mpWindowImpl->mnRightBorder, GetWindow()->mpWindowImpl->mnBottomBorder );
mpOldBorderWin->Resize();
}
GetWindow()->mpWindowImpl->mpBorderWindow = mpOldBorderWin;
GetWindow()->SetParent( pRealParent );
GetWindow()->mpWindowImpl->mpRealParent = pRealParent;
mpFloatWin.disposeAndClear();
GetWindow()->SetPosPixel( maDockPos );
if ( bVisible )
GetWindow()->Show();
ToggleFloatingMode();
}
}
}
}
void ImplDockingWindowWrapper::SetFloatStyle( WinBits nStyle )
{
mnFloatBits = nStyle;
}
void ImplDockingWindowWrapper::setPosSizePixel( long nX, long nY,
long nWidth, long nHeight,
PosSizeFlags nFlags )
{
if ( mpFloatWin )
mpFloatWin->setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
else
GetWindow()->setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
}
Point ImplDockingWindowWrapper::GetPosPixel() const
{
if ( mpFloatWin )
return mpFloatWin->GetPosPixel();
else
return mpDockingWindow->GetPosPixel();
}
Size ImplDockingWindowWrapper::GetSizePixel() const
{
if ( mpFloatWin )
return mpFloatWin->GetSizePixel();
else
return mpDockingWindow->GetSizePixel();
}
// old inlines from DockingWindow
void ImplDockingWindowWrapper::SetMinOutputSizePixel( const Size& rSize )
{
if ( mpFloatWin )
mpFloatWin->SetMinOutputSizePixel( rSize );
maMinOutSize = rSize;
}
void ImplDockingWindowWrapper::SetMaxOutputSizePixel( const Size& rSize )
{
if ( mpFloatWin )
mpFloatWin->SetMaxOutputSizePixel( rSize );
maMaxOutSize = rSize;
}
bool ImplDockingWindowWrapper::IsFloatingMode() const
{
return (mpFloatWin != nullptr);
}
void ImplDockingWindowWrapper::SetDragArea( const tools::Rectangle& rRect )
{
maDragArea = rRect;
}
void ImplDockingWindowWrapper::Lock()
{
mbLocked = true;
// only toolbars support locking
ToolBox *pToolBox = dynamic_cast< ToolBox * >( GetWindow() );
if( pToolBox )
pToolBox->Lock( mbLocked );
}
void ImplDockingWindowWrapper::Unlock()
{
mbLocked = false;
// only toolbars support locking
ToolBox *pToolBox = dynamic_cast< ToolBox * >( GetWindow() );
if( pToolBox )
pToolBox->Lock( mbLocked );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */