LibreOffice Module sd (master) 1
ViewTabBar.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 <ViewTabBar.hxx>
21
22#include <ViewShellBase.hxx>
24#include <framework/Pane.hxx>
25#include <DrawController.hxx>
26
27#include <Client.hxx>
28#include <utility>
29#include <vcl/settings.hxx>
30#include <vcl/svapp.hxx>
31
32#include <sfx2/viewfrm.hxx>
33#include <com/sun/star/drawing/framework/ResourceId.hpp>
34#include <com/sun/star/drawing/framework/XControllerManager.hpp>
35#include <com/sun/star/lang/DisposedException.hpp>
36#include <com/sun/star/drawing/framework/XView.hpp>
41
42using namespace ::com::sun::star;
43using namespace ::com::sun::star::uno;
45using ::sd::framework::FrameworkHelper;
46
47namespace sd {
48
49namespace {
50bool IsEqual (const TabBarButton& rButton1, const TabBarButton& rButton2)
51{
52 return ((rButton1.ResourceId.is()
53 && rButton2.ResourceId.is()
54 && rButton1.ResourceId->compareTo(rButton2.ResourceId) == 0)
55 || rButton1.ButtonLabel == rButton2.ButtonLabel);
56}
57
58} // end of anonymous namespace
59
61 const Reference<XResourceId>& rxViewTabBarId,
62 const rtl::Reference<::sd::DrawController>& rxController)
63 : mpTabControl(VclPtr<TabBarControl>::Create(GetAnchorWindow(rxViewTabBarId,rxController), this)),
64 mxController(rxController),
65 mxViewTabBarId(rxViewTabBarId),
66 mpViewShellBase(nullptr),
67 mnNoteBookWidthPadding(0)
68{
69 // Do this manually instead of via uno::Reference, so we don't delete ourselves.
70 osl_atomic_increment(&m_refCount);
71
72 // Tunnel through the controller and use the ViewShellBase to obtain the
73 // view frame.
74 if (mxController)
75 mpViewShellBase = mxController->GetViewShellBase();
76
77 // Register as listener at XConfigurationController.
78 if (mxController.is())
79 {
80 mxConfigurationController = mxController->getConfigurationController();
82 {
83 mxConfigurationController->addConfigurationChangeListener(
84 this,
85 FrameworkHelper::msResourceActivationEvent,
86 Any());
87 }
88 }
89
90 mpTabControl->Show();
91
92 if (mpViewShellBase != nullptr
93 && rxViewTabBarId->isBoundToURL(
94 FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
95 {
97 }
98
99 osl_atomic_decrement(&m_refCount);
100}
101
103{
104}
105
106void ViewTabBar::disposing(std::unique_lock<std::mutex>&)
107{
108 if (mpViewShellBase != nullptr
109 && mxViewTabBarId->isBoundToURL(
110 FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
111 {
113 }
114
116 {
117 // Unregister listener from XConfigurationController.
118 try
119 {
120 mxConfigurationController->removeConfigurationChangeListener(this);
121 }
122 catch (const lang::DisposedException&)
123 {
124 // Receiving a disposed exception is the normal case. Is there
125 // a way to avoid it?
126 }
128 }
129
130 {
131 const SolarMutexGuard aSolarGuard;
132 mpTabControl.disposeAndClear();
133 }
134
135 mxController = nullptr;
136}
137
139 const Reference<XResourceId>& rxViewTabBarId,
140 const rtl::Reference<::sd::DrawController>& rxController)
141{
142 vcl::Window* pWindow = nullptr;
143 ViewShellBase* pBase = nullptr;
144
145 // Tunnel through the controller and use the ViewShellBase to obtain the
146 // view frame.
147 if (rxController)
148 pBase = rxController->GetViewShellBase();
149
150 // The ViewTabBar supports at the moment only the center pane.
151 if (rxViewTabBarId.is()
152 && rxViewTabBarId->isBoundToURL(
153 FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
154 {
155 if (pBase != nullptr)
156 pWindow = &pBase->GetViewFrame().GetWindow();
157 }
158
159 // The rest is (at the moment) just for the emergency case.
160 if (pWindow == nullptr)
161 {
162 Reference<XPane> xPane;
163 try
164 {
165 Reference<XConfigurationController> xCC (
166 rxController->getConfigurationController());
167 if (xCC.is())
168 xPane.set(xCC->getResource(rxViewTabBarId->getAnchor()), UNO_QUERY);
169 }
170 catch (const RuntimeException&)
171 {
172 }
173
174 // Tunnel through the XWindow to the VCL side.
175 try
176 {
177 if (auto pPane = dynamic_cast<framework::Pane*>(xPane.get()))
178 pWindow = pPane->GetWindow()->GetParent();
179 }
180 catch (const RuntimeException&)
181 {
182 }
183 }
184
185 return pWindow;
186}
187
188//----- XConfigurationChangeListener ------------------------------------------
189
191 const ConfigurationChangeEvent& rEvent)
192{
193 if (rEvent.Type == FrameworkHelper::msResourceActivationEvent
194 && rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix)
195 && rEvent.ResourceId->isBoundTo(mxViewTabBarId->getAnchor(), AnchorBindingMode_DIRECT))
196 {
198 }
199}
200
201//----- XEventListener --------------------------------------------------------
202
203void SAL_CALL ViewTabBar::disposing(
204 const lang::EventObject& rEvent)
205{
206 if (rEvent.Source == mxConfigurationController)
207 {
209 mxController = nullptr;
210 }
211}
212
213//----- XTabBar ---------------------------------------------------------------
214
216 const TabBarButton& rButton,
217 const TabBarButton& rAnchor)
218{
219 const SolarMutexGuard aSolarGuard;
220 AddTabBarButton(rButton, rAnchor);
221}
222
223void SAL_CALL ViewTabBar::appendTabBarButton (const TabBarButton& rButton)
224{
225 const SolarMutexGuard aSolarGuard;
226 AddTabBarButton(rButton);
227}
228
229void SAL_CALL ViewTabBar::removeTabBarButton (const TabBarButton& rButton)
230{
231 const SolarMutexGuard aSolarGuard;
232 RemoveTabBarButton(rButton);
233}
234
235sal_Bool SAL_CALL ViewTabBar::hasTabBarButton (const TabBarButton& rButton)
236{
237 const SolarMutexGuard aSolarGuard;
238 return HasTabBarButton(rButton);
239}
240
241Sequence<TabBarButton> SAL_CALL ViewTabBar::getTabBarButtons()
242{
243 const SolarMutexGuard aSolarGuard;
244 return GetTabBarButtons();
245}
246
247//----- XResource -------------------------------------------------------------
248
249Reference<XResourceId> SAL_CALL ViewTabBar::getResourceId()
250{
251 return mxViewTabBarId;
252}
253
255{
256 return false;
257}
258
259bool ViewTabBar::ActivatePage(size_t nIndex)
260{
261 try
262 {
263 Reference<XConfigurationController> xConfigurationController (
264 mxController->getConfigurationController());
265 if ( ! xConfigurationController.is())
266 throw RuntimeException();
267 Reference<XView> xView;
268 try
269 {
270 xView.set(xConfigurationController->getResource(
271 ResourceId::create(
272 ::comphelper::getProcessComponentContext(),
273 FrameworkHelper::msCenterPaneURL)),
274 UNO_QUERY);
275 }
276 catch (const DeploymentException&)
277 {
278 }
279
280 Client* pIPClient = nullptr;
281 if (mpViewShellBase != nullptr)
282 pIPClient = dynamic_cast<Client*>(mpViewShellBase->GetIPClient());
283 if (pIPClient==nullptr || ! pIPClient->IsObjectInPlaceActive())
284 {
285 if (nIndex < maTabBarButtons.size())
286 {
287 xConfigurationController->requestResourceActivation(
289 ResourceActivationMode_REPLACE);
290 }
291
292 return true;
293 }
294 }
295 catch (const RuntimeException&)
296 {
297 DBG_UNHANDLED_EXCEPTION("sd.view");
298 }
299
300 return false;
301}
302
304{
305 int nHeight (0);
306
307 if (!maTabBarButtons.empty())
308 {
309 if (mpTabControl->IsReallyVisible())
310 {
311 weld::Notebook& rNotebook = mpTabControl->GetNotebook();
312 int nAllocatedWidth = mpTabControl->GetAllocatedWidth();
313 int nPageWidth = nAllocatedWidth - mnNoteBookWidthPadding;
314
315 // set each page width-request to the size it takes to fit the notebook allocation
316 for (int nIndex = 1, nPageCount = rNotebook.get_n_pages(); nIndex <= nPageCount; ++nIndex)
317 {
318 OUString sIdent(OUString::number(nIndex));
319 weld::Container* pContainer = rNotebook.get_page(sIdent);
320 pContainer->set_size_request(nPageWidth, -1);
321 }
322
323 // get the height-for-width for this allocation
324 nHeight = mpTabControl->get_preferred_size().Height();
325 }
326
327 if (nHeight <= 0)
328 {
329 // Using a default when the real height can not be determined.
330 // To get correct height this method should be called when the
331 // control is visible.
332 nHeight = 21;
333 }
334 }
335
336 return nHeight;
337}
338
340 const css::drawing::framework::TabBarButton& rButton,
341 const css::drawing::framework::TabBarButton& rAnchor)
342{
343 TabBarButtonList::size_type nIndex;
344
345 if ( ! rAnchor.ResourceId.is()
346 || (rAnchor.ResourceId->getResourceURL().isEmpty()
347 && rAnchor.ButtonLabel.isEmpty()))
348 {
349 nIndex = 0;
350 }
351 else
352 {
353 for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
354 {
355 if (IsEqual(maTabBarButtons[nIndex], rAnchor))
356 {
357 ++nIndex;
358 break;
359 }
360 }
361 }
362
363 AddTabBarButton(rButton,nIndex);
364}
365
367 const css::drawing::framework::TabBarButton& rButton)
368{
369 AddTabBarButton(rButton, maTabBarButtons.size());
370}
371
373 const css::drawing::framework::TabBarButton& rButton,
374 sal_Int32 nPosition)
375{
376 if (nPosition >= 0 &&
377 nPosition <= mpTabControl->GetNotebook().get_n_pages())
378 {
379 // Insert the button into our local array.
380 maTabBarButtons.insert(maTabBarButtons.begin() + nPosition, rButton);
383 }
384}
385
387 const css::drawing::framework::TabBarButton& rButton)
388{
389 for (TabBarButtonList::size_type nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
390 {
391 if (IsEqual(maTabBarButtons[nIndex], rButton))
392 {
396 break;
397 }
398 }
399}
400
402 const css::drawing::framework::TabBarButton& rButton)
403{
404 bool bResult (false);
405
406 for (const css::drawing::framework::TabBarButton & r : maTabBarButtons)
407 {
408 if (IsEqual(r, rButton))
409 {
410 bResult = true;
411 break;
412 }
413 }
414
415 return bResult;
416}
417
418css::uno::Sequence<css::drawing::framework::TabBarButton>
420{
422}
423
425{
426 Reference<XView> xView;
427 if (mpViewShellBase != nullptr)
428 xView = FrameworkHelper::Instance(*mpViewShellBase)->GetView(
429 mxViewTabBarId->getAnchor());
430 if (!xView.is())
431 return;
432
433 Reference<XResourceId> xViewId (xView->getResourceId());
434 for (size_t nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
435 {
436 if (maTabBarButtons[nIndex].ResourceId->compareTo(xViewId) == 0)
437 {
438 mpTabControl->GetNotebook().set_current_page(nIndex);
439 break;
440 }
441 }
442}
443
445{
446 int nMaxPageWidthReq(0);
447
448 weld::Notebook& rNotebook = mpTabControl->GetNotebook();
449 int nPageCount(rNotebook.get_n_pages());
450 int nIndex = 1;
451 for (const auto& rTab : maTabBarButtons)
452 {
453 OUString sIdent(OUString::number(nIndex));
454 // Create a new tab when there are not enough.
455 if (nPageCount < nIndex)
456 rNotebook.append_page(sIdent, rTab.ButtonLabel);
457 else
458 {
459 // Update the tab.
460 rNotebook.set_tab_label_text(sIdent, rTab.ButtonLabel);
461 }
462
463 // Set a fairly arbitrary initial width request for the pages so we can
464 // measure what extra width the notebook itself uses
465 weld::Container* pContainer = rNotebook.get_page(sIdent);
466 int nTextWidth = pContainer->get_pixel_size(rTab.ButtonLabel).Width();
467 pContainer->set_size_request(nTextWidth, -1);
468 nMaxPageWidthReq = std::max(nMaxPageWidthReq, nTextWidth);
469
470 ++nIndex;
471 }
472
473 // Delete tabs that are no longer used.
474 for (; nIndex<=nPageCount; ++nIndex)
475 rNotebook.remove_page(OUString::number(nIndex));
476
477 int nWidthReq = rNotebook.get_preferred_size().Width();
478 // The excess width over the page request that the notebook uses we will
479 // use this later to help measure the best height-for-width given the
480 // eventual allocated width of the notebook
481 mnNoteBookWidthPadding = nWidthReq - nMaxPageWidthReq;
482}
483
484//===== TabBarControl =========================================================
485
487 vcl::Window* pParentWindow,
489 : InterimItemWindow(pParentWindow, "modules/simpress/ui/tabviewbar.ui", "TabViewBar")
490 , mxTabControl(m_xBuilder->weld_notebook("tabcontrol"))
491 , mpViewTabBar(std::move(pViewTabBar))
492 , mnAllocatedWidth(0)
493{
494 // Because the actual window background is transparent--to avoid
495 // flickering due to multiple background paintings by this and by child
496 // windows--we have to paint the background for this control explicitly:
497 // the actual control is not painted over its whole bounding box.
498 SetPaintTransparent(false);
499 SetBackground(Application::GetSettings().GetStyleSettings().GetDialogColor());
500
502
503 mxTabControl->connect_enter_page(LINK(this, TabBarControl, ActivatePageHdl));
504 mxTabControl->connect_size_allocate(LINK(this, TabBarControl, NotebookSizeAllocHdl));
505}
506
508{
509 mxTabControl.reset();
511}
512
514{
515 disposeOnce();
516}
517
518IMPL_LINK(TabBarControl, NotebookSizeAllocHdl, const Size&, rSize, void)
519{
520 mnAllocatedWidth = rSize.Width();
521}
522
523IMPL_LINK(TabBarControl, ActivatePageHdl, const OUString&, rPage, void)
524{
525 if (!mpViewTabBar->ActivatePage(mxTabControl->get_page_index(rPage)))
526 {
527 // When we run into this else branch then we have an active OLE
528 // object. We ignore the request to switch views. Additionally
529 // we put the active tab back to the one for the current view.
530 mpViewTabBar->UpdateActiveButton();
531 }
532}
533
534} // end of namespace sd
535
536/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static const AllSettings & GetSettings()
virtual void dispose() override
void InitControlBase(weld::Widget *pWidget)
bool IsObjectInPlaceActive() const
vcl::Window & GetWindow() const
SfxViewFrame & GetViewFrame() const
SfxInPlaceClient * GetIPClient() const
constexpr tools::Long Width() const
virtual ~TabBarControl() override
Definition: ViewTabBar.cxx:513
virtual void dispose() override
Definition: ViewTabBar.cxx:507
TabBarControl(vcl::Window *pParentWindow, ::rtl::Reference< ViewTabBar > pViewTabBar)
Definition: ViewTabBar.cxx:486
std::unique_ptr< weld::Notebook > mxTabControl
Definition: ViewTabBar.hxx:54
SfxViewShell descendant that the stacked Draw/Impress shells are based on.
void SetViewTabBar(const ::rtl::Reference< ViewTabBar > &rViewTabBar)
int GetHeight() const
The returned value is calculated as the difference between the total height of the control and the he...
Definition: ViewTabBar.cxx:303
virtual ~ViewTabBar() override
Definition: ViewTabBar.cxx:102
void UpdateTabBarButtons()
Definition: ViewTabBar.cxx:444
virtual void SAL_CALL addTabBarButtonAfter(const css::drawing::framework::TabBarButton &rButton, const css::drawing::framework::TabBarButton &rAnchor) override
Definition: ViewTabBar.cxx:215
static vcl::Window * GetAnchorWindow(const css::uno::Reference< css::drawing::framework::XResourceId > &rxViewTabBarId, const rtl::Reference<::sd::DrawController > &rxController)
This method is called from the constructor to get the window for an anchor ResourceId and pass it to ...
Definition: ViewTabBar.cxx:138
VclPtr< TabBarControl > mpTabControl
Definition: ViewTabBar.hxx:151
bool ActivatePage(size_t nIndex)
Definition: ViewTabBar.cxx:259
virtual sal_Bool SAL_CALL hasTabBarButton(const css::drawing::framework::TabBarButton &rButton) override
Definition: ViewTabBar.cxx:235
TabBarButtonList maTabBarButtons
Definition: ViewTabBar.hxx:155
css::uno::Sequence< css::drawing::framework::TabBarButton > GetTabBarButtons()
Definition: ViewTabBar.cxx:419
ViewTabBar(const css::uno::Reference< css::drawing::framework::XResourceId > &rxViewTabBarId, const rtl::Reference< ::sd::DrawController > &rxController)
Definition: ViewTabBar.cxx:60
virtual void SAL_CALL removeTabBarButton(const css::drawing::framework::TabBarButton &rButton) override
Definition: ViewTabBar.cxx:229
virtual sal_Bool SAL_CALL isAnchorOnly() override
Definition: ViewTabBar.cxx:254
virtual css::uno::Reference< css::drawing::framework::XResourceId > SAL_CALL getResourceId() override
Definition: ViewTabBar.cxx:249
rtl::Reference<::sd::DrawController > mxController
Definition: ViewTabBar.hxx:152
css::uno::Reference< css::drawing::framework::XConfigurationController > mxConfigurationController
Definition: ViewTabBar.hxx:153
ViewShellBase * mpViewShellBase
Definition: ViewTabBar.hxx:157
virtual void SAL_CALL appendTabBarButton(const css::drawing::framework::TabBarButton &rButton) override
Definition: ViewTabBar.cxx:223
virtual void disposing(std::unique_lock< std::mutex > &) override
Definition: ViewTabBar.cxx:106
css::uno::Reference< css::drawing::framework::XResourceId > mxViewTabBarId
Definition: ViewTabBar.hxx:156
virtual css::uno::Sequence< css::drawing::framework::TabBarButton > SAL_CALL getTabBarButtons() override
Definition: ViewTabBar.cxx:241
void AddTabBarButton(const css::drawing::framework::TabBarButton &rButton, const css::drawing::framework::TabBarButton &rAnchor)
Definition: ViewTabBar.cxx:339
bool HasTabBarButton(const css::drawing::framework::TabBarButton &rButton)
Definition: ViewTabBar.cxx:401
int mnNoteBookWidthPadding
Definition: ViewTabBar.hxx:158
virtual void SAL_CALL notifyConfigurationChange(const css::drawing::framework::ConfigurationChangeEvent &rEvent) override
Definition: ViewTabBar.cxx:190
void UpdateActiveButton()
Definition: ViewTabBar.cxx:424
void RemoveTabBarButton(const css::drawing::framework::TabBarButton &rButton)
Definition: ViewTabBar.cxx:386
A pane is a wrapper for a window and possibly for a tab bar (for view switching).
Definition: Pane.hxx:51
vcl::Window * GetParent() const
vcl::Window * GetWindow(GetWindowType nType) const
void SetPaintTransparent(bool bTransparent)
void SetBackground()
void append_page(const OUString &rIdent, const OUString &rLabel)
virtual void set_tab_label_text(const OUString &rIdent, const OUString &rLabel)=0
virtual int get_n_pages() const=0
virtual weld::Container * get_page(const OUString &rIdent) const=0
virtual void remove_page(const OUString &rIdent)=0
virtual Size get_pixel_size(const OUString &rText) const=0
virtual void set_size_request(int nWidth, int nHeight)=0
virtual Size get_preferred_size() const=0
#define DBG_UNHANDLED_EXCEPTION(...)
ULONG m_refCount
sal_Int32 nIndex
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
sal_uInt16 ResourceId
void Create(SwFormatVertOrient &rItem, SvStream &rStrm, sal_uInt16 nVersionAbusedAsSize)
IMPL_LINK(SdCharHeightPropertyBox, implMenuSelectHdl, const OUString &, rIdent, void)
unsigned char sal_Bool