LibreOffice Module sfx2 (master) 1
Deck.cxx
Go to the documentation of this file.
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 <sfx2/sidebar/Deck.hxx>
28#include <sfx2/viewsh.hxx>
29
30#include <vcl/event.hxx>
31#include <comphelper/lok.hxx>
33#include <tools/json_writer.hxx>
34
35using namespace css;
36using namespace css::uno;
37
38namespace sfx2::sidebar {
39
41{
43 {
44 sal_uInt64 nShellId = reinterpret_cast<sal_uInt64>(SfxViewShell::Current());
45 jsdialog::SendFullUpdate(OUString::number(nShellId) + "sidebar", "Panel");
46 }
47}
48
49Deck::Deck(const DeckDescriptor& rDeckDescriptor, SidebarDockingWindow* pParentWindow,
50 const std::function<void()>& rCloserAction)
51 : InterimItemWindow(pParentWindow, "sfx/ui/deck.ui", "Deck")
52 , msId(rDeckDescriptor.msId)
53 , mnMinimalWidth(0)
54 , mnScrolledWindowExtraWidth(0)
55 , mnMinimalHeight(0)
56 , maPanels()
57 , mxParentWindow(pParentWindow)
58 , mxTitleBar(new DeckTitleBar(rDeckDescriptor.msTitle, *m_xBuilder, rCloserAction))
59 , mxVerticalScrollBar(m_xBuilder->weld_scrolled_window("scrolledwindow"))
60 , mxContents(m_xBuilder->weld_box("contents"))
61{
63
65
66 mxVerticalScrollBar->vadjustment_set_step_increment(10);
67 mxVerticalScrollBar->vadjustment_set_page_increment(100);
68
69 // tdf#142458 Measure the preferred width of an empty ScrolledWindow
70 // to add to the width of the union of panel widths when calculating
71 // the minimal width of the deck
72 mxVerticalScrollBar->set_hpolicy(VclPolicyType::NEVER);
73 mxVerticalScrollBar->set_vpolicy(VclPolicyType::NEVER);
74 mnScrolledWindowExtraWidth = mxVerticalScrollBar->get_preferred_size().Width();
75 mxVerticalScrollBar->set_hpolicy(VclPolicyType::AUTOMATIC);
76 mxVerticalScrollBar->set_vpolicy(VclPolicyType::AUTOMATIC);
77}
78
80{
82}
83
85{
87 aPanels.swap(maPanels);
88
89 // We have to explicitly trigger the destruction of panels.
90 // Otherwise that is done by one of our base class destructors
91 // without updating maPanels.
92 for (auto& rpPanel : aPanels)
93 rpPanel.reset();
94
95 maPanels.clear();
96 mxTitleBar.reset();
97 mxContents.reset();
98 mxVerticalScrollBar.reset();
99
100 mxParentWindow.clear();
101
103}
104
106{
107 return mxTitleBar.get();
108}
109
111{
112 const Size aWindowSize (GetSizePixel());
113 const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize));
114 if (aWindowSize.IsEmpty())
115 return tools::Rectangle();
116
117 return tools::Rectangle(
120 aWindowSize.Width() - 1 - Theme::GetInteger(Theme::Int_DeckRightPadding) - nBorderSize,
121 aWindowSize.Height() - 1 - Theme::GetInteger(Theme::Int_DeckBottomPadding) - nBorderSize);
122}
123
125{
126 for (auto& rpPanel : maPanels)
127 rpPanel->DataChanged();
128
131}
132
133/*
134 * Get the ordering as is shown in the layout, and our type as 'deck'
135 * also elide nested panel windows.
136 */
138{
139 rJsonWriter.put("id", get_id().isEmpty() ? msId : get_id());
140 rJsonWriter.put("type", "deck");
141 rJsonWriter.put("text", GetText());
142 rJsonWriter.put("enabled", IsEnabled());
143 if (!IsVisible())
144 rJsonWriter.put("visible", false);
145
146 auto childrenNode = rJsonWriter.startArray("children");
147 for (const auto &it : maPanels)
148 {
149 // collapse the panel itself out
150 auto xContent = it->GetContents();
151 if (!xContent)
152 continue;
153
154 auto childNode = rJsonWriter.startStruct();
155 rJsonWriter.put("id", it->GetId());
156 rJsonWriter.put("type", "panel");
157 rJsonWriter.put("text", it->GetTitle());
158 rJsonWriter.put("enabled", true);
159 rJsonWriter.put("hidden", it->IsLurking());
160 rJsonWriter.put("expanded", it->IsExpanded());
161
162 if (it->GetTitleBar() && !it->GetTitleBar()->GetMoreOptionsCommand().isEmpty())
163 rJsonWriter.put("command", it->GetTitleBar()->GetMoreOptionsCommand());
164
165 {
166 auto children2Node = rJsonWriter.startArray("children");
167 {
168 auto child2Node = rJsonWriter.startStruct();
169 xContent->get_property_tree(rJsonWriter);
170 }
171 }
172 }
173}
174
180{
181 SharedPanelContainer aHiddens;
182
183 // First hide old panels we don't need just now.
184 for (auto& rpPanel : maPanels)
185 {
186 bool bFound = false;
187 for (const auto & i : rPanelContainer)
188 bFound = bFound || (rpPanel.get() == i.get());
189 if (!bFound) // this one didn't survive.
190 {
191 rpPanel->SetLurkMode(true);
192 aHiddens.push_back(rpPanel);
193 }
194 }
195
196 bool bDifferent = maPanels.size() != rPanelContainer.size() || aHiddens.size();
197 maPanels = std::move(rPanelContainer);
198
199 // Hidden ones always at the end
200 maPanels.insert(std::end(maPanels), std::begin(aHiddens), std::end(aHiddens));
201
203
204 if (bDifferent)
206}
207
209{
210 mnMinimalWidth = 0;
211 mnMinimalHeight = 0;
212
216
217 if (mnMinimalWidth)
218 {
219 // tdf#142458 at this point mnMinimalWidth contains the width required
220 // by the panels, but extra space may be needed by the scrolledwindow
221 // that will contain the panels
223 }
224}
225
227{
229
231 return;
232
233 bool bChangeNeeded = false;
234 Size aParentSize = mxParentWindow->GetSizePixel();
235
236 if (mnMinimalHeight > 0 && (mnMinimalHeight != aParentSize.Height() || GetSizePixel().Height() != mnMinimalHeight))
237 {
238 aParentSize.setHeight(mnMinimalHeight);
239 bChangeNeeded = true;
240 }
241 const SfxViewShell* pViewShell = SfxViewShell::Current();
242 if (mnMinimalWidth > 0 && (mnMinimalWidth != aParentSize.Width() || GetSizePixel().Width() != mnMinimalWidth)
243 && pViewShell && pViewShell->isLOKMobilePhone())
244 {
245 aParentSize.setWidth(mnMinimalWidth);
246 bChangeNeeded = true;
247 }
248
249 if (bChangeNeeded)
250 {
251 mxParentWindow->SetSizePixel(aParentSize);
252 setPosSizePixel(0, 0, aParentSize.Width(), aParentSize.Height());
253 }
254 else if (aParentSize != GetSizePixel()) //Sync parent & child sizes
255 setPosSizePixel(0, 0, aParentSize.Width(), aParentSize.Height());
256}
257
259{
260 return mxContents.get();
261}
262
263std::shared_ptr<Panel> Deck::GetPanel(std::u16string_view panelId)
264{
265 for (const auto& pPanel : maPanels)
266 {
267 if(pPanel->GetId() == panelId)
268 {
269 return pPanel;
270 }
271 }
272 return nullptr;
273
274}
275
276void Deck::ShowPanel(const Panel& rPanel)
277{
278 if (!mxVerticalScrollBar || mxVerticalScrollBar->get_vpolicy() == VclPolicyType::NEVER)
279 return;
280
281 // Get vertical extent of the panel.
282 tools::Rectangle aExtents;
283 if (!rPanel.get_extents(aExtents))
284 return;
285
286 auto nPanelTop = aExtents.Top();
287 auto nPanelBottom = aExtents.Bottom() - 1;
288
289 // Determine what the new thumb position should be like.
290 // When the whole panel does not fit then make its top visible
291 // and it off at the bottom.
292 sal_Int32 nNewThumbPos(mxVerticalScrollBar->vadjustment_get_value());
293 if (nPanelBottom >= nNewThumbPos + mxVerticalScrollBar->vadjustment_get_page_size())
294 nNewThumbPos = nPanelBottom - mxVerticalScrollBar->vadjustment_get_page_size();
295 if (nPanelTop < nNewThumbPos)
296 nNewThumbPos = nPanelTop;
297
298 mxVerticalScrollBar->vadjustment_set_value(nNewThumbPos);
299}
300
301} // end of namespace sfx2::sidebar
302
303/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual void dispose() override
std::unique_ptr< weld::Container > m_xContainer
One SfxViewShell more or less represents one edit window for a document, there can be multiple ones f...
Definition: viewsh.hxx:165
bool isLOKMobilePhone() const
Check if the lok client is running on a mobile device.
Definition: viewsh.hxx:470
static SAL_WARN_UNUSED_RESULT SfxViewShell * Current()
Definition: viewsh.cxx:1848
bool IsEmpty() const
constexpr tools::Long Height() const
void setWidth(tools::Long nWidth)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
virtual ~Deck() override
Definition: Deck.cxx:79
std::unique_ptr< DeckTitleBar > mxTitleBar
Definition: Deck.hxx:82
weld::Widget * GetPanelParentWindow()
Definition: Deck.cxx:258
void RequestLayoutInternal()
Definition: Deck.cxx:208
sal_Int32 mnScrolledWindowExtraWidth
Definition: Deck.hxx:77
std::unique_ptr< weld::ScrolledWindow > mxVerticalScrollBar
Definition: Deck.hxx:83
Deck(const DeckDescriptor &rDeckDescriptor, SidebarDockingWindow *pParentWindow, const std::function< void()> &rCloserAction)
Definition: Deck.cxx:49
SharedPanelContainer maPanels
Definition: Deck.hxx:79
virtual void DumpAsPropertyTree(tools::JsonWriter &) override
Definition: Deck.cxx:137
sal_Int32 mnMinimalHeight
Definition: Deck.hxx:78
std::shared_ptr< Panel > GetPanel(std::u16string_view panelId)
Definition: Deck.cxx:263
void ShowPanel(const Panel &rPanel)
Try to make the panel completely visible.
Definition: Deck.cxx:276
const OUString msId
Definition: Deck.hxx:75
DeckTitleBar * GetTitleBar() const
Definition: Deck.cxx:105
tools::Rectangle GetContentArea() const
Definition: Deck.cxx:110
static void LOKSendSidebarFullUpdate()
Definition: Deck.cxx:40
std::unique_ptr< weld::Box > mxContents
Definition: Deck.hxx:84
virtual void dispose() override
Definition: Deck.cxx:84
VclPtr< SidebarDockingWindow > mxParentWindow
Definition: Deck.hxx:81
virtual void DataChanged(const DataChangedEvent &rEvent) override
Definition: Deck.cxx:124
void ResetPanels(SharedPanelContainer &&rPanels)
This container may contain existing panels that are being re-used, and new ones too.
Definition: Deck.cxx:179
sal_Int32 mnMinimalWidth
Definition: Deck.hxx:76
void RequestLayout()
Definition: Deck.cxx:226
Multiple panels form a single deck.
Definition: Panel.hxx:54
bool get_extents(tools::Rectangle &rExtents) const
Definition: Panel.cxx:72
static Color GetColor(const ThemeItem eItem)
Definition: Theme.cxx:49
static sal_Int32 GetInteger(const ThemeItem eItem)
Definition: Theme.cxx:61
void put(std::u16string_view pPropName, const OUString &rPropValue)
ScopedJsonWriterStruct startStruct()
ScopedJsonWriterArray startArray(std::string_view)
constexpr tools::Long Top() const
constexpr tools::Long Bottom() const
void SetStyle(WinBits nStyle)
const OUString & get_id() const
WinBits GetStyle() const
virtual void setPosSizePixel(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, PosSizeFlags nFlags=PosSizeFlags::All)
virtual Size GetSizePixel() const
bool IsVisible() const
virtual OUString GetText() const
bool IsEnabled() const
int i
VCL_DLLPUBLIC void SendFullUpdate(const OUString &nWindowId, const OUString &rWidget)
void LayoutDeck(const SidebarDockingWindow *pDockingWindow, const tools::Rectangle &rContentArea, sal_Int32 &rMinimalWidth, sal_Int32 &rMinimalHeight, SharedPanelContainer &rPanels, DeckTitleBar &pDeckTitleBar, weld::ScrolledWindow &pVerticalScrollBar)
std::vector< std::shared_ptr< Panel > > SharedPanelContainer
Definition: Panel.hxx:118
WinBits const WB_DIALOGCONTROL