Files
libreoffice/vcl/source/window/dockwin.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

1062 lines
33 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 <vcl/accel.hxx>
#include <vcl/event.hxx>
#include <vcl/floatwin.hxx>
#include <vcl/dockwin.hxx>
#include <vcl/layout.hxx>
#include <vcl/svapp.hxx>
#include <vcl/timer.hxx>
#include <vcl/idle.hxx>
#include <vcl/settings.hxx>
#include <svdata.hxx>
#include <window.h>
#include <brdwin.hxx>
#define DOCKWIN_FLOATSTYLES (WB_SIZEABLE | WB_MOVEABLE | WB_CLOSEABLE | WB_STANDALONE | WB_ROLLABLE )
class DockingWindow::ImplData
{
public:
ImplData();
VclPtr<vcl::Window> mpParent;
Size maMaxOutSize;
};
DockingWindow::ImplData::ImplData()
{
mpParent = nullptr;
maMaxOutSize = Size( SHRT_MAX, SHRT_MAX );
}
namespace {
class ImplDockFloatWin : public FloatingWindow
{
private:
VclPtr<DockingWindow> mpDockWin;
sal_uInt64 const mnLastTicks;
Idle maDockIdle;
Point maDockPos;
tools::Rectangle maDockRect;
bool mbInMove;
ImplSVEvent * mnLastUserEvent;
DECL_LINK(DockingHdl, void *, void);
DECL_LINK(DockTimerHdl, Timer *, void);
public:
ImplDockFloatWin( vcl::Window* pParent, WinBits nWinBits,
DockingWindow* pDockingWin );
virtual ~ImplDockFloatWin() override;
virtual void dispose() override;
virtual void Move() override;
virtual void Resize() override;
virtual void Resizing( Size& rSize ) override;
virtual bool Close() override;
};
}
ImplDockFloatWin::ImplDockFloatWin( vcl::Window* pParent, WinBits nWinBits,
DockingWindow* pDockingWin ) :
FloatingWindow( pParent, nWinBits ),
mpDockWin( pDockingWin ),
mnLastTicks( tools::Time::GetSystemTicks() ),
mbInMove( false ),
mnLastUserEvent( nullptr )
{
// copy settings of DockingWindow
if ( pDockingWin )
{
SetSettings( pDockingWin->GetSettings() );
Enable( pDockingWin->IsEnabled(), false );
EnableInput( pDockingWin->IsInputEnabled(), false );
AlwaysEnableInput( pDockingWin->IsAlwaysEnableInput(), false );
EnableAlwaysOnTop( pDockingWin->IsAlwaysOnTopEnabled() );
SetActivateMode( pDockingWin->GetActivateMode() );
}
SetBackground();
maDockIdle.SetInvokeHandler( LINK( this, ImplDockFloatWin, DockTimerHdl ) );
maDockIdle.SetPriority( TaskPriority::HIGH_IDLE );
maDockIdle.SetDebugName( "vcl::ImplDockFloatWin maDockIdle" );
}
ImplDockFloatWin::~ImplDockFloatWin()
{
disposeOnce();
}
void ImplDockFloatWin::dispose()
{
if( mnLastUserEvent )
Application::RemoveUserEvent( mnLastUserEvent );
disposeBuilder();
mpDockWin.clear();
FloatingWindow::dispose();
}
IMPL_LINK_NOARG(ImplDockFloatWin, DockTimerHdl, Timer *, void)
{
SAL_WARN_IF( !mpDockWin->IsFloatingMode(), "vcl", "docktimer called but not floating" );
maDockIdle.Stop();
PointerState aState = GetPointerState();
if( aState.mnState & KEY_MOD1 )
{
// i43499 CTRL disables docking now
mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking();
mpDockWin->EndDocking( maDockRect, true );
if( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) )
maDockIdle.Start();
}
else if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) )
{
mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking();
mpDockWin->EndDocking( maDockRect, false );
}
else
{
mpDockWin->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, ShowTrackFlags::Big | ShowTrackFlags::TrackWindow );
maDockIdle.Start();
}
}
IMPL_LINK_NOARG(ImplDockFloatWin, DockingHdl, void*, void)
{
PointerState aState = mpDockWin->GetParent()->GetPointerState();
mnLastUserEvent = nullptr;
if( mpDockWin->IsDockable() &&
(tools::Time::GetSystemTicks() - mnLastTicks > 500) &&
( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) &&
!(aState.mnState & KEY_MOD1) ) // i43499 CTRL disables docking now
{
maDockPos = mpDockWin->GetParent()->AbsoluteScreenToOutputPixel( OutputToAbsoluteScreenPixel( Point() ) );
maDockPos = mpDockWin->GetParent()->OutputToScreenPixel( maDockPos ); // sfx expects screen coordinates
if( ! mpDockWin->IsDocking() )
mpDockWin->StartDocking();
maDockRect = tools::Rectangle( maDockPos, mpDockWin->GetSizePixel() );
// mouse pos also in screen pixels
Point aMousePos = mpDockWin->GetParent()->OutputToScreenPixel( aState.maPos );
bool bFloatMode = mpDockWin->Docking( aMousePos, maDockRect );
if( ! bFloatMode )
{
mpDockWin->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, ShowTrackFlags::Object | ShowTrackFlags::TrackWindow );
DockTimerHdl( nullptr );
}
else
{
mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking();
maDockIdle.Stop();
mpDockWin->EndDocking( maDockRect, true );
}
}
mbInMove = false;
}
void ImplDockFloatWin::Move()
{
if( mbInMove )
return;
mbInMove = true;
FloatingWindow::Move();
mpDockWin->Move();
/*
* note: the window should only dock if
* 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, ImplDockFloatWin, DockingHdl ), nullptr, true );
}
void ImplDockFloatWin::Resize()
{
FloatingWindow::Resize();
Size aSize( GetSizePixel() );
mpDockWin->ImplPosSizeWindow( 0, 0, aSize.Width(), aSize.Height(), PosSizeFlags::PosSize );
}
void ImplDockFloatWin::Resizing( Size& rSize )
{
FloatingWindow::Resizing( rSize );
mpDockWin->Resizing( rSize );
}
bool ImplDockFloatWin::Close()
{
return mpDockWin->Close();
}
void DockingWindow::ImplStartDocking( const Point& rPos )
{
if ( !mbDockable )
return;
maMouseOff = rPos;
mbDocking = true;
mbLastFloatMode = IsFloatingMode();
mbStartFloat = mbLastFloatMode;
// calculate FloatingBorder
VclPtr<FloatingWindow> pWin;
if ( mpFloatWin )
pWin = mpFloatWin;
else
pWin = VclPtr<ImplDockFloatWin>::Create( mpImplData->mpParent, mnFloatBits, nullptr );
pWin->GetBorder( mnDockLeft, mnDockTop, mnDockRight, mnDockBottom );
if ( !mpFloatWin )
pWin.disposeAndClear();
Point aPos = ImplOutputToFrame( Point() );
Size aSize = Window::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;
}
if ( GetSettings().GetStyleSettings().GetDragFullOptions() & DragFullOptions::Docking &&
!( mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ) ) // no full drag when migrating to system window
mbDragFull = true;
else
{
StartDocking();
mbDragFull = false;
ImplUpdateAll();
ImplGetFrameWindow()->ImplUpdateAll();
}
StartTracking( StartTrackingFlags::KeyMod );
}
void DockingWindow::ImplInitDockingWindowData()
{
mpWindowImpl->mbDockWin = true;
mpFloatWin = nullptr;
mpOldBorderWin = nullptr;
mpImplData.reset(new ImplData);
mnTrackX = 0;
mnTrackY = 0;
mnTrackWidth = 0;
mnTrackHeight = 0;
mnDockLeft = 0;
mnDockTop = 0;
mnDockRight = 0;
mnDockBottom = 0;
mnFloatBits = 0;
mbDockCanceled = false;
mbDockable = false;
mbDocking = false;
mbDragFull = false;
mbLastFloatMode = false;
mbStartFloat = false;
mbRollUp = false;
mbDockBtn = false;
mbHideBtn = false;
mbIsDeferredInit = false;
mbIsCalculatingInitialLayoutSize = false;
mpDialogParent = nullptr;
//To-Do, reuse maResizeTimer
maLayoutIdle.SetPriority(TaskPriority::RESIZE);
maLayoutIdle.SetInvokeHandler( LINK( this, DockingWindow, ImplHandleLayoutTimerHdl ) );
maLayoutIdle.SetDebugName( "vcl::DockingWindow maLayoutIdle" );
}
void DockingWindow::ImplInit( vcl::Window* pParent, WinBits nStyle )
{
if ( !(nStyle & WB_NODIALOGCONTROL) )
nStyle |= WB_DIALOGCONTROL;
mpImplData->mpParent = pParent;
mbDockable = (nStyle & WB_DOCKABLE) != 0;
mnFloatBits = WB_BORDER | (nStyle & DOCKWIN_FLOATSTYLES);
nStyle &= ~(DOCKWIN_FLOATSTYLES | WB_BORDER);
Window::ImplInit( pParent, nStyle, nullptr );
ImplInitSettings();
}
void DockingWindow::ImplInitSettings()
{
// Hack: to be able to build DockingWindows w/o background before switching
// TODO: Hack
if ( IsBackground() )
{
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
Color aColor;
if ( IsControlBackground() )
aColor = GetControlBackground();
else if ( Window::GetStyle() & WB_3DLOOK )
aColor = rStyleSettings.GetFaceColor();
else
aColor = rStyleSettings.GetWindowColor();
SetBackground( aColor );
}
}
DockingWindow::DockingWindow( WindowType nType ) :
Window(nType)
{
ImplInitDockingWindowData();
}
DockingWindow::DockingWindow( vcl::Window* pParent, WinBits nStyle ) :
Window( WindowType::DOCKINGWINDOW )
{
ImplInitDockingWindowData();
ImplInit( pParent, nStyle );
}
//Find the real parent stashed in mpDialogParent.
void DockingWindow::doDeferredInit(WinBits nBits)
{
vcl::Window *pParent = mpDialogParent;
mpDialogParent = nullptr;
ImplInit(pParent, nBits);
mbIsDeferredInit = false;
}
void DockingWindow::loadUI(vcl::Window* pParent, const OString& rID, const OUString& rUIXMLDescription,
const css::uno::Reference<css::frame::XFrame> &rFrame)
{
mbIsDeferredInit = true;
mpDialogParent = pParent; //should be unset in doDeferredInit
m_pUIBuilder.reset( new VclBuilder(this, getUIRootDir(), rUIXMLDescription, rID, rFrame) );
}
DockingWindow::DockingWindow(vcl::Window* pParent, const OString& rID,
const OUString& rUIXMLDescription, const css::uno::Reference<css::frame::XFrame> &rFrame)
: Window(WindowType::DOCKINGWINDOW)
{
ImplInitDockingWindowData();
loadUI(pParent, rID, rUIXMLDescription, rFrame);
}
DockingWindow::~DockingWindow()
{
disposeOnce();
}
void DockingWindow::dispose()
{
if ( IsFloatingMode() )
{
Show( false, ShowFlags::NoFocusChange );
SetFloatingMode(false);
}
mpImplData.reset();
mpFloatWin.clear();
mpOldBorderWin.clear();
mpDialogParent.clear();
disposeBuilder();
Window::dispose();
}
void DockingWindow::Tracking( const TrackingEvent& rTEvt )
{
if( GetDockingManager()->IsDockable( this ) ) // new docking interface
return Window::Tracking( rTEvt );
if ( mbDocking )
{
if ( rTEvt.IsTrackingEnded() )
{
mbDocking = false;
if ( mbDragFull )
{
// reset old state on Cancel
if ( rTEvt.IsTrackingCanceled() )
{
StartDocking();
tools::Rectangle aRect( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) );
EndDocking( aRect, mbStartFloat );
}
}
else
{
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 );
}
}
// dock only for non-synthetic MouseEvents
else if ( !rTEvt.GetMouseEvent().IsSynthetic() || rTEvt.GetMouseEvent().IsModifierChanged() )
{
Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
Point aFrameMousePos = ImplOutputToFrame( aMousePos );
Size aFrameSize = mpWindowImpl->mpFrameWindow->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 = ImplFrameToOutput( aFrameMousePos );
aMousePos.AdjustX( -(maMouseOff.X()) );
aMousePos.AdjustY( -(maMouseOff.Y()) );
Point aFramePos = ImplOutputToFrame( aMousePos );
tools::Rectangle aTrackRect( aFramePos, Size( mnTrackWidth, mnTrackHeight ) );
tools::Rectangle aCompRect = aTrackRect;
aFramePos.AdjustX(maMouseOff.X() );
aFramePos.AdjustY(maMouseOff.Y() );
if ( mbDragFull )
StartDocking();
bool bFloatMode = Docking( aFramePos, 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;
}
if ( mbDragFull )
{
Point aOldPos = OutputToScreenPixel( Point() );
EndDocking( aTrackRect, mbLastFloatMode );
// repaint if state or position has changed
if ( aOldPos != OutputToScreenPixel( Point() ) )
{
ImplUpdateAll();
ImplGetFrameWindow()->ImplUpdateAll();
}
// EndDocking( aTrackRect, mbLastFloatMode );
}
else
{
ShowTrackFlags nTrackStyle;
if ( bFloatMode )
nTrackStyle = ShowTrackFlags::Big;
else
nTrackStyle = ShowTrackFlags::Object;
tools::Rectangle aShowTrackRect = aTrackRect;
aShowTrackRect.SetPos( ImplFrameToOutput( aShowTrackRect.TopLeft() ) );
ShowTracking( aShowTrackRect, nTrackStyle );
// recalculate mouse offset, as the rectangle was changed
maMouseOff.setX( aFramePos.X() - aTrackRect.Left() );
maMouseOff.setY( aFramePos.Y() - aTrackRect.Top() );
}
mnTrackX = aTrackRect.Left();
mnTrackY = aTrackRect.Top();
mnTrackWidth = aTrackRect.GetWidth();
mnTrackHeight = aTrackRect.GetHeight();
}
}
}
bool DockingWindow::EventNotify( NotifyEvent& rNEvt )
{
if( GetDockingManager()->IsDockable( this ) ) // new docking interface
return Window::EventNotify( rNEvt );
if ( mbDockable )
{
const bool bDockingSupportCrippled = !StyleSettings::GetDockingFloatsSupported();
if ( rNEvt.GetType() == MouseNotifyEvent::MOUSEBUTTONDOWN )
{
const MouseEvent* pMEvt = rNEvt.GetMouseEvent();
if ( pMEvt->IsLeft() )
{
if (!bDockingSupportCrippled && pMEvt->IsMod1() && (pMEvt->GetClicks() == 2) )
{
SetFloatingMode( !IsFloatingMode() );
if ( IsFloatingMode() )
ToTop( ToTopFlags::GrabFocusOnly );
return true;
}
else if ( pMEvt->GetClicks() == 1 )
{
// check if window is floating standalone (IsFloating())
// or only partially floating and still docked with one border
// ( !mpWindowImpl->mbFrame)
if( ! IsFloatingMode() || ! mpFloatWin->mpWindowImpl->mbFrame )
{
Point aPos = pMEvt->GetPosPixel();
vcl::Window* pWindow = rNEvt.GetWindow();
if ( pWindow != this )
{
aPos = pWindow->OutputToScreenPixel( aPos );
aPos = ScreenToOutputPixel( aPos );
}
ImplStartDocking( aPos );
}
return true;
}
}
}
else if( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
{
const vcl::KeyCode& rKey = rNEvt.GetKeyEvent()->GetKeyCode();
if( rKey.GetCode() == KEY_F10 && rKey.GetModifier() &&
rKey.IsShift() && rKey.IsMod1() && !bDockingSupportCrippled )
{
SetFloatingMode( !IsFloatingMode() );
if ( IsFloatingMode() )
ToTop( ToTopFlags::GrabFocusOnly );
return true;
}
}
}
return Window::EventNotify( rNEvt );
}
void DockingWindow::StartDocking()
{
mbDocking = true;
}
bool DockingWindow::Docking( const Point&, tools::Rectangle& )
{
return IsFloatingMode();
}
void DockingWindow::EndDocking( const tools::Rectangle& rRect, bool bFloatMode )
{
bool bOrigDockCanceled = mbDockCanceled;
if (bFloatMode && !StyleSettings::GetDockingFloatsSupported())
mbDockCanceled = true;
if ( !IsDockingCanceled() )
{
if ( bFloatMode != IsFloatingMode() )
{
SetFloatingMode( bFloatMode );
if ( IsFloatingMode() )
ToTop( ToTopFlags::GrabFocusOnly );
if ( bFloatMode && mpFloatWin )
mpFloatWin->SetPosSizePixel( rRect.TopLeft(), rRect.GetSize() );
}
if ( !bFloatMode )
{
Point aPos = rRect.TopLeft();
aPos = GetParent()->ScreenToOutputPixel( aPos );
Window::SetPosSizePixel( aPos, rRect.GetSize() );
}
}
mbDocking = false;
mbDockCanceled = bOrigDockCanceled;
}
bool DockingWindow::PrepareToggleFloatingMode()
{
return true;
}
bool DockingWindow::Close()
{
VclPtr<vcl::Window> xWindow = this;
CallEventListeners( VclEventId::WindowClose );
if ( xWindow->IsDisposed() )
return false;
if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() )
return false;
Show( false, ShowFlags::NoFocusChange );
return true;
}
void DockingWindow::ToggleFloatingMode()
{
}
void DockingWindow::Resizing( Size& )
{
}
void DockingWindow::DoInitialLayout()
{
if (GetSettings().GetStyleSettings().GetAutoMnemonic())
Accelerator::GenerateAutoMnemonicsOnHierarchy(this);
if (isLayoutEnabled())
{
mbIsCalculatingInitialLayoutSize = true;
setDeferredProperties();
if (IsFloatingMode())
setOptimalLayoutSize();
mbIsCalculatingInitialLayoutSize = false;
}
}
void DockingWindow::StateChanged( StateChangedType nType )
{
switch(nType)
{
case StateChangedType::InitShow:
DoInitialLayout();
break;
case StateChangedType::ControlBackground:
ImplInitSettings();
Invalidate();
break;
case StateChangedType::Style:
mbDockable = (GetStyle() & WB_DOCKABLE) != 0;
break;
default:
break;
}
Window::StateChanged( nType );
}
void DockingWindow::DataChanged( const DataChangedEvent& rDCEvt )
{
if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
(rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
{
ImplInitSettings();
Invalidate();
}
else
Window::DataChanged( rDCEvt );
}
void DockingWindow::SetFloatingMode( bool bFloatMode )
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
pWrapper->SetFloatingMode( bFloatMode );
return;
}
if ( IsFloatingMode() != bFloatMode )
{
if ( PrepareToggleFloatingMode() ) // changes to floating mode can be vetoed
{
bool bVisible = IsVisible();
if ( bFloatMode )
{
// set deferred properties early, so border width will end up
// in our mpWindowImpl->mnBorderWidth, not in mpBorderWindow.
// (see its usage in setPosSizeOnContainee and GetOptimalSize.)
setDeferredProperties();
Show( false, ShowFlags::NoFocusChange );
maDockPos = Window::GetPosPixel();
vcl::Window* pRealParent = mpWindowImpl->mpRealParent;
mpOldBorderWin = mpWindowImpl->mpBorderWindow;
VclPtrInstance<ImplDockFloatWin> pWin(
mpImplData->mpParent,
mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ? mnFloatBits | WB_SYSTEMWINDOW : mnFloatBits,
this );
mpFloatWin = pWin;
mpWindowImpl->mpBorderWindow = nullptr;
mpWindowImpl->mnLeftBorder = 0;
mpWindowImpl->mnTopBorder = 0;
mpWindowImpl->mnRightBorder = 0;
mpWindowImpl->mnBottomBorder = 0;
// if the parent gets destroyed, we also have to reset the parent of the BorderWindow
if ( mpOldBorderWin )
mpOldBorderWin->SetParent( pWin );
// #i123765# reset the buffered DropTargets when undocking, else it may not
// be correctly initialized
mpWindowImpl->mxDNDListenerContainer.clear();
SetParent( pWin );
SetPosPixel( Point() );
mpWindowImpl->mpBorderWindow = pWin;
pWin->mpWindowImpl->mpClientWindow = this;
mpWindowImpl->mpRealParent = pRealParent;
pWin->SetText( Window::GetText() );
Size aSize(Window::GetSizePixel());
pWin->SetOutputSizePixel(aSize);
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( mpImplData->maMaxOutSize );
ToggleFloatingMode();
if ( bVisible )
Show();
}
else
{
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();
mpImplData->maMaxOutSize = mpFloatWin->GetMaxOutputSizePixel();
vcl::Window* pRealParent = mpWindowImpl->mpRealParent;
mpWindowImpl->mpBorderWindow = nullptr;
if ( mpOldBorderWin )
{
SetParent( mpOldBorderWin );
static_cast<ImplBorderWindow*>(mpOldBorderWin.get())->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
mpOldBorderWin->Resize();
}
mpWindowImpl->mpBorderWindow = mpOldBorderWin;
SetParent( pRealParent );
mpWindowImpl->mpRealParent = pRealParent;
mpFloatWin.disposeAndClear();
SetPosPixel( maDockPos );
ToggleFloatingMode();
if ( bVisible )
Show();
}
}
}
}
void DockingWindow::SetFloatStyle( WinBits nStyle )
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
pWrapper->SetFloatStyle( nStyle );
return;
}
mnFloatBits = nStyle;
}
WinBits DockingWindow::GetFloatStyle() const
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
return pWrapper->GetFloatStyle();
}
return mnFloatBits;
}
void DockingWindow::setPosSizePixel( long nX, long nY,
long nWidth, long nHeight,
PosSizeFlags nFlags )
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if (pWrapper)
{
if (!pWrapper->mpFloatWin)
Window::setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
}
else
{
if (!mpFloatWin)
Window::setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
else
{
mpFloatWin->SetOutputSizePixel(Size(nWidth, nHeight));
mpFloatWin->SetPosPixel(Point(nX, nY));
}
}
if (::isLayoutEnabled(this))
setPosSizeOnContainee();
}
Point DockingWindow::GetPosPixel() const
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
if ( pWrapper->mpFloatWin )
return pWrapper->mpFloatWin->GetPosPixel();
else
return Window::GetPosPixel();
}
if ( mpFloatWin )
return mpFloatWin->GetPosPixel();
else
return Window::GetPosPixel();
}
Size DockingWindow::GetSizePixel() const
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
if ( pWrapper->mpFloatWin )
return pWrapper->mpFloatWin->GetSizePixel();
else
return Window::GetSizePixel();
}
if ( mpFloatWin )
return mpFloatWin->GetSizePixel();
else
return Window::GetSizePixel();
}
void DockingWindow::SetOutputSizePixel( const Size& rNewSize )
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
if ( pWrapper->mpFloatWin )
pWrapper->mpFloatWin->SetOutputSizePixel( rNewSize );
else
Window::SetOutputSizePixel( rNewSize );
return;
}
if ( mpFloatWin )
mpFloatWin->SetOutputSizePixel( rNewSize );
else
Window::SetOutputSizePixel( rNewSize );
}
Size DockingWindow::GetOutputSizePixel() const
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
if ( pWrapper->mpFloatWin )
return pWrapper->mpFloatWin->GetOutputSizePixel();
else
return Window::GetOutputSizePixel();
}
if ( mpFloatWin )
return mpFloatWin->GetOutputSizePixel();
else
return Window::GetOutputSizePixel();
}
Point DockingWindow::GetFloatingPos() const
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
if ( pWrapper->mpFloatWin )
{
WindowStateData aData;
aData.SetMask( WindowStateMask::Pos );
pWrapper->mpFloatWin->GetWindowStateData( aData );
Point aPos( aData.GetX(), aData.GetY() );
aPos = pWrapper->mpFloatWin->GetParent()->ImplGetFrameWindow()->AbsoluteScreenToOutputPixel( aPos );
return aPos;
}
else
return maFloatPos;
}
if ( mpFloatWin )
{
WindowStateData aData;
aData.SetMask( WindowStateMask::Pos );
mpFloatWin->GetWindowStateData( aData );
Point aPos( aData.GetX(), aData.GetY() );
aPos = mpFloatWin->GetParent()->ImplGetFrameWindow()->AbsoluteScreenToOutputPixel( aPos );
return aPos;
}
else
return maFloatPos;
}
bool DockingWindow::IsFloatingMode() const
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
return pWrapper->IsFloatingMode();
else
return (mpFloatWin != nullptr);
}
void DockingWindow::SetMaxOutputSizePixel( const Size& rSize )
{
if ( mpFloatWin )
mpFloatWin->SetMaxOutputSizePixel( rSize );
mpImplData->maMaxOutSize = rSize;
}
void DockingWindow::SetText(const OUString& rStr)
{
setDeferredProperties();
Window::SetText(rStr);
}
OUString DockingWindow::GetText() const
{
const_cast<DockingWindow*>(this)->setDeferredProperties();
return Window::GetText();
}
bool DockingWindow::isLayoutEnabled() const
{
//pre dtor called, and single child is a container => we're layout enabled
return mpImplData && ::isLayoutEnabled(this);
}
void DockingWindow::setOptimalLayoutSize()
{
maLayoutIdle.Stop();
//resize DockingWindow to fit requisition on initial show
Size aSize = get_preferred_size();
Size aMax(bestmaxFrameSizeForScreenSize(GetDesktopRectPixel().GetSize()));
aSize.setWidth( std::min(aMax.Width(), aSize.Width()) );
aSize.setHeight( std::min(aMax.Height(), aSize.Height()) );
SetMinOutputSizePixel(aSize);
setPosSizeOnContainee();
}
void DockingWindow::setPosSizeOnContainee()
{
Size aSize = GetOutputSizePixel();
// Don't make the border width accessible via get_border_width(),
// otherwise the floating window will handle the border as well.
sal_Int32 nBorderWidth = mpWindowImpl->mnBorderWidth;
aSize.AdjustWidth( -(2 * nBorderWidth) );
aSize.AdjustHeight( -(2 * nBorderWidth) );
Window* pBox = GetWindow(GetWindowType::FirstChild);
assert(pBox);
VclContainer::setLayoutAllocation(*pBox, Point(nBorderWidth, nBorderWidth), aSize);
}
Size DockingWindow::GetOptimalSize() const
{
if (!isLayoutEnabled())
return Window::GetOptimalSize();
Size aSize = VclContainer::getLayoutRequisition(*GetWindow(GetWindowType::FirstChild));
// Don't make the border width accessible via get_border_width(),
// otherwise the floating window will handle the border as well.
sal_Int32 nBorderWidth = mpWindowImpl->mnBorderWidth;
aSize.AdjustHeight(2 * nBorderWidth );
aSize.AdjustWidth(2 * nBorderWidth );
return aSize;
}
void DockingWindow::queue_resize(StateChangedType eReason)
{
bool bTriggerLayout = true;
if (maLayoutIdle.IsActive() || mbIsCalculatingInitialLayoutSize)
{
bTriggerLayout = false;
}
if (!isLayoutEnabled())
{
bTriggerLayout = false;
}
if (bTriggerLayout)
{
InvalidateSizeCache();
maLayoutIdle.Start();
}
vcl::Window::queue_resize(eReason);
}
IMPL_LINK_NOARG(DockingWindow, ImplHandleLayoutTimerHdl, Timer*, void)
{
if (!isLayoutEnabled())
{
SAL_WARN("vcl.layout", "DockingWindow has become non-layout because extra children have been added directly to it.");
return;
}
setPosSizeOnContainee();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */