1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sfx2/sidebar/Deck.hxx>
21 #include <sidebar/DeckDescriptor.hxx>
22 #include <sidebar/DeckLayouter.hxx>
23 #include <sidebar/DeckTitleBar.hxx>
24 #include <sidebar/PanelTitleBar.hxx>
25 #include <sfx2/sidebar/Panel.hxx>
26 #include <sfx2/sidebar/SidebarDockingWindow.hxx>
27 #include <sfx2/sidebar/Theme.hxx>
28 #include <sfx2/viewsh.hxx>
30 #include <vcl/event.hxx>
31 #include <comphelper/lok.hxx>
32 #include <vcl/commandevent.hxx>
33 #include <vcl/IDialogRenderable.hxx>
34 #include <toolkit/helper/vclunohelper.hxx>
35 #include <tools/svborder.hxx>
36 #include <tools/json_writer.hxx>
37 #include <sal/log.hxx>
40 using namespace css::uno
;
42 namespace sfx2::sidebar
{
44 Deck::Deck(const DeckDescriptor
& rDeckDescriptor
, SidebarDockingWindow
* pParentWindow
,
45 const std::function
<void()>& rCloserAction
)
46 : InterimItemWindow(pParentWindow
, "sfx/ui/deck.ui", "Deck")
47 , msId(rDeckDescriptor
.msId
)
49 , mnScrolledWindowExtraWidth(0)
52 , mxParentWindow(pParentWindow
)
53 , mxTitleBar(new DeckTitleBar(rDeckDescriptor
.msTitle
, *m_xBuilder
, rCloserAction
))
54 , mxVerticalScrollBar(m_xBuilder
->weld_scrolled_window("scrolledwindow"))
55 , mxContents(m_xBuilder
->weld_box("contents"))
57 SetStyle(GetStyle() | WB_DIALOGCONTROL
);
59 m_xContainer
->set_background(Theme::GetColor(Theme::Color_DeckBackground
));
61 mxVerticalScrollBar
->vadjustment_set_step_increment(10);
62 mxVerticalScrollBar
->vadjustment_set_page_increment(100);
64 // tdf#142458 Measure the preferred width of an empty ScrolledWindow
65 // to add to the width of the union of panel widths when calculating
66 // the minimal width of the deck
67 mxVerticalScrollBar
->set_hpolicy(VclPolicyType::NEVER
);
68 mxVerticalScrollBar
->set_vpolicy(VclPolicyType::NEVER
);
69 mnScrolledWindowExtraWidth
= mxVerticalScrollBar
->get_preferred_size().Width();
70 mxVerticalScrollBar
->set_hpolicy(VclPolicyType::AUTOMATIC
);
71 mxVerticalScrollBar
->set_vpolicy(VclPolicyType::AUTOMATIC
);
81 SharedPanelContainer aPanels
;
82 aPanels
.swap(maPanels
);
84 // We have to explicitly trigger the destruction of panels.
85 // Otherwise that is done by one of our base class destructors
86 // without updating maPanels.
87 for (auto& rpPanel
: aPanels
)
93 mxVerticalScrollBar
.reset();
95 mxParentWindow
.clear();
97 InterimItemWindow::dispose();
100 DeckTitleBar
* Deck::GetTitleBar() const
102 return mxTitleBar
.get();
105 tools::Rectangle
Deck::GetContentArea() const
107 const Size
aWindowSize (GetSizePixel());
108 const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize
));
109 if (aWindowSize
.IsEmpty())
110 return tools::Rectangle();
112 return tools::Rectangle(
113 Theme::GetInteger(Theme::Int_DeckLeftPadding
) + nBorderSize
,
114 Theme::GetInteger(Theme::Int_DeckTopPadding
) + nBorderSize
,
115 aWindowSize
.Width() - 1 - Theme::GetInteger(Theme::Int_DeckRightPadding
) - nBorderSize
,
116 aWindowSize
.Height() - 1 - Theme::GetInteger(Theme::Int_DeckBottomPadding
) - nBorderSize
);
119 void Deck::DataChanged(const DataChangedEvent
&)
121 for (auto& rpPanel
: maPanels
)
122 rpPanel
->DataChanged();
124 RequestLayoutInternal();
128 * Get the ordering as is shown in the layout, and our type as 'deck'
129 * also elide nested panel windows.
131 void Deck::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
133 rJsonWriter
.put("id", get_id().isEmpty() ? msId
: get_id());
134 rJsonWriter
.put("type", "deck");
135 rJsonWriter
.put("text", GetText());
136 rJsonWriter
.put("enabled", IsEnabled());
138 rJsonWriter
.put("visible", false);
140 auto childrenNode
= rJsonWriter
.startArray("children");
141 for (const auto &it
: maPanels
)
143 // collapse the panel itself out
144 auto xContent
= it
->GetContents();
148 auto childNode
= rJsonWriter
.startStruct();
149 rJsonWriter
.put("id", it
->GetId());
150 rJsonWriter
.put("type", "panel");
151 rJsonWriter
.put("text", it
->GetTitle());
152 rJsonWriter
.put("enabled", true);
153 rJsonWriter
.put("hidden", it
->IsLurking());
154 rJsonWriter
.put("expanded", it
->IsExpanded());
156 if (it
->GetTitleBar() && !it
->GetTitleBar()->GetMoreOptionsCommand().isEmpty())
157 rJsonWriter
.put("command", it
->GetTitleBar()->GetMoreOptionsCommand());
160 auto children2Node
= rJsonWriter
.startArray("children");
162 auto child2Node
= rJsonWriter
.startStruct();
163 xContent
->get_property_tree(rJsonWriter
);
170 * This container may contain existing panels that are
171 * being re-used, and new ones too.
173 void Deck::ResetPanels(SharedPanelContainer
&& rPanelContainer
)
175 SharedPanelContainer aHiddens
;
177 // First hide old panels we don't need just now.
178 for (auto& rpPanel
: maPanels
)
181 for (const auto & i
: rPanelContainer
)
182 bFound
= bFound
|| (rpPanel
.get() == i
.get());
183 if (!bFound
) // this one didn't survive.
185 rpPanel
->SetLurkMode(true);
186 aHiddens
.push_back(rpPanel
);
189 maPanels
= std::move(rPanelContainer
);
191 // Hidden ones always at the end
192 maPanels
.insert(std::end(maPanels
), std::begin(aHiddens
), std::end(aHiddens
));
194 RequestLayoutInternal();
197 void Deck::RequestLayoutInternal()
202 DeckLayouter::LayoutDeck(mxParentWindow
.get(), GetContentArea(),
203 mnMinimalWidth
, mnMinimalHeight
, maPanels
,
204 *GetTitleBar(), *mxVerticalScrollBar
);
208 // tdf#142458 at this point mnMinimalWidth contains the width required
209 // by the panels, but extra space may be needed by the scrolledwindow
210 // that will contain the panels
211 mnMinimalWidth
+= mnScrolledWindowExtraWidth
;
215 void Deck::RequestLayout()
217 RequestLayoutInternal();
219 if (!comphelper::LibreOfficeKit::isActive())
222 bool bChangeNeeded
= false;
223 Size aParentSize
= mxParentWindow
->GetSizePixel();
225 if (mnMinimalHeight
> 0 && (mnMinimalHeight
!= aParentSize
.Height() || GetSizePixel().Height() != mnMinimalHeight
))
227 aParentSize
.setHeight(mnMinimalHeight
);
228 bChangeNeeded
= true;
230 const SfxViewShell
* pViewShell
= SfxViewShell::Current();
231 if (mnMinimalWidth
> 0 && (mnMinimalWidth
!= aParentSize
.Width() || GetSizePixel().Width() != mnMinimalWidth
)
232 && pViewShell
&& pViewShell
->isLOKMobilePhone())
234 aParentSize
.setWidth(mnMinimalWidth
);
235 bChangeNeeded
= true;
240 mxParentWindow
->SetSizePixel(aParentSize
);
241 setPosSizePixel(0, 0, aParentSize
.Width(), aParentSize
.Height());
243 else if (aParentSize
!= GetSizePixel()) //Sync parent & child sizes
244 setPosSizePixel(0, 0, aParentSize
.Width(), aParentSize
.Height());
247 weld::Widget
* Deck::GetPanelParentWindow()
249 return mxContents
.get();
252 std::shared_ptr
<Panel
> Deck::GetPanel(std::u16string_view panelId
)
254 for (const auto& pPanel
: maPanels
)
256 if(pPanel
->GetId() == panelId
)
265 void Deck::ShowPanel(const Panel
& rPanel
)
267 if (!mxVerticalScrollBar
|| mxVerticalScrollBar
->get_vpolicy() == VclPolicyType::NEVER
)
270 // Get vertical extent of the panel.
271 tools::Rectangle aExtents
;
272 if (!rPanel
.get_extents(aExtents
))
275 auto nPanelTop
= aExtents
.Top();
276 auto nPanelBottom
= aExtents
.Bottom() - 1;
278 // Determine what the new thumb position should be like.
279 // When the whole panel does not fit then make its top visible
280 // and it off at the bottom.
281 sal_Int32
nNewThumbPos(mxVerticalScrollBar
->vadjustment_get_value());
282 if (nPanelBottom
>= nNewThumbPos
+ mxVerticalScrollBar
->vadjustment_get_page_size())
283 nNewThumbPos
= nPanelBottom
- mxVerticalScrollBar
->vadjustment_get_page_size();
284 if (nPanelTop
< nNewThumbPos
)
285 nNewThumbPos
= nPanelTop
;
287 mxVerticalScrollBar
->vadjustment_set_value(nNewThumbPos
);
290 } // end of namespace sfx2::sidebar
292 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */