/src/libreoffice/vcl/source/control/InterimItemWindow.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ |
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 <vcl/InterimItemWindow.hxx> |
11 | | #include <vcl/layout.hxx> |
12 | | #include <vcl/rendercontext/SystemTextColorFlags.hxx> |
13 | | #include <vcl/weld/Builder.hxx> |
14 | | #include <vcl/weld/Container.hxx> |
15 | | |
16 | | #include <salobj.hxx> |
17 | | #include <svdata.hxx> |
18 | | #include <window.h> |
19 | | |
20 | | InterimItemWindow::InterimItemWindow(vcl::Window* pParent, const OUString& rUIXMLDescription, |
21 | | const OUString& rID, bool bAllowCycleFocusOut) |
22 | 0 | : Control(pParent, WB_TABSTOP) |
23 | 0 | , m_pWidget(nullptr) // inheritors are expected to call InitControlBase |
24 | 0 | , m_aLayoutIdle("InterimItemWindow m_aLayoutIdle") |
25 | 0 | { |
26 | 0 | m_aLayoutIdle.SetPriority(TaskPriority::RESIZE); |
27 | 0 | m_aLayoutIdle.SetInvokeHandler(LINK(this, InterimItemWindow, DoLayout)); |
28 | |
|
29 | 0 | m_xVclContentArea = VclPtr<VclVBox>::Create(this); |
30 | 0 | m_xVclContentArea->Show(); |
31 | 0 | m_xBuilder = Application::CreateInterimBuilder(m_xVclContentArea, rUIXMLDescription, |
32 | 0 | bAllowCycleFocusOut); |
33 | 0 | m_xContainer = m_xBuilder->weld_container(rID); |
34 | |
|
35 | 0 | SetBackground(); |
36 | 0 | SetPaintTransparent(true); |
37 | 0 | } Unexecuted instantiation: InterimItemWindow::InterimItemWindow(vcl::Window*, rtl::OUString const&, rtl::OUString const&, bool) Unexecuted instantiation: InterimItemWindow::InterimItemWindow(vcl::Window*, rtl::OUString const&, rtl::OUString const&, bool) |
38 | | |
39 | | void InterimItemWindow::StateChanged(StateChangedType nStateChange) |
40 | 0 | { |
41 | 0 | if (nStateChange == StateChangedType::Enable) |
42 | 0 | m_xContainer->set_sensitive(IsEnabled()); |
43 | 0 | Control::StateChanged(nStateChange); |
44 | 0 | } |
45 | | |
46 | 0 | InterimItemWindow::~InterimItemWindow() { disposeOnce(); } |
47 | | |
48 | | void InterimItemWindow::dispose() |
49 | 0 | { |
50 | 0 | m_pWidget = nullptr; |
51 | |
|
52 | 0 | m_xContainer.reset(); |
53 | 0 | m_xBuilder.reset(); |
54 | 0 | m_xVclContentArea.disposeAndClear(); |
55 | |
|
56 | 0 | m_aLayoutIdle.Stop(); |
57 | |
|
58 | 0 | Control::dispose(); |
59 | 0 | } |
60 | | |
61 | | void InterimItemWindow::StartIdleLayout() |
62 | 0 | { |
63 | 0 | if (!m_xVclContentArea) |
64 | 0 | return; |
65 | 0 | if (m_aLayoutIdle.IsActive()) |
66 | 0 | return; |
67 | 0 | m_aLayoutIdle.Start(); |
68 | 0 | } |
69 | | |
70 | | void InterimItemWindow::queue_resize(StateChangedType eReason) |
71 | 0 | { |
72 | 0 | Control::queue_resize(eReason); |
73 | 0 | StartIdleLayout(); |
74 | 0 | } |
75 | | |
76 | 0 | void InterimItemWindow::Resize() { Layout(); } |
77 | | |
78 | | void InterimItemWindow::UnclipVisibleSysObj() |
79 | 0 | { |
80 | 0 | if (!IsVisible()) |
81 | 0 | return; |
82 | 0 | vcl::Window* pChild = m_xVclContentArea->GetWindow(GetWindowType::FirstChild); |
83 | 0 | if (!pChild) |
84 | 0 | return; |
85 | 0 | WindowImpl* pWindowImpl = pChild->ImplGetWindowImpl(); |
86 | 0 | if (!pWindowImpl) |
87 | 0 | return; |
88 | 0 | if (!pWindowImpl->mpSysObj) |
89 | 0 | return; |
90 | 0 | pWindowImpl->mpSysObj->Show(true); |
91 | 0 | pWindowImpl->mpSysObj->ResetClipRegion(); |
92 | | // flag that sysobj clip is dirty and needs to be recalculated on next use |
93 | 0 | pWindowImpl->mbInitWinClipRegion = true; |
94 | 0 | } |
95 | | |
96 | 0 | IMPL_LINK_NOARG(InterimItemWindow, DoLayout, Timer*, void) { Layout(); } |
97 | | |
98 | | void InterimItemWindow::Layout() |
99 | 0 | { |
100 | 0 | m_aLayoutIdle.Stop(); |
101 | 0 | vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); |
102 | 0 | assert(pChild); |
103 | 0 | VclContainer::setLayoutAllocation(*pChild, Point(0, 0), GetSizePixel()); |
104 | 0 | Control::Resize(); |
105 | 0 | } |
106 | | |
107 | | Size InterimItemWindow::GetOptimalSize() const |
108 | 0 | { |
109 | 0 | return VclContainer::getLayoutRequisition(*GetWindow(GetWindowType::FirstChild)); |
110 | 0 | } |
111 | | |
112 | | void InterimItemWindow::InvalidateChildSizeCache() |
113 | 0 | { |
114 | | // find the bottom vcl::Window of the hierarchy and queue_resize on that |
115 | | // one will invalidate all the size caches upwards |
116 | 0 | vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); |
117 | 0 | while (true) |
118 | 0 | { |
119 | 0 | vcl::Window* pSubChild = pChild->GetWindow(GetWindowType::FirstChild); |
120 | 0 | if (!pSubChild) |
121 | 0 | break; |
122 | 0 | pChild = pSubChild; |
123 | 0 | } |
124 | 0 | pChild->queue_resize(); |
125 | 0 | } |
126 | | |
127 | | bool InterimItemWindow::ControlHasFocus() const |
128 | 0 | { |
129 | 0 | if (!m_pWidget) |
130 | 0 | return false; |
131 | 0 | return m_pWidget->has_focus(); |
132 | 0 | } |
133 | | |
134 | 0 | void InterimItemWindow::InitControlBase(weld::Widget* pWidget) { m_pWidget = pWidget; } |
135 | | |
136 | | void InterimItemWindow::GetFocus() |
137 | 0 | { |
138 | | // tdf#157738 Don't grab focus to the other widget hierarchy if the parent has |
139 | | // captured the mouse in order to avoid breaking the capture. |
140 | 0 | ImplSVWinData* pWinData = ImplGetSVData()->mpWinData; |
141 | 0 | const bool bParentHasCapturedMouse |
142 | 0 | = pWinData->mpCaptureWin && pWinData->mpCaptureWin->ImplIsChild(this); |
143 | 0 | if (m_pWidget && !bParentHasCapturedMouse) |
144 | 0 | m_pWidget->grab_focus(); |
145 | | |
146 | | /* let toolbox know this item window has focus so it updates its mnHighItemId to point |
147 | | to this toolitem in case tab means to move to another toolitem within |
148 | | the toolbox |
149 | | */ |
150 | 0 | vcl::Window* pToolBox = GetParent(); |
151 | 0 | NotifyEvent aNEvt(NotifyEventType::GETFOCUS, this); |
152 | 0 | pToolBox->EventNotify(aNEvt); |
153 | 0 | } |
154 | | |
155 | | bool InterimItemWindow::ChildKeyInput(const KeyEvent& rKEvt) |
156 | 0 | { |
157 | 0 | sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); |
158 | 0 | if (nCode != KEY_TAB) |
159 | 0 | return false; |
160 | | |
161 | | /* if the native widget has focus, then no vcl window has focus. |
162 | | |
163 | | We want to grab focus to this vcl widget so that pressing tab will traverse |
164 | | to the next vcl widget. |
165 | | |
166 | | But just using GrabFocus will, because no vcl widget has focus, trigger |
167 | | bringing the toplevel to front with the expectation that a suitable widget |
168 | | will be picked for focus when that happen, which is no use to us here. |
169 | | |
170 | | SetFakeFocus avoids the problem, allowing GrabFocus to do the expected thing |
171 | | then sending the Tab to our parent will do the right traversal |
172 | | */ |
173 | 0 | SetFakeFocus(true); |
174 | 0 | GrabFocus(); |
175 | | |
176 | | /* now give focus to our toolbox parent */ |
177 | 0 | vcl::Window* pToolBox = GetParent(); |
178 | 0 | pToolBox->GrabFocus(); |
179 | | |
180 | | /* let toolbox know this item window has focus so it updates its mnHighItemId to point |
181 | | to this toolitem in case tab means to move to another toolitem within |
182 | | the toolbox |
183 | | */ |
184 | 0 | NotifyEvent aNEvt(NotifyEventType::GETFOCUS, this); |
185 | 0 | pToolBox->EventNotify(aNEvt); |
186 | | |
187 | | /* send parent the tab */ |
188 | 0 | pToolBox->KeyInput(rKEvt); |
189 | |
|
190 | 0 | return true; |
191 | 0 | } |
192 | | |
193 | | void InterimItemWindow::Draw(OutputDevice& rDevice, const Point& rPos, |
194 | | SystemTextColorFlags /*nFlags*/) |
195 | 0 | { |
196 | 0 | m_xContainer->draw(rDevice, rPos, GetSizePixel()); |
197 | 0 | } |
198 | | |
199 | | void InterimItemWindow::SetPriority(TaskPriority nPriority) |
200 | 0 | { |
201 | | // Eliminate warning when changing timer's priority |
202 | | // Task::SetPriority() expects the timer to be stopped while |
203 | | // changing the timer's priority. |
204 | 0 | bool bActive = m_aLayoutIdle.IsActive(); |
205 | 0 | if (bActive) |
206 | 0 | m_aLayoutIdle.Stop(); |
207 | 0 | m_aLayoutIdle.SetPriority(nPriority); |
208 | 0 | if (bActive) |
209 | 0 | m_aLayoutIdle.Start(); |
210 | 0 | } |
211 | | |
212 | | void InterimItemWindow::ImplPaintToDevice(OutputDevice& rTargetOutDev, const Point& rPos) |
213 | 0 | { |
214 | 0 | Draw(rTargetOutDev, rPos, SystemTextColorFlags::NONE); |
215 | 0 | } |
216 | | |
217 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |