Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/dialog/dockwin.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <svl/eitem.hxx>
21
#include <svl/solar.hrc>
22
#include <vcl/event.hxx>
23
#include <vcl/settings.hxx>
24
25
#include <vcl/svapp.hxx>
26
#include <vcl/timer.hxx>
27
#include <vcl/idle.hxx>
28
#include <vcl/weld/Builder.hxx>
29
#include <o3tl/safeint.hxx>
30
#include <o3tl/string_view.hxx>
31
#include <osl/diagnose.h>
32
#include <toolkit/helper/vclunohelper.hxx>
33
#include <tools/debug.hxx>
34
#include <comphelper/processfactory.hxx>
35
#include <comphelper/propertysequence.hxx>
36
#include <svl/itemset.hxx>
37
38
#include <sfx2/chalign.hxx>
39
#include <sfx2/dockwin.hxx>
40
#include <sfx2/bindings.hxx>
41
#include <sfx2/viewfrm.hxx>
42
#include <sfx2/dispatch.hxx>
43
#include <workwin.hxx>
44
#include <splitwin.hxx>
45
#include <sfx2/viewsh.hxx>
46
47
#include <com/sun/star/beans/UnknownPropertyException.hpp>
48
#include <com/sun/star/lang/XSingleComponentFactory.hpp>
49
#include <com/sun/star/awt/XWindow.hpp>
50
#include <com/sun/star/uno/XComponentContext.hpp>
51
#include <com/sun/star/frame/ModuleManager.hpp>
52
#include <com/sun/star/container/XNameAccess.hpp>
53
#include <com/sun/star/ui/theWindowStateConfiguration.hpp>
54
#include <com/sun/star/ui/theWindowContentFactoryManager.hpp>
55
56
0
#define MAX_TOGGLEAREA_WIDTH        20
57
0
#define MAX_TOGGLEAREA_HEIGHT       20
58
59
using namespace ::com::sun::star;
60
61
// If you want to change the number you also have to:
62
// - Add new slot ids to sfxsids.hrc
63
// - Add new slots to frmslots.sdi
64
// - Add new slot definitions to sfx.sdi
65
const int NUM_OF_DOCKINGWINDOWS = 10;
66
67
namespace {
68
69
class SfxTitleDockingWindow : public SfxDockingWindow
70
{
71
    VclPtr<vcl::Window>   m_pWrappedWindow;
72
73
public:
74
                        SfxTitleDockingWindow(
75
                            SfxBindings* pBindings ,
76
                            SfxChildWindow* pChildWin ,
77
                            vcl::Window* pParent ,
78
                            WinBits nBits);
79
    virtual             ~SfxTitleDockingWindow() override;
80
    virtual void        dispose() override;
81
82
0
    vcl::Window*        GetWrappedWindow() const { return m_pWrappedWindow; }
83
    void                SetWrappedWindow(vcl::Window* const pWindow);
84
85
    virtual void        StateChanged( StateChangedType nType ) override;
86
    virtual void        Resize() override;
87
    virtual void        Resizing( Size& rSize ) override;
88
};
89
90
    struct WindowState
91
    {
92
        OUString sTitle;
93
    };
94
}
95
96
static bool lcl_getWindowState( const uno::Reference< container::XNameAccess >& xWindowStateMgr, const OUString& rResourceURL, WindowState& rWindowState )
97
0
{
98
0
    bool bResult = false;
99
100
0
    try
101
0
    {
102
0
        uno::Any a;
103
0
        uno::Sequence< beans::PropertyValue > aWindowState;
104
0
        a = xWindowStateMgr->getByName( rResourceURL );
105
0
        if ( a >>= aWindowState )
106
0
        {
107
0
            for (const auto& rProp : aWindowState)
108
0
            {
109
0
                if ( rProp.Name == "UIName" )
110
0
                {
111
0
                    rProp.Value >>= rWindowState.sTitle;
112
0
                }
113
0
            }
114
0
        }
115
116
0
        bResult = true;
117
0
    }
118
0
    catch ( container::NoSuchElementException& )
119
0
    {
120
0
        bResult = false;
121
0
    }
122
123
0
    return bResult;
124
0
}
125
126
SfxDockingWrapper::SfxDockingWrapper( vcl::Window* pParentWnd ,
127
                                      sal_uInt16 nId ,
128
                                      SfxBindings* pBindings ,
129
                                      SfxChildWinInfo* pInfo )
130
0
                    : SfxChildWindow( pParentWnd , nId )
131
0
{
132
0
    const uno::Reference< uno::XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
133
134
0
    VclPtr<SfxTitleDockingWindow> pTitleDockWindow = VclPtr<SfxTitleDockingWindow>::Create( pBindings, this, pParentWnd,
135
0
        WB_STDDOCKWIN | WB_CLIPCHILDREN | WB_SIZEABLE | WB_3DLOOK);
136
0
    SetWindow( pTitleDockWindow );
137
138
    // Use factory manager to retrieve XWindow factory. That can be used to instantiate
139
    // the real window factory.
140
0
    uno::Reference< lang::XSingleComponentFactory > xFactoryMgr = ui::theWindowContentFactoryManager::get(xContext);
141
142
0
    SfxDispatcher* pDispatcher = pBindings->GetDispatcher();
143
0
    uno::Reference< frame::XFrame > xFrame = pDispatcher->GetFrame()->GetFrame().GetFrameInterface();
144
    // create a resource URL from the nId provided by the sfx2
145
0
    OUString aResourceURL =  "private:resource/dockingwindow/" + OUString::number(nId);
146
0
    uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
147
0
    {
148
0
        {"Frame", uno::Any(xFrame)},
149
0
        {"ResourceURL", uno::Any(aResourceURL)},
150
0
    }));
151
152
0
    uno::Reference< awt::XWindow > xWindow;
153
0
    try
154
0
    {
155
0
        xWindow.set(
156
0
            xFactoryMgr->createInstanceWithArgumentsAndContext( aArgs, xContext ),
157
0
            uno::UNO_QUERY );
158
159
0
        static uno::WeakReference< frame::XModuleManager2 >  s_xModuleManager;
160
161
0
        uno::Reference< frame::XModuleManager2 > xModuleManager( s_xModuleManager );
162
0
        if ( !xModuleManager.is() )
163
0
        {
164
0
            xModuleManager = frame::ModuleManager::create(xContext);
165
0
            s_xModuleManager = xModuleManager;
166
0
        }
167
168
0
        static uno::WeakReference< container::XNameAccess > s_xWindowStateConfiguration;
169
170
0
        uno::Reference< container::XNameAccess > xWindowStateConfiguration( s_xWindowStateConfiguration );
171
0
        if ( !xWindowStateConfiguration.is() )
172
0
        {
173
0
            xWindowStateConfiguration = ui::theWindowStateConfiguration::get( xContext );
174
0
            s_xWindowStateConfiguration = xWindowStateConfiguration;
175
0
        }
176
177
0
        OUString sModuleIdentifier = xModuleManager->identify( xFrame );
178
179
0
        uno::Reference< container::XNameAccess > xModuleWindowState(
180
0
                                                    xWindowStateConfiguration->getByName( sModuleIdentifier ),
181
0
                                                    uno::UNO_QUERY );
182
0
        if ( xModuleWindowState.is() )
183
0
        {
184
0
            WindowState aDockWinState;
185
0
            if ( lcl_getWindowState( xModuleWindowState, aResourceURL, aDockWinState ))
186
0
                pTitleDockWindow->SetText( aDockWinState.sTitle );
187
0
        }
188
0
    }
189
0
    catch ( beans::UnknownPropertyException& )
190
0
    {
191
0
    }
192
0
    catch ( uno::RuntimeException& )
193
0
    {
194
0
    }
195
0
    catch ( uno::Exception& )
196
0
    {
197
0
    }
198
199
0
    VclPtr<vcl::Window> pContentWindow = VCLUnoHelper::GetWindow(xWindow);
200
0
    if ( pContentWindow )
201
0
        pContentWindow->SetStyle( pContentWindow->GetStyle() | WB_DIALOGCONTROL | WB_CHILDDLGCTRL );
202
0
    pTitleDockWindow->SetWrappedWindow(pContentWindow);
203
204
0
    GetWindow()->SetOutputSizePixel( Size( 270, 240 ) );
205
206
0
    static_cast<SfxDockingWindow*>( GetWindow() )->Initialize( pInfo );
207
0
    SetHideNotDelete( true );
208
0
}
209
210
std::unique_ptr<SfxChildWindow> SfxDockingWrapper::CreateImpl(vcl::Window *pParent, sal_uInt16 nId,
211
                                              SfxBindings *pBindings, SfxChildWinInfo* pInfo)
212
0
{
213
0
    return std::make_unique<SfxDockingWrapper>(pParent, nId, pBindings, pInfo);
214
0
}
215
216
void SfxDockingWrapper::RegisterChildWindow (bool bVis, SfxModule *pMod, SfxChildWindowFlags nFlags)
217
27
{
218
    // pre-register a couple of docking windows
219
297
    for (int i=0; i < NUM_OF_DOCKINGWINDOWS; i++ )
220
270
    {
221
270
        sal_uInt16 nID = sal_uInt16(SID_DOCKWIN_START+i);
222
270
        SfxChildWinFactory aFact( SfxDockingWrapper::CreateImpl, nID, 0xffff );
223
270
        aFact.aInfo.nFlags |= nFlags;
224
270
        aFact.aInfo.bVisible = bVis;
225
270
        SfxChildWindow::RegisterChildWindow(pMod, aFact);
226
270
    }
227
27
}
228
229
SfxChildWinInfo  SfxDockingWrapper::GetInfo() const
230
0
{
231
0
    SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
232
0
    static_cast<SfxDockingWindow*>(GetWindow())->FillInfo( aInfo );
233
0
    return aInfo;
234
0
};
235
236
SfxTitleDockingWindow::SfxTitleDockingWindow(SfxBindings* pBind, SfxChildWindow* pChildWin,
237
                                             vcl::Window* pParent, WinBits nBits)
238
0
    : SfxDockingWindow(pBind, pChildWin, pParent, nBits)
239
0
    , m_pWrappedWindow(nullptr)
240
0
{
241
0
}
242
243
SfxTitleDockingWindow::~SfxTitleDockingWindow()
244
0
{
245
0
    disposeOnce();
246
0
}
247
248
void SfxTitleDockingWindow::dispose()
249
0
{
250
0
    m_pWrappedWindow.disposeAndClear();
251
0
    SfxDockingWindow::dispose();
252
0
}
253
254
void SfxTitleDockingWindow::SetWrappedWindow( vcl::Window* const pWindow )
255
0
{
256
0
    m_pWrappedWindow = pWindow;
257
0
    if (m_pWrappedWindow)
258
0
    {
259
0
        m_pWrappedWindow->SetParent(this);
260
0
        m_pWrappedWindow->SetSizePixel( GetOutputSizePixel() );
261
0
        m_pWrappedWindow->Show();
262
0
    }
263
0
}
264
265
void SfxTitleDockingWindow::StateChanged( StateChangedType nType )
266
0
{
267
0
    if ( nType == StateChangedType::InitShow )
268
0
    {
269
0
        vcl::Window* pWindow = GetWrappedWindow();
270
0
        if ( pWindow )
271
0
        {
272
0
            pWindow->SetSizePixel( GetOutputSizePixel() );
273
0
            pWindow->Show();
274
0
        }
275
0
    }
276
277
0
    SfxDockingWindow::StateChanged(nType);
278
0
}
279
280
void SfxTitleDockingWindow::Resize()
281
0
{
282
0
    SfxDockingWindow::Resize();
283
0
    if (m_pWrappedWindow)
284
0
        m_pWrappedWindow->SetSizePixel( GetOutputSizePixel() );
285
0
}
286
287
void SfxTitleDockingWindow::Resizing( Size &rSize )
288
0
{
289
0
    SfxDockingWindow::Resizing( rSize );
290
0
    if (m_pWrappedWindow)
291
0
        m_pWrappedWindow->SetSizePixel( GetOutputSizePixel() );
292
0
}
293
294
static bool lcl_checkDockingWindowID( sal_uInt16 nID )
295
0
{
296
0
    return nID >= SID_DOCKWIN_START && nID < o3tl::make_unsigned(SID_DOCKWIN_START+NUM_OF_DOCKINGWINDOWS);
297
0
}
298
299
static SfxWorkWindow* lcl_getWorkWindowFromXFrame( const uno::Reference< frame::XFrame >& rFrame )
300
0
{
301
    // We need to find the corresponding SfxFrame of our XFrame
302
0
    SfxFrame* pFrame  = SfxFrame::GetFirst();
303
0
    SfxFrame* pXFrame = nullptr;
304
0
    while ( pFrame )
305
0
    {
306
0
        uno::Reference< frame::XFrame > xViewShellFrame( pFrame->GetFrameInterface() );
307
0
        if ( xViewShellFrame == rFrame )
308
0
        {
309
0
            pXFrame = pFrame;
310
0
            break;
311
0
        }
312
0
        else
313
0
            pFrame = SfxFrame::GetNext( *pFrame );
314
0
    }
315
316
    // If we have a SfxFrame we can retrieve the work window (Sfx layout manager for docking windows)
317
0
    if ( pXFrame )
318
0
        return pXFrame->GetWorkWindow_Impl();
319
0
    else
320
0
        return nullptr;
321
0
}
322
323
/** Factory function used by the framework layout manager to "create" a docking window with a special name.
324
    The string rDockingWindowName MUST BE a valid ID! The ID is pre-defined by a certain slot range located
325
    in sfxsids.hrc (currently SID_DOCKWIN_START = 9800).
326
*/
327
void SfxDockingWindowFactory( const uno::Reference< frame::XFrame >& rFrame, std::u16string_view rDockingWindowName )
328
0
{
329
0
    SolarMutexGuard aGuard;
330
0
    sal_uInt16 nID = sal_uInt16(o3tl::toInt32(rDockingWindowName));
331
332
    // Check the range of the provided ID otherwise nothing will happen
333
0
    if ( !lcl_checkDockingWindowID( nID ))
334
0
        return;
335
336
0
    SfxWorkWindow* pWorkWindow = lcl_getWorkWindowFromXFrame( rFrame );
337
0
    if ( pWorkWindow )
338
0
    {
339
0
        SfxChildWindow* pChildWindow = pWorkWindow->GetChildWindow_Impl(nID);
340
0
        if ( !pChildWindow )
341
0
        {
342
            // Register window at the workwindow child window list
343
0
            pWorkWindow->SetChildWindow_Impl( nID, true, false );
344
0
        }
345
0
    }
346
0
}
347
348
/** Function used by the framework layout manager to determine the visibility state of a docking window with
349
    a special name. The string rDockingWindowName MUST BE a valid ID! The ID is pre-defined by a certain slot
350
    range located in sfxsids.hrc (currently SID_DOCKWIN_START = 9800).
351
*/
352
bool IsDockingWindowVisible( const uno::Reference< frame::XFrame >& rFrame, std::u16string_view rDockingWindowName )
353
0
{
354
0
    SolarMutexGuard aGuard;
355
356
0
    sal_uInt16 nID = sal_uInt16(o3tl::toInt32(rDockingWindowName));
357
358
    // Check the range of the provided ID otherwise nothing will happen
359
0
    if ( lcl_checkDockingWindowID( nID ))
360
0
    {
361
0
        SfxWorkWindow* pWorkWindow = lcl_getWorkWindowFromXFrame( rFrame );
362
0
        if ( pWorkWindow )
363
0
        {
364
0
            SfxChildWindow* pChildWindow = pWorkWindow->GetChildWindow_Impl(nID);
365
0
            if ( pChildWindow )
366
0
                return true;
367
0
        }
368
0
    }
369
370
0
    return false;
371
0
}
372
373
class SfxDockingWindow_Impl
374
{
375
friend class SfxDockingWindow;
376
377
    SfxChildAlignment   eLastAlignment;
378
    SfxChildAlignment   eDockAlignment;
379
    bool                bConstructed;
380
    Size                aMinSize;
381
    VclPtr<SfxSplitWindow>  pSplitWin;
382
    Idle                aMoveIdle;
383
384
    // The following members are only valid in the time from startDocking to
385
    // EndDocking:
386
    Size                aSplitSize;
387
    tools::Long                nHorizontalSize;
388
    tools::Long                nVerticalSize;
389
    sal_uInt16          nLine;
390
    sal_uInt16          nPos;
391
    sal_uInt16          nDockLine;
392
    sal_uInt16          nDockPos;
393
    bool                bNewLine;
394
    bool                bDockingPrevented;
395
    OUString            aWinState;
396
397
    explicit            SfxDockingWindow_Impl(SfxDockingWindow *pBase);
398
    SfxChildAlignment   GetLastAlignment() const
399
0
                        { return eLastAlignment; }
400
    void                SetLastAlignment(SfxChildAlignment eAlign)
401
0
                        { eLastAlignment = eAlign; }
402
    SfxChildAlignment   GetDockAlignment() const
403
0
                        { return eDockAlignment; }
404
    void                SetDockAlignment(SfxChildAlignment eAlign)
405
0
                        { eDockAlignment = eAlign; }
406
};
407
408
SfxDockingWindow_Impl::SfxDockingWindow_Impl(SfxDockingWindow* pBase)
409
0
    :eLastAlignment(SfxChildAlignment::NOALIGNMENT)
410
0
    ,eDockAlignment(SfxChildAlignment::NOALIGNMENT)
411
0
    ,bConstructed(false)
412
0
    ,pSplitWin(nullptr)
413
0
    ,aMoveIdle( "sfx::SfxDockingWindow_Impl aMoveIdle" )
414
0
    ,nHorizontalSize(0)
415
0
    ,nVerticalSize(0)
416
0
    ,nLine(0)
417
0
    ,nPos(0)
418
0
    ,nDockLine(0)
419
0
    ,nDockPos(0)
420
0
    ,bNewLine(false)
421
0
    ,bDockingPrevented(false)
422
0
{
423
0
    aMoveIdle.SetPriority(TaskPriority::RESIZE);
424
0
    aMoveIdle.SetInvokeHandler(LINK(pBase,SfxDockingWindow,TimerHdl));
425
0
}
426
427
/*  [Description]
428
429
    This virtual method of the class FloatingWindow keeps track of changes in
430
    FloatingSize. If this method is overridden by a derived class,
431
    then the FloatingWindow: Resize() must also be called.
432
*/
433
void SfxDockingWindow::Resize()
434
0
{
435
0
    ResizableDockingWindow::Resize();
436
0
    Invalidate();
437
0
    if ( !pImpl || !pImpl->bConstructed || !pMgr )
438
0
        return;
439
440
0
    if ( IsFloatingMode() )
441
0
    {
442
        // start timer for saving window status information
443
0
        pImpl->aMoveIdle.Start();
444
0
    }
445
0
    else
446
0
    {
447
0
        Size aSize( GetSizePixel() );
448
0
        switch ( pImpl->GetDockAlignment() )
449
0
        {
450
0
            case SfxChildAlignment::LEFT:
451
0
            case SfxChildAlignment::FIRSTLEFT:
452
0
            case SfxChildAlignment::LASTLEFT:
453
0
            case SfxChildAlignment::RIGHT:
454
0
            case SfxChildAlignment::FIRSTRIGHT:
455
0
            case SfxChildAlignment::LASTRIGHT:
456
0
                pImpl->nHorizontalSize = aSize.Width();
457
0
                pImpl->aSplitSize = aSize;
458
0
                break;
459
0
            case SfxChildAlignment::TOP:
460
0
            case SfxChildAlignment::LOWESTTOP:
461
0
            case SfxChildAlignment::HIGHESTTOP:
462
0
            case SfxChildAlignment::BOTTOM:
463
0
            case SfxChildAlignment::HIGHESTBOTTOM:
464
0
            case SfxChildAlignment::LOWESTBOTTOM:
465
0
                pImpl->nVerticalSize = aSize.Height();
466
0
                pImpl->aSplitSize = aSize;
467
0
                break;
468
0
            default:
469
0
                break;
470
0
        }
471
0
    }
472
0
}
473
474
/*  [Description]
475
476
    This virtual method of the class DockingWindow makes it possible to
477
    intervene in the switching of the floating mode.
478
    If this method is overridden by a derived class,
479
    then the SfxDockingWindow::PrepareToggleFloatingMode() must be called
480
    afterwards, if not FALSE is returned.
481
*/
482
bool SfxDockingWindow::PrepareToggleFloatingMode()
483
0
{
484
0
    if (!pImpl || !pImpl->bConstructed)
485
0
        return true;
486
487
0
    if ( (Application::IsInModalMode() && IsFloatingMode()) || !pMgr )
488
0
        return false;
489
490
0
    if ( pImpl->bDockingPrevented )
491
0
        return false;
492
493
0
    if (!IsFloatingMode())
494
0
    {
495
        // Test, if FloatingMode is permitted.
496
0
        if ( CheckAlignment(GetAlignment(),SfxChildAlignment::NOALIGNMENT) != SfxChildAlignment::NOALIGNMENT )
497
0
            return false;
498
499
0
        if ( pImpl->pSplitWin )
500
0
        {
501
            // The DockingWindow is inside a SplitWindow and will be teared of.
502
0
            pImpl->pSplitWin->RemoveWindow(this/*, sal_False*/);
503
0
            pImpl->pSplitWin = nullptr;
504
0
        }
505
0
    }
506
0
    else if ( pMgr )
507
0
    {
508
0
        pImpl->aWinState = GetFloatingWindow()->GetWindowState();
509
510
        // Test if it is allowed to dock,
511
0
        if (CheckAlignment(GetAlignment(),pImpl->GetLastAlignment()) == SfxChildAlignment::NOALIGNMENT)
512
0
            return false;
513
514
        // Test, if the Workwindow allows for docking at the moment.
515
0
        SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
516
0
        if ( !pWorkWin->IsDockingAllowed() || !pWorkWin->IsInternalDockingAllowed() )
517
0
            return false;
518
0
    }
519
520
0
    return true;
521
0
}
522
523
/*  [Description]
524
525
    This virtual method of the DockingWindow class sets the internal data of
526
    the SfxDockingWindow and ensures the correct alignment on the parent window.
527
    Through PrepareToggleFloatMode and Initialize it is ensured that
528
    pImpl-> GetLastAlignment() always delivers an allowed alignment. If this
529
    method is overridden by a derived class, then first the
530
    SfxDockingWindow::ToggleFloatingMode() must be called.
531
*/
532
void SfxDockingWindow::ToggleFloatingMode()
533
0
{
534
0
    if ( !pImpl || !pImpl->bConstructed || !pMgr )
535
0
        return;                                 // No Handler call
536
537
    // Remember old alignment and then switch.
538
    // SV has already switched, but the alignment SfxDockingWindow is still
539
    // the old one. What I was before?
540
0
    SfxChildAlignment eLastAlign = GetAlignment();
541
542
0
    SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
543
544
0
    if (IsFloatingMode())
545
0
    {
546
0
        SetAlignment(SfxChildAlignment::NOALIGNMENT);
547
0
        if ( !pImpl->aWinState.isEmpty() )
548
0
            GetFloatingWindow()->SetWindowState( pImpl->aWinState );
549
0
        else
550
0
            GetFloatingWindow()->SetOutputSizePixel( GetFloatingSize() );
551
0
    }
552
0
    else
553
0
    {
554
0
        if (pImpl->GetDockAlignment() == eLastAlign)
555
0
        {
556
            // If ToggleFloatingMode was called, but the DockAlignment still
557
            // is unchanged, then this means that it must have been a toggling
558
            // through DClick, so use last alignment
559
0
            SetAlignment (pImpl->GetLastAlignment());
560
0
        }
561
0
        else
562
0
        {
563
564
            // Toggling was triggered by dragging
565
0
            pImpl->nLine = pImpl->nDockLine;
566
0
            pImpl->nPos = pImpl->nDockPos;
567
0
            SetAlignment (pImpl->GetDockAlignment());
568
0
        }
569
570
        // The DockingWindow is now in a SplitWindow
571
0
        pImpl->pSplitWin = pWorkWin->GetSplitWindow_Impl(GetAlignment());
572
573
        // The LastAlignment is still the last docked
574
0
        SfxSplitWindow *pSplit = pWorkWin->GetSplitWindow_Impl(pImpl->GetLastAlignment());
575
576
0
        DBG_ASSERT( pSplit, "LastAlignment is not correct!" );
577
0
        if ( pSplit && pSplit != pImpl->pSplitWin )
578
0
            pSplit->ReleaseWindow_Impl(this);
579
0
        if ( pImpl->GetDockAlignment() == eLastAlign )
580
0
            pImpl->pSplitWin->InsertWindow( this, pImpl->aSplitSize );
581
0
        else
582
0
            pImpl->pSplitWin->InsertWindow( this, pImpl->aSplitSize, pImpl->nLine, pImpl->nPos, pImpl->bNewLine );
583
0
        if ( !pImpl->pSplitWin->IsFadeIn() )
584
0
            pImpl->pSplitWin->FadeIn();
585
0
    }
586
587
    // Keep the old alignment for the next toggle; set it only now due to the
588
    // unregister SplitWindow!
589
0
    pImpl->SetLastAlignment(eLastAlign);
590
591
    // Reset DockAlignment, if EndDocking is still called
592
0
    pImpl->SetDockAlignment(GetAlignment());
593
594
    // Dock or undock SfxChildWindow correctly.
595
0
    pWorkWin->ConfigChild_Impl( SfxChildIdentifier::SPLITWINDOW, SfxDockingConfig::TOGGLEFLOATMODE, pMgr->GetType() );
596
0
}
597
598
/*  [Description]
599
600
    This virtual method of the DockingWindow class takes the inner and outer
601
    docking rectangle from the parent window. If this method is overridden by
602
    a derived class, then SfxDockingWindow:StartDocking() has to be called at
603
    the end.
604
*/
605
void SfxDockingWindow::StartDocking()
606
0
{
607
0
    if ( !pImpl || !pImpl->bConstructed || !pMgr )
608
0
        return;
609
0
    SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
610
0
    pWorkWin->ConfigChild_Impl( SfxChildIdentifier::SPLITWINDOW, SfxDockingConfig::SETDOCKINGRECTS, pMgr->GetType() );
611
0
    pImpl->SetDockAlignment(GetAlignment());
612
613
0
    if ( pImpl->pSplitWin )
614
0
    {
615
        // Get the current docking data
616
0
        pImpl->pSplitWin->GetWindowPos(this, pImpl->nLine, pImpl->nPos);
617
0
        pImpl->nDockLine = pImpl->nLine;
618
0
        pImpl->nDockPos = pImpl->nPos;
619
0
        pImpl->bNewLine = false;
620
0
    }
621
0
}
622
623
/*  [Description]
624
625
    This virtual method of the DockingWindow class calculates the current
626
    tracking rectangle. For this purpose the method CalcAlignment(RPOs, rRect)
627
    is used, the behavior can be influenced by the derived classes (see below).
628
    This method should if possible not be overwritten.
629
*/
630
bool SfxDockingWindow::Docking( const Point& rPos, tools::Rectangle& rRect )
631
0
{
632
0
    if ( Application::IsInModalMode() )
633
0
        return true;
634
635
0
    if ( !pImpl || !pImpl->bConstructed || !pMgr )
636
0
    {
637
0
        rRect.SetSize( Size() );
638
0
        return IsFloatingMode();
639
0
    }
640
641
0
    SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
642
0
    if ( pImpl->bDockingPrevented || !pWorkWin->IsInternalDockingAllowed() )
643
0
        return false;
644
645
0
    bool bFloatMode = false;
646
647
0
    if ( GetOuterRect().Contains( rPos ) )
648
0
    {
649
        // Mouse within OuterRect: calculate Alignment and Rectangle
650
0
        SfxChildAlignment eAlign = CalcAlignment(rPos, rRect);
651
0
        if (eAlign == SfxChildAlignment::NOALIGNMENT)
652
0
            bFloatMode = true;
653
0
        pImpl->SetDockAlignment(eAlign);
654
0
    }
655
0
    else
656
0
    {
657
        // Mouse is not within OuterRect: must be FloatingWindow
658
        // Is this allowed?
659
0
        if (CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::NOALIGNMENT) != SfxChildAlignment::NOALIGNMENT)
660
0
            return false;
661
0
        bFloatMode = true;
662
0
        if ( SfxChildAlignment::NOALIGNMENT != pImpl->GetDockAlignment() )
663
0
        {
664
            // Due to a bug the rRect may only be changed when the
665
            // alignment is changed!
666
0
            pImpl->SetDockAlignment(SfxChildAlignment::NOALIGNMENT);
667
0
            rRect.SetSize(CalcDockingSize(SfxChildAlignment::NOALIGNMENT));
668
0
        }
669
0
    }
670
671
0
    return bFloatMode;
672
0
}
673
674
/** Virtual method of the DockingWindow class ensures the correct alignment on
675
    the parent window. If this method is overridden by a derived class, then
676
    SfxDockingWindow::EndDocking() must be called first.
677
*/
678
void SfxDockingWindow::EndDocking( const tools::Rectangle& rRect, bool bFloatMode )
679
0
{
680
0
    if ( !pImpl || !pImpl->bConstructed || IsDockingCanceled() || !pMgr )
681
0
        return;
682
683
0
    SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
684
685
    // If the alignment changes and the window is in a docked state in a
686
    // SplitWindow, then it must be re-registered. If it is docked again,
687
    // PrepareToggleFloatingMode() and ToggleFloatingMode() perform the
688
    // re-registered
689
0
    bool bReArrange = !bFloatMode;
690
691
0
    if ( bReArrange )
692
0
    {
693
0
        if ( GetAlignment() != pImpl->GetDockAlignment() )
694
0
        {
695
            // before Show() is called must the reassignment have been made,
696
            // therefore the base class can not be called
697
0
            if ( IsFloatingMode() )
698
0
                Show( false, ShowFlags::NoFocusChange );
699
700
            // Set the size for toggling.
701
0
            pImpl->aSplitSize = rRect.GetSize();
702
0
            if ( IsFloatingMode() )
703
0
            {
704
0
                SetFloatingMode( bFloatMode );
705
0
                if ( IsFloatingMode() )
706
0
                    Show( true, ShowFlags::NoFocusChange );
707
0
            }
708
0
            else
709
0
            {
710
0
                pImpl->pSplitWin->RemoveWindow(this,false);
711
0
                pImpl->nLine = pImpl->nDockLine;
712
0
                pImpl->nPos = pImpl->nDockPos;
713
0
                pImpl->pSplitWin->ReleaseWindow_Impl(this);
714
0
                pImpl->pSplitWin = pWorkWin->GetSplitWindow_Impl(pImpl->GetDockAlignment());
715
0
                pImpl->pSplitWin->InsertWindow( this, pImpl->aSplitSize, pImpl->nDockLine, pImpl->nDockPos, pImpl->bNewLine );
716
0
                if ( !pImpl->pSplitWin->IsFadeIn() )
717
0
                    pImpl->pSplitWin->FadeIn();
718
0
            }
719
0
        }
720
0
        else if ( pImpl->nLine != pImpl->nDockLine || pImpl->nPos != pImpl->nDockPos || pImpl->bNewLine )
721
0
        {
722
            // Moved within Splitwindows
723
0
            if ( pImpl->nLine != pImpl->nDockLine )
724
0
                pImpl->aSplitSize = rRect.GetSize();
725
0
            pImpl->pSplitWin->MoveWindow( this, pImpl->aSplitSize, pImpl->nDockLine, pImpl->nDockPos, pImpl->bNewLine );
726
0
        }
727
0
    }
728
0
    else
729
0
    {
730
0
        ResizableDockingWindow::EndDocking(rRect, bFloatMode);
731
0
    }
732
733
0
    SetAlignment( IsFloatingMode() ? SfxChildAlignment::NOALIGNMENT : pImpl->GetDockAlignment() );
734
0
}
735
736
/*  [Description]
737
738
    Virtual method of the DockingWindow class. Here, the interactive resize in
739
    FloatingMode can be influenced, for example by only allowing for discrete
740
    values for width and / or height. The base implementation prevents that the
741
    output size is smaller than one set with SetMinOutputSizePixel().
742
*/
743
void SfxDockingWindow::Resizing( Size& /*rSize*/ )
744
0
{
745
746
0
}
747
748
/*  [Description]
749
750
    Constructor for the SfxDockingWindow class. A SfxChildWindow will be
751
    required because the docking is implemented in Sfx through SfxChildWindows.
752
*/
753
SfxDockingWindow::SfxDockingWindow( SfxBindings *pBindinx, SfxChildWindow *pCW,
754
    vcl::Window* pParent, WinBits nWinBits)
755
0
    : ResizableDockingWindow(pParent, nWinBits)
756
0
    , pBindings(pBindinx)
757
0
    , pMgr(pCW)
758
0
{
759
0
    pImpl.reset(new SfxDockingWindow_Impl(this));
760
0
}
Unexecuted instantiation: SfxDockingWindow::SfxDockingWindow(SfxBindings*, SfxChildWindow*, vcl::Window*, long)
Unexecuted instantiation: SfxDockingWindow::SfxDockingWindow(SfxBindings*, SfxChildWindow*, vcl::Window*, long)
761
762
/** Constructor for the SfxDockingWindow class. A SfxChildWindow will be
763
    required because the docking is implemented in Sfx through SfxChildWindows.
764
*/
765
SfxDockingWindow::SfxDockingWindow( SfxBindings *pBindinx, SfxChildWindow *pCW,
766
    vcl::Window* pParent, const OUString& rID, const OUString& rUIXMLDescription)
767
0
    : ResizableDockingWindow(pParent)
768
0
    , pBindings(pBindinx)
769
0
    , pMgr(pCW)
770
0
{
771
0
    m_xBuilder = Application::CreateInterimBuilder(m_xBox, rUIXMLDescription, true);
772
0
    m_xContainer = m_xBuilder->weld_box(rID);
773
774
0
    pImpl.reset(new SfxDockingWindow_Impl(this));
775
0
}
Unexecuted instantiation: SfxDockingWindow::SfxDockingWindow(SfxBindings*, SfxChildWindow*, vcl::Window*, rtl::OUString const&, rtl::OUString const&)
Unexecuted instantiation: SfxDockingWindow::SfxDockingWindow(SfxBindings*, SfxChildWindow*, vcl::Window*, rtl::OUString const&, rtl::OUString const&)
776
777
/** Initialization of the SfxDockingDialog class via a SfxChildWinInfo.
778
    The initialization is done only in a 2nd step after the constructor, this
779
    constructor should be called from the derived class or from the
780
    SfxChildWindows.
781
*/
782
void SfxDockingWindow::Initialize(SfxChildWinInfo *pInfo)
783
0
{
784
0
    if ( !pMgr )
785
0
    {
786
0
        pImpl->SetDockAlignment( SfxChildAlignment::NOALIGNMENT );
787
0
        pImpl->bConstructed = true;
788
0
        return;
789
0
    }
790
791
0
    if (pInfo && (pInfo->nFlags & SfxChildWindowFlags::FORCEDOCK))
792
0
        pImpl->bDockingPrevented = true;
793
794
0
    pImpl->aSplitSize = GetOutputSizePixel();
795
0
    if ( !GetFloatingSize().Width() )
796
0
    {
797
0
        Size aMinSize( GetMinOutputSizePixel() );
798
0
        SetFloatingSize( pImpl->aSplitSize );
799
0
        if ( pImpl->aSplitSize.Width() < aMinSize.Width() )
800
0
            pImpl->aSplitSize.setWidth( aMinSize.Width() );
801
0
        if ( pImpl->aSplitSize.Height() < aMinSize.Height() )
802
0
            pImpl->aSplitSize.setHeight( aMinSize.Height() );
803
0
    }
804
805
0
    bool bVertHorzRead( false );
806
0
    if (pInfo && !pInfo->aExtraString.isEmpty())
807
0
    {
808
        // get information about alignment, split size and position in SplitWindow
809
0
        OUString aStr;
810
0
        sal_Int32 nPos = pInfo->aExtraString.indexOf("AL:");
811
0
        if ( nPos != -1 )
812
0
        {
813
            // alignment information
814
0
            sal_Int32 n1 = pInfo->aExtraString.indexOf('(', nPos);
815
0
            if ( n1 != -1 )
816
0
            {
817
0
                sal_Int32 n2 = pInfo->aExtraString.indexOf(')', n1);
818
0
                if ( n2 != -1 )
819
0
                {
820
                    // extract alignment information from extrastring
821
0
                    aStr = pInfo->aExtraString.copy(nPos, n2 - nPos + 1);
822
0
                    pInfo->aExtraString = pInfo->aExtraString.replaceAt(nPos, n2 - nPos + 1, u"");
823
0
                    aStr = aStr.replaceAt(nPos, n1-nPos+1, u"");
824
0
                }
825
0
            }
826
0
        }
827
828
0
        if ( !aStr.isEmpty() )
829
0
        {
830
            // accept window state only if alignment is also set
831
0
            pImpl->aWinState = pInfo->aWinState;
832
833
            // check for valid alignment
834
0
            SfxChildAlignment eLocalAlignment = static_cast<SfxChildAlignment>(static_cast<sal_uInt16>(aStr.toInt32()));
835
0
            bool bIgnoreFloatConfig = (eLocalAlignment == SfxChildAlignment::NOALIGNMENT &&
836
0
                                       !StyleSettings::GetDockingFloatsSupported());
837
0
            if (pImpl->bDockingPrevented || bIgnoreFloatConfig)
838
                // docking prevented, ignore old configuration and take alignment from default
839
0
                aStr.clear();
840
0
            else
841
0
                SetAlignment( eLocalAlignment );
842
843
0
            SfxChildAlignment eAlign = CheckAlignment(GetAlignment(),GetAlignment());
844
0
            if ( eAlign != GetAlignment() )
845
0
            {
846
0
                OSL_FAIL("Invalid Alignment!");
847
0
                SetAlignment( eAlign );
848
0
                aStr.clear();
849
0
            }
850
851
            // get last alignment (for toggling)
852
0
            nPos = aStr.indexOf(',');
853
0
            if ( nPos != -1 )
854
0
            {
855
0
                aStr = aStr.copy(nPos+1);
856
0
                pImpl->SetLastAlignment( static_cast<SfxChildAlignment>(static_cast<sal_uInt16>(aStr.toInt32())) );
857
0
            }
858
859
0
            nPos = aStr.indexOf(',');
860
0
            if ( nPos != -1 )
861
0
            {
862
                // get split size and position in SplitWindow
863
0
                Point aPos;
864
0
                aStr = aStr.copy(nPos+1);
865
0
                if ( GetPosSizeFromString( aStr, aPos, pImpl->aSplitSize ) )
866
0
                {
867
0
                    pImpl->nLine = pImpl->nDockLine = static_cast<sal_uInt16>(aPos.X());
868
0
                    pImpl->nPos  = pImpl->nDockPos  = static_cast<sal_uInt16>(aPos.Y());
869
0
                    pImpl->nVerticalSize = pImpl->aSplitSize.Height();
870
0
                    pImpl->nHorizontalSize = pImpl->aSplitSize.Width();
871
0
                    if ( GetSplitSizeFromString( aStr, pImpl->aSplitSize ))
872
0
                        bVertHorzRead = true;
873
0
                }
874
0
            }
875
0
        }
876
0
        else {
877
0
            OSL_FAIL( "Information is missing!" );
878
0
        }
879
0
    }
880
881
0
    if ( !bVertHorzRead )
882
0
    {
883
0
        pImpl->nVerticalSize = pImpl->aSplitSize.Height();
884
0
        pImpl->nHorizontalSize = pImpl->aSplitSize.Width();
885
0
    }
886
887
0
    SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
888
0
    if ( GetAlignment() != SfxChildAlignment::NOALIGNMENT )
889
0
    {
890
        // check if SfxWorkWindow is able to allow docking at its border
891
0
        if (
892
0
            !pWorkWin->IsDockingAllowed() ||
893
0
            !pWorkWin->IsInternalDockingAllowed() ||
894
0
            ( (GetFloatStyle() & WB_STANDALONE) && Application::IsInModalMode()) )
895
0
        {
896
0
            SetAlignment( SfxChildAlignment::NOALIGNMENT );
897
0
        }
898
0
    }
899
900
    // detect floating mode
901
    // toggling mode will not execute code in handlers, because pImpl->bConstructed is not set yet
902
0
    bool bFloatMode = IsFloatingMode();
903
0
    if ( bFloatMode != (GetAlignment() == SfxChildAlignment::NOALIGNMENT) )
904
0
    {
905
0
        bFloatMode = !bFloatMode;
906
0
        SetFloatingMode( bFloatMode );
907
0
        if ( bFloatMode )
908
0
        {
909
0
            if ( !pImpl->aWinState.isEmpty() )
910
0
                GetFloatingWindow()->SetWindowState( pImpl->aWinState );
911
0
            else
912
0
                GetFloatingWindow()->SetOutputSizePixel( GetFloatingSize() );
913
0
        }
914
0
    }
915
916
0
    if ( IsFloatingMode() )
917
0
    {
918
        // validate last alignment
919
0
        SfxChildAlignment eLastAlign = pImpl->GetLastAlignment();
920
0
        if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
921
0
            eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::LEFT);
922
0
        if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
923
0
            eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::RIGHT);
924
0
        if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
925
0
            eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::TOP);
926
0
        if ( eLastAlign == SfxChildAlignment::NOALIGNMENT)
927
0
            eLastAlign = CheckAlignment(eLastAlign, SfxChildAlignment::BOTTOM);
928
0
        pImpl->SetLastAlignment(eLastAlign);
929
0
    }
930
0
    else
931
0
    {
932
        // docked window must have NOALIGNMENT as last alignment
933
0
        pImpl->SetLastAlignment(SfxChildAlignment::NOALIGNMENT);
934
935
0
        pImpl->pSplitWin = pWorkWin->GetSplitWindow_Impl(GetAlignment());
936
0
        pImpl->pSplitWin->InsertWindow(this, pImpl->aSplitSize);
937
0
    }
938
939
    // save alignment
940
0
    pImpl->SetDockAlignment( GetAlignment() );
941
0
}
942
943
void SfxDockingWindow::Initialize_Impl()
944
0
{
945
0
    if ( !pMgr )
946
0
    {
947
0
        pImpl->bConstructed = true;
948
0
        return;
949
0
    }
950
951
0
    SystemWindow* pFloatWin = GetFloatingWindow();
952
0
    bool bSet = false;
953
0
    if ( pFloatWin )
954
0
    {
955
0
        bSet = !pFloatWin->IsDefaultPos();
956
0
    }
957
0
    else
958
0
    {
959
0
        Point aPos = GetFloatingPos();
960
0
        if ( aPos != Point() )
961
0
            bSet = true;
962
0
    }
963
964
0
    if ( !bSet)
965
0
    {
966
0
        SfxViewFrame *pFrame = pBindings->GetDispatcher_Impl()->GetFrame();
967
0
        vcl::Window* pEditWin = pFrame->GetViewShell()->GetWindow();
968
0
        Point aPos = pEditWin->OutputToScreenPixel( pEditWin->GetPosPixel() );
969
0
        aPos = GetParent()->ScreenToOutputPixel( aPos );
970
0
        SetFloatingPos( aPos );
971
0
    }
972
973
0
    if ( pFloatWin )
974
0
    {
975
        // initialize floating window
976
0
        if ( pImpl->aWinState.isEmpty() )
977
            // window state never set before, get if from defaults
978
0
            pImpl->aWinState = pFloatWin->GetWindowState();
979
980
        // trick: use VCL method SetWindowState to adjust position and size
981
0
        pFloatWin->SetWindowState( pImpl->aWinState );
982
0
        Size aSize(pFloatWin->GetSizePixel());
983
984
        // remember floating size for calculating alignment and tracking rectangle
985
0
        SetFloatingSize(aSize);
986
987
0
    }
988
989
    // allow calling of docking handlers
990
0
    pImpl->bConstructed = true;
991
0
}
992
993
/** Fills a SfxChildWinInfo with specific data from SfxDockingWindow,
994
    so that it can be written in the INI file. It is assumed that rinfo
995
    receives all other possible relevant data in the ChildWindow class.
996
    Insertions are marked with size and the ZoomIn flag.
997
    If this method is overridden, the base implementation must be called first.
998
*/
999
void SfxDockingWindow::FillInfo(SfxChildWinInfo& rInfo) const
1000
0
{
1001
0
    if (!pMgr || !pImpl)
1002
0
        return;
1003
1004
0
    if (GetFloatingWindow() && pImpl->bConstructed)
1005
0
        pImpl->aWinState = GetFloatingWindow()->GetWindowState();
1006
1007
0
    rInfo.aWinState = pImpl->aWinState;
1008
0
    rInfo.aExtraString = "AL:(";
1009
0
    rInfo.aExtraString += OUString::number(static_cast<sal_uInt16>(GetAlignment()));
1010
0
    rInfo.aExtraString += ",";
1011
0
    rInfo.aExtraString += OUString::number (static_cast<sal_uInt16>(pImpl->GetLastAlignment()));
1012
1013
0
    Point aPos(pImpl->nLine, pImpl->nPos);
1014
0
    rInfo.aExtraString += ",";
1015
0
    rInfo.aExtraString += OUString::number( aPos.X() );
1016
0
    rInfo.aExtraString += "/";
1017
0
    rInfo.aExtraString += OUString::number( aPos.Y() );
1018
0
    rInfo.aExtraString += "/";
1019
0
    rInfo.aExtraString += OUString::number( pImpl->nHorizontalSize );
1020
0
    rInfo.aExtraString += "/";
1021
0
    rInfo.aExtraString += OUString::number( pImpl->nVerticalSize );
1022
0
    rInfo.aExtraString += ",";
1023
0
    rInfo.aExtraString += OUString::number( pImpl->aSplitSize.Width() );
1024
0
    rInfo.aExtraString += ";";
1025
0
    rInfo.aExtraString += OUString::number( pImpl->aSplitSize.Height() );
1026
1027
0
    rInfo.aExtraString += ")";
1028
0
}
1029
1030
SfxDockingWindow::~SfxDockingWindow()
1031
0
{
1032
0
    disposeOnce();
1033
0
}
1034
1035
void SfxDockingWindow::dispose()
1036
0
{
1037
0
    ReleaseChildWindow_Impl();
1038
0
    pImpl.reset();
1039
0
    m_xContainer.reset();
1040
0
    m_xBuilder.reset();
1041
0
    ResizableDockingWindow::dispose();
1042
0
}
1043
1044
void SfxDockingWindow::ReleaseChildWindow_Impl()
1045
0
{
1046
0
    if ( pMgr && pMgr->GetFrame() == pBindings->GetActiveFrame() )
1047
0
        pBindings->SetActiveFrame( nullptr );
1048
1049
0
    if ( pMgr && pImpl->pSplitWin && pImpl->pSplitWin->IsItemValid( GetType() ) )
1050
0
        pImpl->pSplitWin->RemoveWindow(this);
1051
1052
0
    pMgr=nullptr;
1053
0
}
1054
1055
/** This method calculates a resulting alignment for the given mouse position
1056
    and tracking rectangle. When changing the alignment it can also be that
1057
    the tracking rectangle is changed, so that an altered rectangle is
1058
    returned. The user of this class can influence behaviour of this method,
1059
    and thus the behavior of his DockinWindow class when docking where the
1060
    called virtual method:
1061
1062
    SfxDockingWindow::CalcDockingSize (SfxChildAlignment eAlign)
1063
1064
    is overridden (see below).
1065
*/
1066
SfxChildAlignment SfxDockingWindow::CalcAlignment(const Point& rPos, tools::Rectangle& rRect)
1067
0
{
1068
    // calculate hypothetical sizes for different modes
1069
0
    Size aFloatingSize(CalcDockingSize(SfxChildAlignment::NOALIGNMENT));
1070
1071
    // check if docking is permitted
1072
0
    SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
1073
0
    if ( !pWorkWin->IsDockingAllowed() )
1074
0
    {
1075
0
        rRect.SetSize( aFloatingSize );
1076
0
        return pImpl->GetDockAlignment();
1077
0
    }
1078
1079
    // calculate borders to shrink inner area before checking for intersection with tracking rectangle
1080
0
    tools::Long nLRBorder, nTBBorder;
1081
1082
    // take the smaller size of docked and floating mode
1083
0
    Size aBorderTmp = pImpl->aSplitSize;
1084
0
    if ( GetFloatingSize().Height() < aBorderTmp.Height() )
1085
0
        aBorderTmp.setHeight( GetFloatingSize().Height() );
1086
0
    if ( GetFloatingSize().Width() < aBorderTmp.Width() )
1087
0
        aBorderTmp.setWidth( GetFloatingSize().Width() );
1088
1089
0
    nLRBorder = aBorderTmp.Width();
1090
0
    nTBBorder = aBorderTmp.Height();
1091
1092
    // limit border to predefined constant values
1093
0
    if ( nLRBorder > MAX_TOGGLEAREA_WIDTH )
1094
0
        nLRBorder = MAX_TOGGLEAREA_WIDTH;
1095
0
    if ( nTBBorder > MAX_TOGGLEAREA_WIDTH )
1096
0
        nTBBorder = MAX_TOGGLEAREA_WIDTH;
1097
1098
    // shrink area for floating mode if possible
1099
0
    tools::Rectangle aInRect = GetInnerRect();
1100
0
    if ( aInRect.GetWidth() > nLRBorder )
1101
0
        aInRect.AdjustLeft(nLRBorder/2 );
1102
0
    if ( aInRect.GetWidth() > nLRBorder )
1103
0
        aInRect.AdjustRight( -(nLRBorder/2) );
1104
0
    if ( aInRect.GetHeight() > nTBBorder )
1105
0
        aInRect.AdjustTop(nTBBorder/2 );
1106
0
    if ( aInRect.GetHeight() > nTBBorder )
1107
0
        aInRect.AdjustBottom( -(nTBBorder/2) );
1108
1109
    // calculate alignment resulting from docking rectangle
1110
0
    bool bBecomesFloating = false;
1111
0
    SfxChildAlignment eDockAlign = pImpl->GetDockAlignment();
1112
0
    tools::Rectangle aDockingRect( rRect );
1113
0
    if ( !IsFloatingMode() )
1114
0
    {
1115
        // don't use tracking rectangle for alignment check, because it will be too large
1116
        // to get a floating mode as result - switch to floating size
1117
        // so the calculation only depends on the position of the rectangle, not the current
1118
        // docking state of the window
1119
0
        aDockingRect.SetSize( GetFloatingSize() );
1120
1121
        // in this mode docking is never done by keyboard, so it's OK to use the mouse position
1122
0
        aDockingRect.SetPos( pWorkWin->GetWindow()->OutputToScreenPixel( pWorkWin->GetWindow()->GetPointerPosPixel() ) );
1123
0
    }
1124
1125
0
    Point aPos = aDockingRect.TopLeft();
1126
0
    tools::Rectangle aIntersect = GetOuterRect().GetIntersection( aDockingRect );
1127
0
    if ( aIntersect.IsEmpty() )
1128
        // docking rectangle completely outside docking area -> floating mode
1129
0
        bBecomesFloating = true;
1130
0
    else
1131
0
    {
1132
        // create a small test rect around the mouse position and use this one
1133
        // instead of the passed rRect to not dock too easily or by accident
1134
0
        tools::Rectangle aSmallDockingRect;
1135
0
        aSmallDockingRect.SetSize( Size( MAX_TOGGLEAREA_WIDTH, MAX_TOGGLEAREA_HEIGHT ) );
1136
0
        Point aNewPos(rPos);
1137
0
        aNewPos.AdjustX( -(aSmallDockingRect.GetWidth()/2) );
1138
0
        aNewPos.AdjustY( -(aSmallDockingRect.GetHeight()/2) );
1139
0
        aSmallDockingRect.SetPos(aNewPos);
1140
0
        tools::Rectangle aIntersectRect = aInRect.GetIntersection( aSmallDockingRect );
1141
0
        if ( aIntersectRect == aSmallDockingRect )
1142
            // docking rectangle completely inside (shrunk) inner area -> floating mode
1143
0
            bBecomesFloating = true;
1144
0
    }
1145
1146
0
    if ( bBecomesFloating )
1147
0
    {
1148
0
        eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::NOALIGNMENT);
1149
0
    }
1150
0
    else
1151
0
    {
1152
        // docking rectangle is in the "sensible area"
1153
0
        Point aInPosTL( aPos.X()-aInRect.Left(), aPos.Y()-aInRect.Top() );
1154
0
        Point aInPosBR( aPos.X()-aInRect.Left() + aDockingRect.GetWidth(), aPos.Y()-aInRect.Top() + aDockingRect.GetHeight() );
1155
0
        Size  aInSize = aInRect.GetSize();
1156
0
        bool  bNoChange = false;
1157
1158
        // check if alignment is still unchanged
1159
0
        switch ( GetAlignment() )
1160
0
        {
1161
0
            case SfxChildAlignment::LEFT:
1162
0
            case SfxChildAlignment::FIRSTLEFT:
1163
0
            case SfxChildAlignment::LASTLEFT:
1164
0
                if (aInPosTL.X() <= 0)
1165
0
                {
1166
0
                    eDockAlign = GetAlignment();
1167
0
                    bNoChange = true;
1168
0
                }
1169
0
                break;
1170
0
            case SfxChildAlignment::TOP:
1171
0
            case SfxChildAlignment::LOWESTTOP:
1172
0
            case SfxChildAlignment::HIGHESTTOP:
1173
0
                if ( aInPosTL.Y() <= 0)
1174
0
                {
1175
0
                    eDockAlign = GetAlignment();
1176
0
                    bNoChange = true;
1177
0
                }
1178
0
                break;
1179
0
            case SfxChildAlignment::RIGHT:
1180
0
            case SfxChildAlignment::FIRSTRIGHT:
1181
0
            case SfxChildAlignment::LASTRIGHT:
1182
0
                if ( aInPosBR.X() >= aInSize.Width())
1183
0
                {
1184
0
                    eDockAlign = GetAlignment();
1185
0
                    bNoChange = true;
1186
0
                }
1187
0
                break;
1188
0
            case SfxChildAlignment::BOTTOM:
1189
0
            case SfxChildAlignment::LOWESTBOTTOM:
1190
0
            case SfxChildAlignment::HIGHESTBOTTOM:
1191
0
                if ( aInPosBR.Y() >= aInSize.Height())
1192
0
                {
1193
0
                    eDockAlign = GetAlignment();
1194
0
                    bNoChange = true;
1195
0
                }
1196
0
                break;
1197
0
            default:
1198
0
                break;
1199
0
        }
1200
1201
0
        if ( !bNoChange )
1202
0
        {
1203
            // alignment will change, test alignment according to distance of the docking rectangles edges
1204
0
            bool bForbidden = true;
1205
0
            if ( aInPosTL.X() <= 0)
1206
0
            {
1207
0
                eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::LEFT);
1208
0
                bForbidden = ( eDockAlign != SfxChildAlignment::LEFT &&
1209
0
                               eDockAlign != SfxChildAlignment::FIRSTLEFT &&
1210
0
                               eDockAlign != SfxChildAlignment::LASTLEFT );
1211
0
            }
1212
1213
0
            if ( bForbidden && aInPosTL.Y() <= 0)
1214
0
            {
1215
0
                eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::TOP);
1216
0
                bForbidden = ( eDockAlign != SfxChildAlignment::TOP &&
1217
0
                               eDockAlign != SfxChildAlignment::HIGHESTTOP &&
1218
0
                               eDockAlign != SfxChildAlignment::LOWESTTOP );
1219
0
            }
1220
1221
0
            if ( bForbidden && aInPosBR.X() >= aInSize.Width())
1222
0
            {
1223
0
                eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::RIGHT);
1224
0
                bForbidden = ( eDockAlign != SfxChildAlignment::RIGHT &&
1225
0
                               eDockAlign != SfxChildAlignment::FIRSTRIGHT &&
1226
0
                               eDockAlign != SfxChildAlignment::LASTRIGHT );
1227
0
            }
1228
1229
0
            if ( bForbidden && aInPosBR.Y() >= aInSize.Height())
1230
0
            {
1231
0
                eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::BOTTOM);
1232
0
                bForbidden = ( eDockAlign != SfxChildAlignment::BOTTOM &&
1233
0
                               eDockAlign != SfxChildAlignment::HIGHESTBOTTOM &&
1234
0
                               eDockAlign != SfxChildAlignment::LOWESTBOTTOM );
1235
0
            }
1236
1237
            // the calculated alignment was rejected by the window -> take floating mode
1238
0
            if ( bForbidden )
1239
0
                eDockAlign = CheckAlignment(pImpl->GetDockAlignment(),SfxChildAlignment::NOALIGNMENT);
1240
0
        }
1241
0
    }
1242
1243
0
    if ( eDockAlign == SfxChildAlignment::NOALIGNMENT )
1244
0
    {
1245
        // In the FloatingMode the tracking rectangle will get the floating
1246
        // size. Due to a bug the rRect may only be changed when the
1247
        // alignment is changed!
1248
0
        if ( eDockAlign != pImpl->GetDockAlignment() )
1249
0
            aDockingRect.SetSize( aFloatingSize );
1250
0
    }
1251
0
    else
1252
0
    {
1253
0
        sal_uInt16 nLine, nPos;
1254
0
        SfxSplitWindow *pSplitWin = pWorkWin->GetSplitWindow_Impl(eDockAlign);
1255
0
        aPos = pSplitWin->ScreenToOutputPixel( aPos );
1256
0
        if ( pSplitWin->GetWindowPos( aPos, nLine, nPos ) )
1257
0
        {
1258
            // mouse over splitwindow, get line and position
1259
0
            pImpl->nDockLine = nLine;
1260
0
            pImpl->nDockPos = nPos;
1261
0
            pImpl->bNewLine = false;
1262
0
        }
1263
0
        else
1264
0
        {
1265
            // mouse touches inner border -> create new line
1266
0
            if ( eDockAlign == GetAlignment() && pImpl->pSplitWin &&
1267
0
                 pImpl->nLine == pImpl->pSplitWin->GetLineCount()-1 && pImpl->pSplitWin->GetWindowCount(pImpl->nLine) == 1 )
1268
0
            {
1269
                // if this window is the only one in the last line, it can't be docked as new line in the same splitwindow
1270
0
                pImpl->nDockLine = pImpl->nLine;
1271
0
                pImpl->nDockPos = pImpl->nPos;
1272
0
                pImpl->bNewLine = false;
1273
0
            }
1274
0
            else
1275
0
            {
1276
                // create new line
1277
0
                pImpl->nDockLine = pSplitWin->GetLineCount();
1278
0
                pImpl->nDockPos = 0;
1279
0
                pImpl->bNewLine = true;
1280
0
            }
1281
0
        }
1282
1283
0
        bool bChanged = pImpl->nLine != pImpl->nDockLine || pImpl->nPos != pImpl->nDockPos || eDockAlign != GetAlignment();
1284
0
        if ( !bChanged && !IsFloatingMode() )
1285
0
        {
1286
            // window only slightly moved, no change of any property
1287
0
            rRect.SetSize( pImpl->aSplitSize );
1288
0
            rRect.SetPos( aDockingRect.TopLeft() );
1289
0
            return eDockAlign;
1290
0
        }
1291
1292
        // calculate new size and position
1293
0
        Size aSize;
1294
0
        Point aPoint = aDockingRect.TopLeft();
1295
0
        Size aInnerSize = GetInnerRect().GetSize();
1296
0
        if ( eDockAlign == SfxChildAlignment::LEFT || eDockAlign == SfxChildAlignment::RIGHT )
1297
0
        {
1298
0
            if ( pImpl->bNewLine )
1299
0
            {
1300
                // set height to height of free area
1301
0
                aSize.setHeight( aInnerSize.Height() );
1302
0
                aSize.setWidth( pImpl->nHorizontalSize );
1303
0
                if ( eDockAlign == SfxChildAlignment::LEFT )
1304
0
                {
1305
0
                    aPoint = aInnerRect.TopLeft();
1306
0
                }
1307
0
                else
1308
0
                {
1309
0
                    aPoint = aInnerRect.TopRight();
1310
0
                    aPoint.AdjustX( -(aSize.Width()) );
1311
0
                }
1312
0
            }
1313
0
            else
1314
0
            {
1315
                // get width from splitwindow
1316
0
                aSize.setWidth( pSplitWin->GetLineSize(nLine) );
1317
0
                aSize.setHeight( pImpl->aSplitSize.Height() );
1318
0
            }
1319
0
        }
1320
0
        else
1321
0
        {
1322
0
            if ( pImpl->bNewLine )
1323
0
            {
1324
                // set width to width of free area
1325
0
                aSize.setWidth( aInnerSize.Width() );
1326
0
                aSize.setHeight( pImpl->nVerticalSize );
1327
0
                if ( eDockAlign == SfxChildAlignment::TOP )
1328
0
                {
1329
0
                    aPoint = aInnerRect.TopLeft();
1330
0
                }
1331
0
                else
1332
0
                {
1333
0
                    aPoint = aInnerRect.BottomLeft();
1334
0
                    aPoint.AdjustY( -(aSize.Height()) );
1335
0
                }
1336
0
            }
1337
0
            else
1338
0
            {
1339
                // get height from splitwindow
1340
0
                aSize.setHeight( pSplitWin->GetLineSize(nLine) );
1341
0
                aSize.setWidth( pImpl->aSplitSize.Width() );
1342
0
            }
1343
0
        }
1344
1345
0
        aDockingRect.SetSize( aSize );
1346
0
        aDockingRect.SetPos( aPoint );
1347
0
    }
1348
1349
0
    rRect = aDockingRect;
1350
0
    return eDockAlign;
1351
0
}
1352
1353
/** Virtual method of the SfxDockingWindow class. This method determines how
1354
    the size of the DockingWindows changes depending on the alignment. The base
1355
    implementation uses the floating mode, the size of the marked Floating
1356
    Size. For horizontal alignment, the width will be the width of the outer
1357
    DockingRectangle, with vertical alignment the height will be the height of
1358
    the inner DockingRectangle (resulting from the order in which the SFX child
1359
    windows are displayed). The other size is set to the current floating-size,
1360
    this could changed by a to intervening derived class. The docking size must
1361
    be the same for Left/Right and Top/Bottom.
1362
*/
1363
Size SfxDockingWindow::CalcDockingSize(SfxChildAlignment eAlign)
1364
0
{
1365
    // Note: if the resizing is also possible in the docked state, then the
1366
    // Floating-size does also have to be adjusted?
1367
1368
0
    Size aSize = GetFloatingSize();
1369
0
    switch (eAlign)
1370
0
    {
1371
0
        case SfxChildAlignment::TOP:
1372
0
        case SfxChildAlignment::BOTTOM:
1373
0
        case SfxChildAlignment::LOWESTTOP:
1374
0
        case SfxChildAlignment::HIGHESTTOP:
1375
0
        case SfxChildAlignment::LOWESTBOTTOM:
1376
0
        case SfxChildAlignment::HIGHESTBOTTOM:
1377
0
            aSize.setWidth( aOuterRect.Right() - aOuterRect.Left() );
1378
0
            break;
1379
0
        case SfxChildAlignment::LEFT:
1380
0
        case SfxChildAlignment::RIGHT:
1381
0
        case SfxChildAlignment::FIRSTLEFT:
1382
0
        case SfxChildAlignment::LASTLEFT:
1383
0
        case SfxChildAlignment::FIRSTRIGHT:
1384
0
        case SfxChildAlignment::LASTRIGHT:
1385
0
            aSize.setHeight( aInnerRect.Bottom() - aInnerRect.Top() );
1386
0
            break;
1387
0
        case SfxChildAlignment::NOALIGNMENT:
1388
0
            break;
1389
0
              default:
1390
0
                  break;
1391
0
    }
1392
1393
0
    return aSize;
1394
0
}
1395
1396
/** Virtual method of the SfxDockingWindow class. Here a derived class can
1397
    disallow certain alignments. The base implementation does not
1398
    prohibit alignment.
1399
*/
1400
SfxChildAlignment SfxDockingWindow::CheckAlignment(SfxChildAlignment,
1401
    SfxChildAlignment eAlign)
1402
0
{
1403
0
    return eAlign;
1404
0
}
1405
1406
/** The window is closed when the ChildWindow is destroyed by running the
1407
    ChildWindow-slots. If this is method is overridden by a derived class
1408
    method, then the SfxDockingDialogWindow: Close() must be called afterwards
1409
    if the Close() was not cancelled with "return sal_False".
1410
*/
1411
bool SfxDockingWindow::Close()
1412
0
{
1413
    // Execute with Parameters, since Toggle is ignored by some ChildWindows.
1414
0
    if ( !pMgr )
1415
0
        return true;
1416
1417
0
    SfxBoolItem aValue( pMgr->GetType(), false);
1418
0
    pBindings->GetDispatcher_Impl()->ExecuteList(
1419
0
        pMgr->GetType(), SfxCallMode::RECORD | SfxCallMode::ASYNCHRON,
1420
0
        { &aValue });
1421
0
    return true;
1422
0
}
1423
1424
void SfxDockingWindow::Paint(vcl::RenderContext&, const tools::Rectangle& /*rRect*/)
1425
0
{
1426
0
}
1427
1428
/** With this method, a minimal OutputSize be can set, that is queried in
1429
    the Resizing()-Handler.
1430
*/
1431
void SfxDockingWindow::SetMinOutputSizePixel( const Size& rSize )
1432
0
{
1433
0
    pImpl->aMinSize = rSize;
1434
0
    ResizableDockingWindow::SetMinOutputSizePixel( rSize );
1435
0
}
1436
1437
/** Set the minimum size which is returned.*/
1438
const Size& SfxDockingWindow::GetMinOutputSizePixel() const
1439
0
{
1440
0
    return pImpl->aMinSize;
1441
0
}
1442
1443
bool SfxDockingWindow::EventNotify( NotifyEvent& rEvt )
1444
0
{
1445
0
    if ( !pImpl )
1446
0
        return ResizableDockingWindow::EventNotify( rEvt );
1447
1448
0
    if ( rEvt.GetType() == NotifyEventType::GETFOCUS )
1449
0
    {
1450
0
        if (pMgr != nullptr)
1451
0
            pBindings->SetActiveFrame( pMgr->GetFrame() );
1452
1453
0
        if ( pImpl->pSplitWin )
1454
0
            pImpl->pSplitWin->SetActiveWindow_Impl( this );
1455
0
        else if (pMgr != nullptr)
1456
0
            pMgr->Activate_Impl();
1457
1458
        // In VCL EventNotify goes first to the window itself, also call the
1459
        // base class, otherwise the parent learns nothing
1460
        // if ( rEvt.GetWindow() == this )  PB: #i74693# not necessary any longer
1461
0
        ResizableDockingWindow::EventNotify( rEvt );
1462
        // tdf#151112 move focus into container widget hierarchy if not already there
1463
0
        if (m_xContainer && !m_xContainer->has_child_focus())
1464
0
            m_xContainer->child_grab_focus();
1465
0
        return true;
1466
0
    }
1467
0
    else if( rEvt.GetType() == NotifyEventType::KEYINPUT )
1468
0
    {
1469
        // First, allow KeyInput for Dialog functions
1470
0
        if (!DockingWindow::EventNotify(rEvt) && SfxViewShell::Current())
1471
0
        {
1472
            // then also for valid global accelerators.
1473
0
            return SfxViewShell::Current()->GlobalKeyInput_Impl( *rEvt.GetKeyEvent() );
1474
0
        }
1475
0
        return true;
1476
0
    }
1477
0
    else if ( rEvt.GetType() == NotifyEventType::LOSEFOCUS && !HasChildPathFocus() )
1478
0
    {
1479
0
        pBindings->SetActiveFrame( nullptr );
1480
0
    }
1481
1482
0
    return ResizableDockingWindow::EventNotify( rEvt );
1483
0
}
1484
1485
void SfxDockingWindow::SetItemSize_Impl( const Size& rSize )
1486
0
{
1487
0
    pImpl->aSplitSize = rSize;
1488
1489
0
    SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
1490
0
    pWorkWin->ConfigChild_Impl( SfxChildIdentifier::SPLITWINDOW, SfxDockingConfig::ALIGNDOCKINGWINDOW, pMgr->GetType() );
1491
0
}
1492
1493
void SfxDockingWindow::Disappear_Impl()
1494
0
{
1495
0
    if ( pImpl->pSplitWin && pImpl->pSplitWin->IsItemValid( GetType() ) )
1496
0
        pImpl->pSplitWin->RemoveWindow(this);
1497
0
}
1498
1499
void SfxDockingWindow::Reappear_Impl()
1500
0
{
1501
0
    if ( pImpl->pSplitWin && !pImpl->pSplitWin->IsItemValid( GetType() ) )
1502
0
    {
1503
0
        pImpl->pSplitWin->InsertWindow( this, pImpl->aSplitSize );
1504
0
    }
1505
0
}
1506
1507
bool SfxDockingWindow::IsAutoHide_Impl() const
1508
0
{
1509
0
    if ( pImpl->pSplitWin )
1510
0
        return !pImpl->pSplitWin->IsFadeIn();
1511
0
    else
1512
0
        return false;
1513
0
}
1514
1515
void SfxDockingWindow::AutoShow_Impl()
1516
0
{
1517
0
    if ( pImpl->pSplitWin )
1518
0
    {
1519
0
        pImpl->pSplitWin->FadeIn();
1520
0
    }
1521
0
}
1522
1523
void SfxDockingWindow::StateChanged( StateChangedType nStateChange )
1524
0
{
1525
0
    if ( nStateChange == StateChangedType::InitShow )
1526
0
        Initialize_Impl();
1527
1528
0
    ResizableDockingWindow::StateChanged( nStateChange );
1529
0
}
1530
1531
void SfxDockingWindow::Move()
1532
0
{
1533
0
    if ( pImpl )
1534
0
        pImpl->aMoveIdle.Start();
1535
0
}
1536
1537
IMPL_LINK_NOARG(SfxDockingWindow, TimerHdl, Timer *, void)
1538
0
{
1539
0
    pImpl->aMoveIdle.Stop();
1540
0
    if ( IsReallyVisible() && IsFloatingMode() )
1541
0
    {
1542
0
        SetFloatingSize( GetOutputSizePixel() );
1543
0
        pImpl->aWinState = GetFloatingWindow()->GetWindowState();
1544
0
        SfxWorkWindow *pWorkWin = pBindings->GetWorkWindow_Impl();
1545
0
        pWorkWin->ConfigChild_Impl( SfxChildIdentifier::SPLITWINDOW, SfxDockingConfig::ALIGNDOCKINGWINDOW, pMgr->GetType() );
1546
0
    }
1547
0
}
1548
1549
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */