/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: */ |