Coverage Report

Created: 2026-07-10 11:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sw/source/uibase/docvw/OutlineContentVisibilityWin.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
10
#include <edtwin.hxx>
11
#include <OutlineContentVisibilityWin.hxx>
12
#include <view.hxx>
13
#include <wrtsh.hxx>
14
15
#include <IDocumentOutlineNodes.hxx>
16
#include <txtfrm.hxx>
17
#include <ndtxt.hxx>
18
#include <vcl/InterimItemWindow.hxx>
19
#include <vcl/event.hxx>
20
#include <vcl/svapp.hxx>
21
#include <vcl/weld/Builder.hxx>
22
#include <strings.hrc>
23
24
#include <viewopt.hxx>
25
26
#include <FrameControlsManager.hxx>
27
28
SwOutlineContentVisibilityWin::SwOutlineContentVisibilityWin(SwEditWin* pEditWin,
29
                                                             const SwFrame* pFrame)
30
0
    : InterimItemWindow(pEditWin, u"modules/swriter/ui/outlinebutton.ui"_ustr,
31
0
                        u"OutlineButton"_ustr)
32
0
    , m_xShowBtn(m_xBuilder->weld_button(u"show"_ustr))
33
0
    , m_xHideBtn(m_xBuilder->weld_button(u"hide"_ustr))
34
0
    , m_pEditWin(pEditWin)
35
0
    , m_pFrame(pFrame)
36
0
    , m_nDelayAppearing(0)
37
0
    , m_aDelayTimer("SwOutlineContentVisibilityWin m_aDelayTimer")
38
0
    , m_bDestroyed(false)
39
0
    , m_nOutlinePos(SwOutlineNodes::npos)
40
0
{
41
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
42
0
    SetPaintTransparent(false);
43
0
    SetBackground(rStyleSettings.GetFaceColor());
44
45
0
    Size aBtnsSize(m_xShowBtn->get_preferred_size());
46
0
    auto nDim = std::max(aBtnsSize.Width(), aBtnsSize.Height());
47
0
    m_xShowBtn->set_size_request(nDim, nDim);
48
0
    m_xHideBtn->set_size_request(nDim, nDim);
49
50
0
    SetSizePixel(get_preferred_size());
51
0
    SetSymbol(ButtonSymbol::NONE);
52
53
0
    m_xShowBtn->connect_mouse_press(LINK(this, SwOutlineContentVisibilityWin, MousePressHdl));
54
0
    m_xHideBtn->connect_mouse_press(LINK(this, SwOutlineContentVisibilityWin, MousePressHdl));
55
56
0
    m_aDelayTimer.SetTimeout(25);
57
0
    m_aDelayTimer.SetInvokeHandler(LINK(this, SwOutlineContentVisibilityWin, DelayAppearHandler));
58
0
}
Unexecuted instantiation: SwOutlineContentVisibilityWin::SwOutlineContentVisibilityWin(SwEditWin*, SwFrame const*)
Unexecuted instantiation: SwOutlineContentVisibilityWin::SwOutlineContentVisibilityWin(SwEditWin*, SwFrame const*)
59
60
void SwOutlineContentVisibilityWin::dispose()
61
0
{
62
0
    m_bDestroyed = true;
63
0
    m_aDelayTimer.Stop();
64
65
0
    m_pEditWin.reset();
66
0
    m_pFrame = nullptr;
67
68
0
    m_xHideBtn.reset();
69
0
    m_xShowBtn.reset();
70
71
0
    InterimItemWindow::dispose();
72
0
}
73
74
ButtonSymbol SwOutlineContentVisibilityWin::GetSymbol() const
75
0
{
76
0
    if (m_xShowBtn->get_visible())
77
0
        return ButtonSymbol::SHOW;
78
0
    if (m_xHideBtn->get_visible())
79
0
        return ButtonSymbol::HIDE;
80
0
    return ButtonSymbol::NONE;
81
0
}
82
83
void SwOutlineContentVisibilityWin::SetSymbol(ButtonSymbol eStyle)
84
0
{
85
0
    if (GetSymbol() == eStyle)
86
0
        return;
87
88
0
    bool bShow = eStyle == ButtonSymbol::SHOW;
89
0
    bool bHide = eStyle == ButtonSymbol::HIDE;
90
91
    // disable mouse move for the hidden button so we don't get mouse
92
    // leave events we don't care about when we swap buttons
93
0
    m_xShowBtn->connect_mouse_move(Link<const MouseEvent&, bool>());
94
0
    m_xHideBtn->connect_mouse_move(Link<const MouseEvent&, bool>());
95
96
0
    m_xShowBtn->set_visible(bShow);
97
0
    m_xHideBtn->set_visible(bHide);
98
99
0
    weld::Button* pButton = nullptr;
100
0
    if (bShow)
101
0
        pButton = m_xShowBtn.get();
102
0
    else if (bHide)
103
0
        pButton = m_xHideBtn.get();
104
0
    InitControlBase(pButton);
105
0
    if (pButton)
106
0
        pButton->connect_mouse_move(LINK(this, SwOutlineContentVisibilityWin, MouseMoveHdl));
107
0
}
108
109
void SwOutlineContentVisibilityWin::Set()
110
0
{
111
0
    const SwTextFrame* pTextFrame = static_cast<const SwTextFrame*>(GetFrame());
112
0
    const SwTextNode* pTextNode = pTextFrame->GetTextNodeFirst();
113
0
    SwWrtShell& rSh = GetEditWin()->GetView().GetWrtShell();
114
0
    const SwOutlineNodes& rOutlineNodes = rSh.GetNodes().GetOutLineNds();
115
116
0
    (void)rOutlineNodes.Seek_Entry(pTextNode, &m_nOutlinePos);
117
118
    // set symbol displayed on button
119
0
    bool bVisible = pTextNode->GetAttrOutlineContentVisible();
120
0
    SetSymbol(bVisible ? ButtonSymbol::HIDE : ButtonSymbol::SHOW);
121
122
    // set quick help
123
0
    SwOutlineNodes::size_type nOutlineNodesCount
124
0
        = rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
125
0
    int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(m_nOutlinePos);
126
0
    OUString sQuickHelp(SwResId(STR_OUTLINE_CONTENT_TOGGLE_VISIBILITY));
127
0
    if (!rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent()
128
0
        && m_nOutlinePos + 1 < nOutlineNodesCount
129
0
        && rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(m_nOutlinePos + 1) > nLevel)
130
0
        sQuickHelp += " (" + SwResId(STR_OUTLINE_CONTENT_TOGGLE_VISIBILITY_EXT) + ")";
131
0
    SetQuickHelpText(sQuickHelp);
132
133
    // Set the position of the window
134
0
    SwRect aFrameAreaRect = pTextFrame->getFrameArea();
135
0
    aFrameAreaRect.AddTop(pTextFrame->GetTopMargin());
136
0
    SwSpecialPos aSpecialPos;
137
0
    aSpecialPos.nExtendRange = pTextNode->HasVisibleNumberingOrBullet() ? SwSPExtendRange::BEFORE
138
0
                                                                        : SwSPExtendRange::NONE;
139
0
    SwCursorMoveState aMoveState;
140
0
    aMoveState.m_pSpecialPos = &aSpecialPos;
141
0
    SwRect aCharRect;
142
0
    pTextFrame->GetCharRect(aCharRect, SwPosition(*(pTextFrame->GetTextNodeForParaProps())),
143
0
                            &aMoveState);
144
0
    Point aPxPt(GetEditWin()->GetOutDev()->LogicToPixel(
145
0
        Point(aCharRect.Left(), aFrameAreaRect.Center().getY())));
146
0
    if (pTextFrame->IsRightToLeft())
147
0
        aPxPt.AdjustX(2);
148
0
    else
149
0
        aPxPt.AdjustX(-(GetSizePixel().getWidth() + 2));
150
0
    aPxPt.AdjustY(-GetSizePixel().getHeight() / 2);
151
0
    SetPosPixel(aPxPt);
152
0
}
153
154
void SwOutlineContentVisibilityWin::ShowAll(bool bShow)
155
0
{
156
0
    if (bShow)
157
0
    {
158
0
        m_nDelayAppearing = 0;
159
0
        if (!m_bDestroyed && m_aDelayTimer.IsActive())
160
0
            m_aDelayTimer.Stop();
161
0
        if (!m_bDestroyed)
162
0
            m_aDelayTimer.Start();
163
0
    }
164
0
    else
165
0
        Hide();
166
0
}
167
168
bool SwOutlineContentVisibilityWin::Contains(const Point& rDocPt) const
169
0
{
170
0
    ::tools::Rectangle aRect(GetPosPixel(), GetSizePixel());
171
0
    if (aRect.Contains(rDocPt))
172
0
        return true;
173
0
    return false;
174
0
}
175
176
IMPL_LINK(SwOutlineContentVisibilityWin, MouseMoveHdl, const MouseEvent&, rMEvt, bool)
177
0
{
178
0
    if (rMEvt.IsLeaveWindow())
179
0
    {
180
0
        if (GetSymbol() == ButtonSymbol::HIDE)
181
0
        {
182
            // MouseMove event may not be seen by the edit window for example when move is to
183
            // a show button or when move is outside of the edit window.
184
            // Only hide when mouse leave results in leaving the frame.
185
0
            tools::Rectangle aFrameAreaPxRect
186
0
                = GetEditWin()->LogicToPixel(GetFrame()->getFrameArea().SVRect());
187
0
            auto nY = GetPosPixel().getY() + rMEvt.GetPosPixel().getY();
188
0
            if (nY <= 0 || nY <= aFrameAreaPxRect.Top() || nY >= aFrameAreaPxRect.Bottom()
189
0
                || nY >= GetEditWin()->GetSizePixel().Height())
190
0
            {
191
0
                GetEditWin()->SetSavedOutlineFrame(nullptr);
192
0
                GetEditWin()->GetFrameControlsManager().RemoveControlsByType(
193
0
                    FrameControlType::Outline, GetFrame());
194
                // warning: "this" is disposed now
195
0
            }
196
0
        }
197
0
    }
198
0
    else if (rMEvt.IsEnterWindow())
199
0
    {
200
        // Leave window event might not have resulted in removing hide button from saved frame
201
        // and the edit win might not receive mouse event between leaving saved frame button and
202
        // entering this button.
203
0
        if (GetFrame() != GetEditWin()->GetSavedOutlineFrame())
204
0
        {
205
0
            SwFrameControlPtr pFrameControl = GetEditWin()->GetFrameControlsManager().GetControl(
206
0
                FrameControlType::Outline, GetEditWin()->GetSavedOutlineFrame());
207
0
            if (pFrameControl)
208
0
            {
209
0
                SwOutlineContentVisibilityWin* pControl
210
0
                    = dynamic_cast<SwOutlineContentVisibilityWin*>(pFrameControl->GetIFacePtr());
211
0
                if (pControl && pControl->GetSymbol() == ButtonSymbol::HIDE)
212
0
                {
213
0
                    GetEditWin()->GetFrameControlsManager().RemoveControlsByType(
214
0
                        FrameControlType::Outline, GetEditWin()->GetSavedOutlineFrame());
215
                    // The outline content visibility window frame control (hide button)
216
                    // for saved outline frame is now disposed.
217
0
                }
218
0
            }
219
0
            GetEditWin()->SetSavedOutlineFrame(
220
0
                static_cast<SwTextFrame*>(const_cast<SwFrame*>(GetFrame())));
221
0
        }
222
0
        if (!m_bDestroyed && m_aDelayTimer.IsActive())
223
0
            m_aDelayTimer.Stop();
224
        // bring button to top
225
0
        SetZOrder(this, ZOrderFlags::First);
226
0
    }
227
0
    return false;
228
0
}
229
230
// Toggle the outline content visibility on mouse press
231
IMPL_LINK(SwOutlineContentVisibilityWin, MousePressHdl, const MouseEvent&, rMEvt, bool)
232
0
{
233
0
    Hide();
234
0
    GetEditWin()->ToggleOutlineContentVisibility(m_nOutlinePos, rMEvt.IsRight());
235
0
    return false;
236
0
}
237
238
IMPL_LINK_NOARG(SwOutlineContentVisibilityWin, DelayAppearHandler, Timer*, void)
239
0
{
240
0
    const int TICKS_BEFORE_WE_APPEAR = 3;
241
0
    if (m_nDelayAppearing < TICKS_BEFORE_WE_APPEAR)
242
0
    {
243
0
        ++m_nDelayAppearing;
244
0
        m_aDelayTimer.Start();
245
0
        return;
246
0
    }
247
0
    if (GetEditWin()->GetSavedOutlineFrame() == GetFrame())
248
0
        Show();
249
0
    m_aDelayTimer.Stop();
250
0
}
251
252
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */