summaryrefslogtreecommitdiffstats
path: root/sfx2/source/sidebar/Deck.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sfx2/source/sidebar/Deck.cxx287
1 files changed, 287 insertions, 0 deletions
diff --git a/sfx2/source/sidebar/Deck.cxx b/sfx2/source/sidebar/Deck.cxx
new file mode 100644
index 000000000..b6ddffa89
--- /dev/null
+++ b/sfx2/source/sidebar/Deck.cxx
@@ -0,0 +1,287 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/sidebar/Deck.hxx>
+#include <sidebar/DeckDescriptor.hxx>
+#include <sidebar/DeckLayouter.hxx>
+#include <sidebar/DeckTitleBar.hxx>
+#include <sidebar/PanelTitleBar.hxx>
+#include <sfx2/sidebar/Panel.hxx>
+#include <sfx2/sidebar/SidebarDockingWindow.hxx>
+#include <sfx2/sidebar/Theme.hxx>
+#include <sfx2/viewsh.hxx>
+
+#include <vcl/event.hxx>
+#include <comphelper/lok.hxx>
+#include <tools/json_writer.hxx>
+
+using namespace css;
+using namespace css::uno;
+
+namespace sfx2::sidebar {
+
+Deck::Deck(const DeckDescriptor& rDeckDescriptor, SidebarDockingWindow* pParentWindow,
+ const std::function<void()>& rCloserAction)
+ : InterimItemWindow(pParentWindow, "sfx/ui/deck.ui", "Deck")
+ , msId(rDeckDescriptor.msId)
+ , mnMinimalWidth(0)
+ , mnScrolledWindowExtraWidth(0)
+ , mnMinimalHeight(0)
+ , maPanels()
+ , mxParentWindow(pParentWindow)
+ , mxTitleBar(new DeckTitleBar(rDeckDescriptor.msTitle, *m_xBuilder, rCloserAction))
+ , mxVerticalScrollBar(m_xBuilder->weld_scrolled_window("scrolledwindow"))
+ , mxContents(m_xBuilder->weld_box("contents"))
+{
+ SetStyle(GetStyle() | WB_DIALOGCONTROL);
+
+ m_xContainer->set_background(Theme::GetColor(Theme::Color_DeckBackground));
+
+ mxVerticalScrollBar->vadjustment_set_step_increment(10);
+ mxVerticalScrollBar->vadjustment_set_page_increment(100);
+
+ // tdf#142458 Measure the preferred width of an empty ScrolledWindow
+ // to add to the width of the union of panel widths when calculating
+ // the minimal width of the deck
+ mxVerticalScrollBar->set_hpolicy(VclPolicyType::NEVER);
+ mxVerticalScrollBar->set_vpolicy(VclPolicyType::NEVER);
+ mnScrolledWindowExtraWidth = mxVerticalScrollBar->get_preferred_size().Width();
+ mxVerticalScrollBar->set_hpolicy(VclPolicyType::AUTOMATIC);
+ mxVerticalScrollBar->set_vpolicy(VclPolicyType::AUTOMATIC);
+}
+
+Deck::~Deck()
+{
+ disposeOnce();
+}
+
+void Deck::dispose()
+{
+ SharedPanelContainer aPanels;
+ aPanels.swap(maPanels);
+
+ // We have to explicitly trigger the destruction of panels.
+ // Otherwise that is done by one of our base class destructors
+ // without updating maPanels.
+ for (auto& rpPanel : aPanels)
+ rpPanel.reset();
+
+ maPanels.clear();
+ mxTitleBar.reset();
+ mxContents.reset();
+ mxVerticalScrollBar.reset();
+
+ mxParentWindow.clear();
+
+ InterimItemWindow::dispose();
+}
+
+DeckTitleBar* Deck::GetTitleBar() const
+{
+ return mxTitleBar.get();
+}
+
+tools::Rectangle Deck::GetContentArea() const
+{
+ const Size aWindowSize (GetSizePixel());
+ const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize));
+ if (aWindowSize.IsEmpty())
+ return tools::Rectangle();
+
+ return tools::Rectangle(
+ Theme::GetInteger(Theme::Int_DeckLeftPadding) + nBorderSize,
+ Theme::GetInteger(Theme::Int_DeckTopPadding) + nBorderSize,
+ aWindowSize.Width() - 1 - Theme::GetInteger(Theme::Int_DeckRightPadding) - nBorderSize,
+ aWindowSize.Height() - 1 - Theme::GetInteger(Theme::Int_DeckBottomPadding) - nBorderSize);
+}
+
+void Deck::DataChanged(const DataChangedEvent&)
+{
+ for (auto& rpPanel : maPanels)
+ rpPanel->DataChanged();
+
+ RequestLayoutInternal();
+}
+
+/*
+ * Get the ordering as is shown in the layout, and our type as 'deck'
+ * also elide nested panel windows.
+ */
+void Deck::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
+{
+ rJsonWriter.put("id", get_id().isEmpty() ? msId : get_id());
+ rJsonWriter.put("type", "deck");
+ rJsonWriter.put("text", GetText());
+ rJsonWriter.put("enabled", IsEnabled());
+ if (!IsVisible())
+ rJsonWriter.put("visible", false);
+
+ auto childrenNode = rJsonWriter.startArray("children");
+ for (const auto &it : maPanels)
+ {
+ // collapse the panel itself out
+ auto xContent = it->GetContents();
+ if (!xContent)
+ continue;
+
+ auto childNode = rJsonWriter.startStruct();
+ rJsonWriter.put("id", it->GetId());
+ rJsonWriter.put("type", "panel");
+ rJsonWriter.put("text", it->GetTitle());
+ rJsonWriter.put("enabled", true);
+ rJsonWriter.put("hidden", it->IsLurking());
+ rJsonWriter.put("expanded", it->IsExpanded());
+
+ if (it->GetTitleBar() && !it->GetTitleBar()->GetMoreOptionsCommand().isEmpty())
+ rJsonWriter.put("command", it->GetTitleBar()->GetMoreOptionsCommand());
+
+ {
+ auto children2Node = rJsonWriter.startArray("children");
+ {
+ auto child2Node = rJsonWriter.startStruct();
+ xContent->get_property_tree(rJsonWriter);
+ }
+ }
+ }
+}
+
+/**
+ * This container may contain existing panels that are
+ * being re-used, and new ones too.
+ */
+void Deck::ResetPanels(SharedPanelContainer&& rPanelContainer)
+{
+ SharedPanelContainer aHiddens;
+
+ // First hide old panels we don't need just now.
+ for (auto& rpPanel : maPanels)
+ {
+ bool bFound = false;
+ for (const auto & i : rPanelContainer)
+ bFound = bFound || (rpPanel.get() == i.get());
+ if (!bFound) // this one didn't survive.
+ {
+ rpPanel->SetLurkMode(true);
+ aHiddens.push_back(rpPanel);
+ }
+ }
+ maPanels = std::move(rPanelContainer);
+
+ // Hidden ones always at the end
+ maPanels.insert(std::end(maPanels), std::begin(aHiddens), std::end(aHiddens));
+
+ RequestLayoutInternal();
+}
+
+void Deck::RequestLayoutInternal()
+{
+ mnMinimalWidth = 0;
+ mnMinimalHeight = 0;
+
+ DeckLayouter::LayoutDeck(mxParentWindow.get(), GetContentArea(),
+ mnMinimalWidth, mnMinimalHeight, maPanels,
+ *GetTitleBar(), *mxVerticalScrollBar);
+
+ if (mnMinimalWidth)
+ {
+ // tdf#142458 at this point mnMinimalWidth contains the width required
+ // by the panels, but extra space may be needed by the scrolledwindow
+ // that will contain the panels
+ mnMinimalWidth += mnScrolledWindowExtraWidth;
+ }
+}
+
+void Deck::RequestLayout()
+{
+ RequestLayoutInternal();
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ bool bChangeNeeded = false;
+ Size aParentSize = mxParentWindow->GetSizePixel();
+
+ if (mnMinimalHeight > 0 && (mnMinimalHeight != aParentSize.Height() || GetSizePixel().Height() != mnMinimalHeight))
+ {
+ aParentSize.setHeight(mnMinimalHeight);
+ bChangeNeeded = true;
+ }
+ const SfxViewShell* pViewShell = SfxViewShell::Current();
+ if (mnMinimalWidth > 0 && (mnMinimalWidth != aParentSize.Width() || GetSizePixel().Width() != mnMinimalWidth)
+ && pViewShell && pViewShell->isLOKMobilePhone())
+ {
+ aParentSize.setWidth(mnMinimalWidth);
+ bChangeNeeded = true;
+ }
+
+ if (bChangeNeeded)
+ {
+ mxParentWindow->SetSizePixel(aParentSize);
+ setPosSizePixel(0, 0, aParentSize.Width(), aParentSize.Height());
+ }
+ else if (aParentSize != GetSizePixel()) //Sync parent & child sizes
+ setPosSizePixel(0, 0, aParentSize.Width(), aParentSize.Height());
+}
+
+weld::Widget* Deck::GetPanelParentWindow()
+{
+ return mxContents.get();
+}
+
+std::shared_ptr<Panel> Deck::GetPanel(std::u16string_view panelId)
+{
+ for (const auto& pPanel : maPanels)
+ {
+ if(pPanel->GetId() == panelId)
+ {
+ return pPanel;
+ }
+ }
+ return nullptr;
+
+}
+
+void Deck::ShowPanel(const Panel& rPanel)
+{
+ if (!mxVerticalScrollBar || mxVerticalScrollBar->get_vpolicy() == VclPolicyType::NEVER)
+ return;
+
+ // Get vertical extent of the panel.
+ tools::Rectangle aExtents;
+ if (!rPanel.get_extents(aExtents))
+ return;
+
+ auto nPanelTop = aExtents.Top();
+ auto nPanelBottom = aExtents.Bottom() - 1;
+
+ // Determine what the new thumb position should be like.
+ // When the whole panel does not fit then make its top visible
+ // and it off at the bottom.
+ sal_Int32 nNewThumbPos(mxVerticalScrollBar->vadjustment_get_value());
+ if (nPanelBottom >= nNewThumbPos + mxVerticalScrollBar->vadjustment_get_page_size())
+ nNewThumbPos = nPanelBottom - mxVerticalScrollBar->vadjustment_get_page_size();
+ if (nPanelTop < nNewThumbPos)
+ nNewThumbPos = nPanelTop;
+
+ mxVerticalScrollBar->vadjustment_set_value(nNewThumbPos);
+}
+
+} // end of namespace sfx2::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */