Line data Source code
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 : #include "SidebarController.hxx"
20 : #include "Deck.hxx"
21 : #include "DeckTitleBar.hxx"
22 : #include "Panel.hxx"
23 : #include "PanelTitleBar.hxx"
24 : #include "SidebarResource.hxx"
25 : #include "TabBar.hxx"
26 : #include <sfx2/sidebar/Theme.hxx>
27 : #include <sfx2/sidebar/SidebarChildWindow.hxx>
28 : #include <sfx2/sidebar/Tools.hxx>
29 : #include "SidebarDockingWindow.hxx"
30 : #include "Context.hxx"
31 :
32 : #include <sfx2/sfxresid.hxx>
33 : #include <sfx2/sfxsids.hrc>
34 : #include <sfx2/titledockwin.hxx>
35 : #include "sfxlocal.hrc"
36 : #include <vcl/floatwin.hxx>
37 : #include <vcl/fixed.hxx>
38 : #include "splitwin.hxx"
39 : #include <svl/smplhint.hxx>
40 : #include <tools/link.hxx>
41 : #include <toolkit/helper/vclunohelper.hxx>
42 : #include <comphelper/processfactory.hxx>
43 : #include <comphelper/namedvaluecollection.hxx>
44 :
45 : #include <com/sun/star/frame/XDispatchProvider.hpp>
46 : #include <com/sun/star/lang/XInitialization.hpp>
47 : #include <com/sun/star/ui/ContextChangeEventMultiplexer.hpp>
48 : #include <com/sun/star/ui/ContextChangeEventObject.hpp>
49 : #include <com/sun/star/ui/theUIElementFactoryManager.hpp>
50 : #include <com/sun/star/util/XURLTransformer.hpp>
51 : #include <com/sun/star/util/URL.hpp>
52 : #include <com/sun/star/rendering/XSpriteCanvas.hpp>
53 :
54 : #include <boost/bind.hpp>
55 : #include <boost/function.hpp>
56 : #include <boost/scoped_array.hpp>
57 :
58 : using namespace css;
59 : using namespace css::uno;
60 : using ::rtl::OUString;
61 :
62 : namespace
63 : {
64 : const static char gsReadOnlyCommandName[] = ".uno:EditDoc";
65 : const static char gsHideSidebarCommandName[] = ".uno:Sidebar";
66 : const static sal_Int32 gnMaximumSidebarWidth (400);
67 : const static sal_Int32 gnWidthCloseThreshold (70);
68 : const static sal_Int32 gnWidthOpenThreshold (40);
69 : }
70 :
71 : namespace sfx2 { namespace sidebar {
72 :
73 216 : SidebarController::SidebarControllerContainer SidebarController::maSidebarControllerContainer;
74 :
75 : namespace {
76 : enum MenuId
77 : {
78 : MID_UNLOCK_TASK_PANEL = 1,
79 : MID_LOCK_TASK_PANEL,
80 : MID_HIDE_SIDEBAR,
81 : MID_CUSTOMIZATION,
82 : MID_RESTORE_DEFAULT,
83 : MID_FIRST_PANEL,
84 : MID_FIRST_HIDE = 1000
85 : };
86 :
87 : /** When in doubt, show this deck.
88 : */
89 : static const char gsDefaultDeckId[] = "PropertyDeck";
90 : }
91 :
92 3155 : SidebarController::SidebarController (
93 : SidebarDockingWindow* pParentWindow,
94 : const css::uno::Reference<css::frame::XFrame>& rxFrame)
95 : : SidebarControllerInterfaceBase(m_aMutex),
96 : mpCurrentDeck(),
97 : mpParentWindow(pParentWindow),
98 : mpTabBar(VclPtr<TabBar>::Create(
99 : mpParentWindow,
100 : rxFrame,
101 3155 : ::boost::bind(&SidebarController::OpenThenSwitchToDeck, this, _1),
102 3155 : ::boost::bind(&SidebarController::ShowPopupMenu, this, _1,_2))),
103 : mxFrame(rxFrame),
104 : maCurrentContext(OUString(), OUString()),
105 : maRequestedContext(),
106 : mnRequestedForceFlags(SwitchFlag_NoForce),
107 : msCurrentDeckId(gsDefaultDeckId),
108 : msCurrentDeckTitle(),
109 : maPropertyChangeForwarder(::boost::bind(&SidebarController::BroadcastPropertyChange, this)),
110 : maContextChangeUpdate(::boost::bind(&SidebarController::UpdateConfigurations, this)),
111 : maAsynchronousDeckSwitch(),
112 : mbIsDeckRequestedOpen(),
113 : mbIsDeckOpen(),
114 : mbCanDeckBeOpened(true),
115 6310 : mnSavedSidebarWidth(pParentWindow->GetSizePixel().Width()),
116 : maFocusManager(::boost::bind(&SidebarController::ShowPanel, this, _1)),
117 : mxReadOnlyModeDispatch(),
118 : mbIsDocumentReadOnly(false),
119 : mpSplitWindow(NULL),
120 15775 : mnWidthOnSplitterButtonDown(0)
121 : {
122 : // Listen for context change events.
123 : css::uno::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer (
124 : css::ui::ContextChangeEventMultiplexer::get(
125 3155 : ::comphelper::getProcessComponentContext()));
126 3155 : if (xMultiplexer.is())
127 3155 : xMultiplexer->addContextChangeEventListener(
128 : static_cast<css::ui::XContextChangeEventListener*>(this),
129 3155 : mxFrame->getController());
130 :
131 : // Listen for window events.
132 3155 : mpParentWindow->AddEventListener(LINK(this, SidebarController, WindowEventHandler));
133 :
134 : // Listen for theme property changes.
135 6310 : Theme::GetPropertySet()->addPropertyChangeListener(
136 : OUString(""),
137 3155 : static_cast<css::beans::XPropertyChangeListener*>(this));
138 :
139 : // Get the dispatch object as preparation to listen for changes of
140 : // the read-only state.
141 6310 : const util::URL aURL (Tools::GetURL(gsReadOnlyCommandName));
142 3155 : mxReadOnlyModeDispatch = Tools::GetDispatch(mxFrame, aURL);
143 3155 : if (mxReadOnlyModeDispatch.is())
144 3155 : mxReadOnlyModeDispatch->addStatusListener(this, aURL);
145 :
146 3155 : SwitchToDeck(gsDefaultDeckId);
147 :
148 6310 : WeakReference<SidebarController> xWeakController (this);
149 : maSidebarControllerContainer.insert(
150 : SidebarControllerContainer::value_type(
151 : rxFrame,
152 6310 : xWeakController));
153 3155 : }
154 :
155 5626 : SidebarController::~SidebarController()
156 : {
157 5626 : }
158 :
159 0 : SidebarController* SidebarController::GetSidebarControllerForFrame (
160 : const css::uno::Reference<css::frame::XFrame>& rxFrame)
161 : {
162 0 : SidebarControllerContainer::iterator iEntry (maSidebarControllerContainer.find(rxFrame));
163 0 : if (iEntry == maSidebarControllerContainer.end())
164 0 : return NULL;
165 :
166 0 : css::uno::Reference<XInterface> xController (iEntry->second.get());
167 0 : if ( ! xController.is())
168 0 : return NULL;
169 :
170 0 : return dynamic_cast<SidebarController*>(xController.get());
171 : }
172 :
173 3155 : void SAL_CALL SidebarController::disposing()
174 : {
175 3155 : mpCloseIndicator.disposeAndClear();
176 :
177 3155 : SidebarControllerContainer::iterator iEntry (maSidebarControllerContainer.find(mxFrame));
178 3155 : if (iEntry != maSidebarControllerContainer.end())
179 3155 : maSidebarControllerContainer.erase(iEntry);
180 :
181 3155 : maFocusManager.Clear();
182 :
183 : css::uno::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer (
184 : css::ui::ContextChangeEventMultiplexer::get(
185 3155 : ::comphelper::getProcessComponentContext()));
186 3155 : if (xMultiplexer.is())
187 3155 : xMultiplexer->removeAllContextChangeEventListeners(
188 3155 : static_cast<css::ui::XContextChangeEventListener*>(this));
189 :
190 3155 : if (mxReadOnlyModeDispatch.is())
191 3155 : mxReadOnlyModeDispatch->removeStatusListener(this, Tools::GetURL(gsReadOnlyCommandName));
192 3155 : if (mpSplitWindow != nullptr)
193 : {
194 3147 : mpSplitWindow->RemoveEventListener(LINK(this, SidebarController, WindowEventHandler));
195 3147 : mpSplitWindow = NULL;
196 : }
197 :
198 3155 : if (mpParentWindow != nullptr)
199 : {
200 3155 : mpParentWindow->RemoveEventListener(LINK(this, SidebarController, WindowEventHandler));
201 3155 : mpParentWindow = NULL;
202 : }
203 :
204 3155 : if (mpCurrentDeck)
205 : {
206 3155 : mpCurrentDeck.disposeAndClear();
207 : }
208 :
209 3155 : mpTabBar.disposeAndClear();
210 :
211 6310 : Theme::GetPropertySet()->removePropertyChangeListener(
212 : OUString(""),
213 3155 : static_cast<css::beans::XPropertyChangeListener*>(this));
214 :
215 3155 : maContextChangeUpdate.CancelRequest();
216 3155 : maAsynchronousDeckSwitch.CancelRequest();
217 3155 : }
218 :
219 7261 : void SAL_CALL SidebarController::notifyContextChangeEvent (const css::ui::ContextChangeEventObject& rEvent)
220 : throw(css::uno::RuntimeException, std::exception)
221 : {
222 : // Update to the requested new context asynchronously to avoid
223 : // subtle errors caused by SFX2 which in rare cases can not
224 : // properly handle a synchronous update.
225 14522 : maRequestedContext = Context(
226 : rEvent.ApplicationName,
227 7261 : rEvent.ContextName);
228 7261 : if (maRequestedContext != maCurrentContext)
229 : {
230 4095 : maAsynchronousDeckSwitch.CancelRequest();
231 4095 : maContextChangeUpdate.RequestCall();
232 : }
233 7261 : }
234 :
235 4 : void SAL_CALL SidebarController::disposing (const css::lang::EventObject& rEventObject)
236 : throw(css::uno::RuntimeException, std::exception)
237 : {
238 : (void)rEventObject;
239 :
240 4 : dispose();
241 4 : }
242 :
243 0 : void SAL_CALL SidebarController::propertyChange (const css::beans::PropertyChangeEvent& rEvent)
244 : throw(css::uno::RuntimeException, std::exception)
245 : {
246 : (void)rEvent;
247 :
248 0 : maPropertyChangeForwarder.RequestCall();
249 0 : }
250 :
251 3601 : void SAL_CALL SidebarController::statusChanged (const css::frame::FeatureStateEvent& rEvent)
252 : throw(css::uno::RuntimeException, std::exception)
253 : {
254 3601 : bool bIsReadWrite (true);
255 3601 : if (rEvent.IsEnabled)
256 2466 : rEvent.State >>= bIsReadWrite;
257 :
258 3601 : if (mbIsDocumentReadOnly != !bIsReadWrite)
259 : {
260 1 : mbIsDocumentReadOnly = !bIsReadWrite;
261 :
262 : // Force the current deck to update its panel list.
263 1 : if ( ! mbIsDocumentReadOnly)
264 0 : msCurrentDeckId = gsDefaultDeckId;
265 1 : mnRequestedForceFlags |= SwitchFlag_ForceSwitch;
266 1 : maAsynchronousDeckSwitch.CancelRequest();
267 1 : maContextChangeUpdate.RequestCall();
268 : }
269 3601 : }
270 :
271 370 : void SAL_CALL SidebarController::requestLayout()
272 : throw(css::uno::RuntimeException, std::exception)
273 : {
274 370 : sal_Int32 nMinimalWidth = 0;
275 370 : if (mpCurrentDeck)
276 : {
277 370 : mpCurrentDeck->RequestLayout();
278 370 : nMinimalWidth = mpCurrentDeck->GetMinimalWidth();
279 : }
280 370 : RestrictWidth(nMinimalWidth);
281 370 : }
282 :
283 0 : void SidebarController::BroadcastPropertyChange()
284 : {
285 0 : DataChangedEvent aEvent (DataChangedEventType::USER);
286 0 : mpParentWindow->NotifyAllChildren(aEvent);
287 0 : mpParentWindow->Invalidate(InvalidateFlags::Children);
288 0 : }
289 :
290 16012 : void SidebarController::NotifyResize()
291 : {
292 16012 : if (!mpTabBar)
293 : {
294 : OSL_ASSERT(mpTabBar!=nullptr);
295 16012 : return;
296 : }
297 :
298 16012 : vcl::Window* pParentWindow = mpTabBar->GetParent();
299 16012 : sal_Int32 nTabBarDefaultWidth = TabBar::GetDefaultWidth() * mpTabBar->GetDPIScaleFactor();
300 :
301 16012 : const sal_Int32 nWidth (pParentWindow->GetSizePixel().Width());
302 16012 : const sal_Int32 nHeight (pParentWindow->GetSizePixel().Height());
303 :
304 16012 : mbIsDeckOpen = (nWidth > nTabBarDefaultWidth);
305 :
306 16012 : if (mnSavedSidebarWidth <= 0)
307 6309 : mnSavedSidebarWidth = nWidth;
308 :
309 : bool bIsDeckVisible;
310 16012 : if (mbCanDeckBeOpened)
311 : {
312 16012 : const bool bIsOpening (nWidth > mnWidthOnSplitterButtonDown);
313 16012 : if (bIsOpening)
314 12858 : bIsDeckVisible = nWidth >= nTabBarDefaultWidth + gnWidthOpenThreshold;
315 : else
316 3154 : bIsDeckVisible = nWidth >= nTabBarDefaultWidth + gnWidthCloseThreshold;
317 16012 : mbIsDeckRequestedOpen = bIsDeckVisible;
318 16012 : UpdateCloseIndicator(!bIsDeckVisible);
319 : }
320 : else
321 0 : bIsDeckVisible = false;
322 :
323 16012 : if (mpCurrentDeck)
324 : {
325 16012 : SfxSplitWindow* pSplitWindow = GetSplitWindow();
326 16012 : WindowAlign eAlign = pSplitWindow ? pSplitWindow->GetAlign() : WINDOWALIGN_RIGHT;
327 : long nDeckX, nTabX;
328 16012 : if (eAlign == WINDOWALIGN_LEFT) // attach the Sidebar towards the left-side of screen
329 : {
330 0 : nDeckX = nTabBarDefaultWidth;
331 0 : nTabX = 0;
332 : }
333 : else // attach the Sidebar towards the right-side of screen
334 : {
335 16012 : nDeckX = 0;
336 16012 : nTabX = nWidth-nTabBarDefaultWidth;
337 : }
338 :
339 : // Place the deck first.
340 16012 : if (bIsDeckVisible)
341 : {
342 2107 : mpCurrentDeck->setPosSizePixel(nDeckX, 0, nWidth - nTabBarDefaultWidth, nHeight);
343 2107 : mpCurrentDeck->Show();
344 2107 : mpCurrentDeck->RequestLayout();
345 : }
346 : else
347 13905 : mpCurrentDeck->Hide();
348 :
349 : // Now place the tab bar.
350 16012 : mpTabBar->setPosSizePixel(nTabX, 0, nTabBarDefaultWidth, nHeight);
351 16012 : mpTabBar->Show();
352 :
353 : }
354 :
355 : // Determine if the closer of the deck can be shown.
356 16012 : sal_Int32 nMinimalWidth = 0;
357 16012 : if (mpCurrentDeck)
358 : {
359 16012 : DeckTitleBar* pTitleBar = mpCurrentDeck->GetTitleBar();
360 16012 : if (pTitleBar != NULL && pTitleBar->IsVisible())
361 3609 : pTitleBar->SetCloserVisible(CanModifyChildWindowWidth());
362 16012 : nMinimalWidth = mpCurrentDeck->GetMinimalWidth();
363 : }
364 :
365 16012 : RestrictWidth(nMinimalWidth);
366 : }
367 :
368 0 : void SidebarController::ProcessNewWidth (const sal_Int32 nNewWidth)
369 : {
370 0 : if ( ! mbIsDeckRequestedOpen)
371 0 : return;
372 :
373 0 : if (mbIsDeckRequestedOpen.get())
374 : {
375 : // Deck became large enough to be shown. Show it.
376 0 : mnSavedSidebarWidth = nNewWidth;
377 0 : RequestOpenDeck();
378 : }
379 : else
380 : {
381 : // Deck became too small. Close it completely.
382 : // If window is wider than the tab bar then mark the deck as being visible, even when it its not.
383 : // This is to trigger an adjustment of the width to the width of the tab bar.
384 0 : mbIsDeckOpen = true;
385 0 : RequestCloseDeck();
386 :
387 0 : if (mnWidthOnSplitterButtonDown > TabBar::GetDefaultWidth() * mpTabBar->GetDPIScaleFactor())
388 0 : mnSavedSidebarWidth = mnWidthOnSplitterButtonDown;
389 : }
390 : }
391 :
392 612 : void SidebarController::UpdateConfigurations()
393 : {
394 1224 : if (maCurrentContext != maRequestedContext
395 612 : || mnRequestedForceFlags!=SwitchFlag_NoForce)
396 : {
397 610 : maCurrentContext = maRequestedContext;
398 :
399 : // Find the set of decks that could be displayed for the new context.
400 610 : ResourceManager::DeckContextDescriptorContainer aDecks;
401 610 : ResourceManager::Instance().GetMatchingDecks (
402 : aDecks,
403 : maCurrentContext,
404 : mbIsDocumentReadOnly,
405 1220 : mxFrame);
406 :
407 : // Notify the tab bar about the updated set of decks.
408 610 : mpTabBar->SetDecks(aDecks);
409 :
410 : // Find the new deck. By default that is the same as the old
411 : // one. If that is not set or not enabled, then choose the
412 : // first enabled deck (which is PropertyDeck).
413 1220 : OUString sNewDeckId;
414 621 : for (ResourceManager::DeckContextDescriptorContainer::const_iterator
415 610 : iDeck(aDecks.begin()),
416 610 : iEnd(aDecks.end());
417 : iDeck!=iEnd;
418 : ++iDeck)
419 : {
420 620 : if (iDeck->mbIsEnabled)
421 : {
422 610 : if (iDeck->msId.equals(msCurrentDeckId))
423 : {
424 609 : sNewDeckId = msCurrentDeckId;
425 609 : break;
426 : }
427 1 : else if (sNewDeckId.getLength() == 0)
428 1 : sNewDeckId = iDeck->msId;
429 : }
430 : }
431 :
432 610 : if (sNewDeckId.getLength() == 0)
433 : {
434 : // We did not find a valid deck.
435 0 : RequestCloseDeck();
436 612 : return;
437 : }
438 :
439 : // Tell the tab bar to highlight the button associated
440 : // with the deck.
441 610 : mpTabBar->HighlightDeck(sNewDeckId);
442 :
443 : const DeckDescriptor* pDescriptor =
444 610 : ResourceManager::Instance().GetDeckDescriptor(sNewDeckId);
445 :
446 610 : if (pDescriptor)
447 : {
448 : SwitchToDeck(
449 : *pDescriptor,
450 610 : maCurrentContext);
451 610 : }
452 : }
453 : }
454 :
455 0 : void SidebarController::OpenThenSwitchToDeck (
456 : const ::rtl::OUString& rsDeckId)
457 : {
458 : // fdo#67627 Clicking a second time on a Deck icon will close the Deck
459 0 : if (IsDeckVisible(rsDeckId))
460 : {
461 : // fdo#88241 Summoning an undocked sidebar a second time should close sidebar
462 0 : if (!GetSplitWindow())
463 : {
464 0 : mpParentWindow->Close();
465 0 : return;
466 : }
467 : else
468 : {
469 0 : RequestCloseDeck();
470 0 : return;
471 : }
472 : }
473 0 : RequestOpenDeck();
474 0 : SwitchToDeck(rsDeckId);
475 0 : mpTabBar->Invalidate();
476 0 : mpTabBar->HighlightDeck(rsDeckId);
477 : }
478 :
479 3155 : void SidebarController::SwitchToDeck (
480 : const ::rtl::OUString& rsDeckId)
481 : {
482 6310 : if ( ! msCurrentDeckId.equals(rsDeckId)
483 3155 : || ! mbIsDeckOpen
484 3155 : || mnRequestedForceFlags!=SwitchFlag_NoForce)
485 : {
486 3155 : const DeckDescriptor* pDeckDescriptor = ResourceManager::Instance().GetDeckDescriptor(rsDeckId);
487 3155 : if (pDeckDescriptor != NULL)
488 3155 : SwitchToDeck(*pDeckDescriptor, maCurrentContext);
489 : }
490 3155 : }
491 :
492 6969 : void SidebarController::SwitchToDeck (
493 : const DeckDescriptor& rDeckDescriptor,
494 : const Context& rContext)
495 : {
496 6969 : maFocusManager.Clear();
497 :
498 6969 : const bool bForceNewDeck ((mnRequestedForceFlags&SwitchFlag_ForceNewDeck)!=0);
499 6969 : const bool bForceNewPanels ((mnRequestedForceFlags&SwitchFlag_ForceNewPanels)!=0);
500 :
501 13938 : if ( ! msCurrentDeckId.equals(rDeckDescriptor.msId)
502 6969 : || bForceNewDeck)
503 : {
504 : // When the deck changes then destroy the deck and all panels
505 : // and create everything new.
506 1 : mpCurrentDeck.disposeAndClear();
507 :
508 1 : msCurrentDeckId = rDeckDescriptor.msId;
509 : }
510 6969 : mpTabBar->HighlightDeck(msCurrentDeckId);
511 :
512 : // Determine the panels to display in the deck.
513 6969 : ResourceManager::PanelContextDescriptorContainer aPanelContextDescriptors;
514 6969 : ResourceManager::Instance().GetMatchingPanels(
515 : aPanelContextDescriptors,
516 : rContext,
517 : rDeckDescriptor.msId,
518 13938 : mxFrame);
519 :
520 6969 : if (aPanelContextDescriptors.empty())
521 : {
522 : // There are no panels to be displayed in the current context.
523 3204 : if (EnumContext::GetContextEnum(rContext.msContext) != EnumContext::Context_Empty)
524 : {
525 : // Switch to the "empty" context and try again.
526 : SwitchToDeck(
527 : rDeckDescriptor,
528 : Context(
529 : rContext.msApplication,
530 3204 : EnumContext::GetContextName(EnumContext::Context_Empty)));
531 3204 : return;
532 : }
533 : else
534 : {
535 : // This is already the "empty" context. Looks like we have
536 : // to live with an empty deck.
537 : }
538 : }
539 :
540 : // Provide a configuration and Deck object.
541 3765 : if ( ! mpCurrentDeck)
542 : {
543 : mpCurrentDeck.reset(
544 : VclPtr<Deck>::Create(
545 : rDeckDescriptor,
546 : mpParentWindow,
547 3156 : ::boost::bind(&SidebarController::RequestCloseDeck, this)));
548 3156 : msCurrentDeckTitle = rDeckDescriptor.msTitle;
549 :
550 : }
551 3765 : if ( ! mpCurrentDeck)
552 0 : return;
553 :
554 : #ifdef DEBUG
555 : // Show the context name in the deck title bar.
556 : DeckTitleBar* pDebugTitleBar = mpCurrentDeck->GetTitleBar();
557 : if (pDebugTitleBar != NULL)
558 : pDebugTitleBar->SetTitle(rDeckDescriptor.msTitle + " (" + maCurrentContext.msContext + ")");
559 : #endif
560 :
561 : // Update the panel list.
562 3765 : const sal_Int32 nNewPanelCount (aPanelContextDescriptors.size());
563 7530 : SharedPanelContainer aNewPanels;
564 3765 : const SharedPanelContainer& rCurrentPanels (mpCurrentDeck->GetPanels());
565 :
566 3765 : aNewPanels.resize(nNewPanelCount);
567 3765 : sal_Int32 nWriteIndex (0);
568 3765 : bool bHasPanelSetChanged (false);
569 8818 : for (sal_Int32 nReadIndex=0; nReadIndex<nNewPanelCount; ++nReadIndex)
570 : {
571 : const ResourceManager::PanelContextDescriptor& rPanelContexDescriptor (
572 5053 : aPanelContextDescriptors[nReadIndex]);
573 :
574 : // Determine if the panel can be displayed.
575 5053 : const bool bIsPanelVisible (!mbIsDocumentReadOnly || rPanelContexDescriptor.mbShowForReadOnlyDocuments);
576 5053 : if ( ! bIsPanelVisible)
577 1 : continue;
578 :
579 : // Find the corresponding panel among the currently active
580 : // panels.
581 5052 : SharedPanelContainer::const_iterator iPanel = rCurrentPanels.end();
582 :
583 5052 : if (!bForceNewPanels)
584 : {
585 5052 : iPanel = rCurrentPanels.end();
586 6885 : for (auto a = rCurrentPanels.begin(); a != rCurrentPanels.end(); ++a)
587 : {
588 1958 : if ((*a)->HasIdPredicate(rPanelContexDescriptor.msId))
589 : {
590 125 : iPanel = a;
591 125 : break;
592 : }
593 : }
594 : }
595 5052 : if (iPanel != rCurrentPanels.end())
596 : {
597 : // Panel already exists in current deck. Reuse it.
598 125 : aNewPanels[nWriteIndex] = *iPanel;
599 125 : aNewPanels[nWriteIndex]->SetExpanded(rPanelContexDescriptor.mbIsInitiallyVisible);
600 : }
601 : else
602 : {
603 : // Panel does not yet exist or creation of new panels is forced.
604 : // Create it.
605 9854 : aNewPanels[nWriteIndex] = CreatePanel(
606 : rPanelContexDescriptor.msId,
607 : mpCurrentDeck->GetPanelParentWindow(),
608 : rPanelContexDescriptor.mbIsInitiallyVisible,
609 4927 : rContext);
610 4927 : bHasPanelSetChanged = true;
611 : }
612 5052 : if (aNewPanels[nWriteIndex] != nullptr)
613 : {
614 : // Depending on the context we have to change the command
615 : // for the "more options" dialog.
616 4373 : PanelTitleBar* pTitleBar = aNewPanels[nWriteIndex]->GetTitleBar();
617 4373 : if (pTitleBar != NULL)
618 : {
619 : pTitleBar->SetMoreOptionsCommand(
620 : rPanelContexDescriptor.msMenuCommand,
621 4373 : mxFrame);
622 : }
623 :
624 4373 : ++nWriteIndex;
625 : }
626 :
627 : }
628 : // mpCurrentPanels - may miss stuff (?)
629 3765 : aNewPanels.resize(nWriteIndex);
630 :
631 3765 : SfxSplitWindow* pSplitWindow = GetSplitWindow();
632 3765 : sal_Int32 nTabBarDefaultWidth = TabBar::GetDefaultWidth() * mpTabBar->GetDPIScaleFactor();
633 3765 : WindowAlign eAlign = pSplitWindow ? pSplitWindow->GetAlign() : WINDOWALIGN_RIGHT;
634 : long nDeckX;
635 3765 : if (eAlign == WINDOWALIGN_LEFT) // attach the Sidebar towards the left-side of screen
636 : {
637 0 : nDeckX = nTabBarDefaultWidth;
638 : }
639 : else // attach the Sidebar towards the right-side of screen
640 : {
641 3765 : nDeckX = 0;
642 : }
643 :
644 : // Activate the deck and the new set of panels.
645 3765 : mpCurrentDeck->setPosSizePixel(
646 : nDeckX,
647 : 0,
648 7530 : mpParentWindow->GetSizePixel().Width() - nTabBarDefaultWidth,
649 11295 : mpParentWindow->GetSizePixel().Height());
650 :
651 3765 : mpCurrentDeck->ResetPanels(aNewPanels);
652 3765 : mpCurrentDeck->Show();
653 :
654 3765 : mpParentWindow->SetText(rDeckDescriptor.msTitle);
655 :
656 3765 : if (bHasPanelSetChanged)
657 3693 : NotifyResize();
658 :
659 : // Tell the focus manager about the new panels and tab bar
660 : // buttons.
661 3765 : maFocusManager.SetDeckTitle(mpCurrentDeck->GetTitleBar());
662 3765 : maFocusManager.SetPanels(aNewPanels);
663 3765 : mpTabBar->UpdateFocusManager(maFocusManager);
664 7530 : UpdateTitleBarIcons();
665 : }
666 :
667 4927 : VclPtr<Panel> SidebarController::CreatePanel (
668 : const OUString& rsPanelId,
669 : vcl::Window* pParentWindow,
670 : const bool bIsInitiallyExpanded,
671 : const Context& rContext)
672 : {
673 4927 : const PanelDescriptor* pPanelDescriptor = ResourceManager::Instance().GetPanelDescriptor(rsPanelId);
674 4927 : if (pPanelDescriptor == NULL)
675 0 : return NULL;
676 :
677 : // Create the panel which is the parent window of the UIElement.
678 : VclPtr<Panel> pPanel = VclPtr<Panel>::Create(
679 : *pPanelDescriptor,
680 : pParentWindow,
681 : bIsInitiallyExpanded,
682 4927 : ::boost::bind(&Deck::RequestLayout, mpCurrentDeck.get()),
683 9854 : ::boost::bind(&SidebarController::GetCurrentContext, this));
684 :
685 : // Create the XUIElement.
686 : Reference<ui::XUIElement> xUIElement (CreateUIElement(
687 9854 : pPanel->GetComponentInterface(),
688 : pPanelDescriptor->msImplementationURL,
689 : pPanelDescriptor->mbWantsCanvas,
690 19708 : rContext));
691 4927 : if (xUIElement.is())
692 : {
693 : // Initialize the panel and add it to the active deck.
694 4248 : pPanel->SetUIElement(xUIElement);
695 : }
696 : else
697 : {
698 679 : pPanel.disposeAndClear();
699 : }
700 :
701 9854 : return pPanel;
702 : }
703 :
704 4927 : Reference<ui::XUIElement> SidebarController::CreateUIElement (
705 : const Reference<awt::XWindowPeer>& rxWindow,
706 : const ::rtl::OUString& rsImplementationURL,
707 : const bool bWantsCanvas,
708 : const Context& rContext)
709 : {
710 : try
711 : {
712 4927 : const Reference<XComponentContext> xComponentContext (::comphelper::getProcessComponentContext() );
713 : const Reference<ui::XUIElementFactory> xUIElementFactory =
714 9854 : ui::theUIElementFactoryManager::get( xComponentContext );
715 :
716 : // Create the XUIElement.
717 9854 : ::comphelper::NamedValueCollection aCreationArguments;
718 4927 : aCreationArguments.put("Frame", makeAny(mxFrame));
719 4927 : aCreationArguments.put("ParentWindow", makeAny(rxWindow));
720 4927 : SfxDockingWindow* pSfxDockingWindow = dynamic_cast<SfxDockingWindow*>(mpParentWindow.get());
721 4927 : if (pSfxDockingWindow != NULL)
722 4927 : aCreationArguments.put("SfxBindings", makeAny(sal_uInt64(&pSfxDockingWindow->GetBindings())));
723 4927 : aCreationArguments.put("Theme", Theme::GetPropertySet());
724 4927 : aCreationArguments.put("Sidebar", makeAny(Reference<ui::XSidebar>(static_cast<ui::XSidebar*>(this))));
725 4927 : if (bWantsCanvas)
726 : {
727 0 : Reference<rendering::XSpriteCanvas> xCanvas (VCLUnoHelper::GetWindow(rxWindow)->GetSpriteCanvas());
728 0 : aCreationArguments.put("Canvas", makeAny(xCanvas));
729 : }
730 4927 : aCreationArguments.put("ApplicationName", makeAny(rContext.msApplication));
731 4927 : aCreationArguments.put("ContextName", makeAny(rContext.msContext));
732 :
733 : Reference<ui::XUIElement> xUIElement(
734 4927 : xUIElementFactory->createUIElement(
735 : rsImplementationURL,
736 4927 : Sequence<beans::PropertyValue>(aCreationArguments.getPropertyValues())),
737 9175 : UNO_QUERY_THROW);
738 :
739 9175 : return xUIElement;
740 : }
741 679 : catch(const Exception& rException)
742 : {
743 : SAL_WARN("sfx.sidebar", "Cannot create panel: " << rException.Message);
744 679 : return NULL;
745 : }
746 : }
747 :
748 91790 : IMPL_LINK(SidebarController, WindowEventHandler, VclWindowEvent*, pEvent)
749 : {
750 45895 : if (pEvent==NULL)
751 0 : return sal_IntPtr(false);
752 :
753 45895 : if (pEvent->GetWindow() == mpParentWindow)
754 : {
755 32598 : switch (pEvent->GetId())
756 : {
757 : case VCLEVENT_WINDOW_SHOW:
758 : case VCLEVENT_WINDOW_RESIZE:
759 12319 : NotifyResize();
760 12319 : break;
761 :
762 : case VCLEVENT_WINDOW_DATACHANGED:
763 : // Force an update of deck and tab bar to reflect
764 : // changes in theme (high contrast mode).
765 3 : Theme::HandleDataChange();
766 3 : UpdateTitleBarIcons();
767 3 : mpParentWindow->Invalidate();
768 3 : mnRequestedForceFlags |= SwitchFlag_ForceNewDeck | SwitchFlag_ForceNewPanels;
769 3 : maAsynchronousDeckSwitch.CancelRequest();
770 3 : maContextChangeUpdate.RequestCall();
771 3 : break;
772 :
773 : case SFX_HINT_DYING:
774 0 : dispose();
775 0 : break;
776 :
777 : case VCLEVENT_WINDOW_PAINT:
778 : OSL_TRACE("Paint");
779 0 : break;
780 :
781 : default:
782 20276 : break;
783 : }
784 : }
785 13297 : else if (pEvent->GetWindow()==mpSplitWindow && mpSplitWindow!=nullptr)
786 : {
787 13297 : switch (pEvent->GetId())
788 : {
789 : case VCLEVENT_WINDOW_MOUSEBUTTONDOWN:
790 0 : mnWidthOnSplitterButtonDown = mpParentWindow->GetSizePixel().Width();
791 0 : break;
792 :
793 : case VCLEVENT_WINDOW_MOUSEBUTTONUP:
794 : {
795 0 : ProcessNewWidth(mpParentWindow->GetSizePixel().Width());
796 0 : mnWidthOnSplitterButtonDown = 0;
797 0 : break;
798 : }
799 :
800 : case SFX_HINT_DYING:
801 0 : dispose();
802 0 : break;
803 : }
804 : }
805 :
806 45895 : return sal_IntPtr(true);
807 : }
808 :
809 0 : void SidebarController::ShowPopupMenu (
810 : const Rectangle& rButtonBox,
811 : const ::std::vector<TabBar::DeckMenuData>& rMenuData) const
812 : {
813 0 : ::boost::shared_ptr<PopupMenu> pMenu = CreatePopupMenu(rMenuData);
814 0 : pMenu->SetSelectHdl(LINK(const_cast<SidebarController*>(this), SidebarController, OnMenuItemSelected));
815 :
816 : // pass toolbox button rect so the menu can stay open on button up
817 0 : Rectangle aBox (rButtonBox);
818 0 : aBox.Move(mpTabBar->GetPosPixel().X(), 0);
819 0 : pMenu->Execute(mpParentWindow, aBox, PopupMenuFlags::ExecuteDown);
820 0 : }
821 :
822 0 : ::boost::shared_ptr<PopupMenu> SidebarController::CreatePopupMenu (
823 : const ::std::vector<TabBar::DeckMenuData>& rMenuData) const
824 : {
825 : // Create the top level popup menu.
826 0 : ::boost::shared_ptr<PopupMenu> pMenu (new PopupMenu());
827 0 : FloatingWindow* pMenuWindow = dynamic_cast<FloatingWindow*>(pMenu->GetWindow());
828 0 : if (pMenuWindow != NULL)
829 : {
830 0 : pMenuWindow->SetPopupModeFlags(pMenuWindow->GetPopupModeFlags() | FloatWinPopupFlags::NoMouseUpClose);
831 : }
832 :
833 : // Create sub menu for customization (hiding of deck tabs.)
834 0 : PopupMenu* pCustomizationMenu = new PopupMenu();
835 :
836 0 : SidebarResource aLocalResource;
837 :
838 : // Add one entry for every tool panel element to individually make
839 : // them visible or hide them.
840 0 : sal_Int32 nIndex (0);
841 0 : for(::std::vector<TabBar::DeckMenuData>::const_iterator
842 0 : iItem(rMenuData.begin()),
843 0 : iEnd(rMenuData.end());
844 : iItem!=iEnd;
845 : ++iItem,++nIndex)
846 : {
847 0 : const sal_Int32 nMenuIndex (nIndex+MID_FIRST_PANEL);
848 0 : pMenu->InsertItem(nMenuIndex, iItem->msDisplayName, MenuItemBits::RADIOCHECK);
849 0 : pMenu->CheckItem(nMenuIndex, iItem->mbIsCurrentDeck);
850 0 : pMenu->EnableItem(nMenuIndex, iItem->mbIsEnabled&&iItem->mbIsActive);
851 :
852 0 : const sal_Int32 nSubMenuIndex (nIndex+MID_FIRST_HIDE);
853 0 : if (iItem->mbIsCurrentDeck)
854 : {
855 : // Don't allow the currently visible deck to be disabled.
856 0 : pCustomizationMenu->InsertItem(nSubMenuIndex, iItem->msDisplayName, MenuItemBits::RADIOCHECK);
857 0 : pCustomizationMenu->CheckItem(nSubMenuIndex, true);
858 : }
859 : else
860 : {
861 0 : pCustomizationMenu->InsertItem(nSubMenuIndex, iItem->msDisplayName, MenuItemBits::CHECKABLE);
862 0 : pCustomizationMenu->CheckItem(nSubMenuIndex, iItem->mbIsActive);
863 : }
864 : }
865 :
866 0 : pMenu->InsertSeparator();
867 :
868 : // Add entry for docking or un-docking the tool panel.
869 0 : if (mpParentWindow->IsFloatingMode())
870 0 : pMenu->InsertItem(MID_LOCK_TASK_PANEL, SFX2_RESSTR(STR_SFX_DOCK));
871 : else
872 0 : pMenu->InsertItem(MID_UNLOCK_TASK_PANEL, SFX2_RESSTR(STR_SFX_UNDOCK));
873 :
874 0 : pMenu->InsertItem(MID_HIDE_SIDEBAR, SFX2_RESSTR(STRING_HIDE_SIDEBAR));
875 0 : pCustomizationMenu->InsertSeparator();
876 0 : pCustomizationMenu->InsertItem(MID_RESTORE_DEFAULT, SFX2_RESSTR(STRING_RESTORE));
877 :
878 0 : pMenu->InsertItem(MID_CUSTOMIZATION, SFX2_RESSTR(STRING_CUSTOMIZATION));
879 0 : pMenu->SetPopupMenu(MID_CUSTOMIZATION, pCustomizationMenu);
880 :
881 0 : pMenu->RemoveDisabledEntries(false, false);
882 :
883 0 : return pMenu;
884 : }
885 :
886 0 : IMPL_LINK(SidebarController, OnMenuItemSelected, Menu*, pMenu)
887 : {
888 0 : if (pMenu == NULL)
889 : {
890 : OSL_ENSURE(pMenu!=NULL, "sfx2::sidebar::SidebarController::OnMenuItemSelected: illegal menu!");
891 0 : return 0;
892 : }
893 :
894 0 : pMenu->Deactivate();
895 0 : const sal_Int32 nIndex (pMenu->GetCurItemId());
896 0 : switch (nIndex)
897 : {
898 : case MID_UNLOCK_TASK_PANEL:
899 0 : mpParentWindow->SetFloatingMode(true);
900 0 : break;
901 :
902 : case MID_LOCK_TASK_PANEL:
903 0 : mpParentWindow->SetFloatingMode(false);
904 0 : break;
905 :
906 : case MID_RESTORE_DEFAULT:
907 0 : mpTabBar->RestoreHideFlags();
908 0 : break;
909 :
910 : case MID_HIDE_SIDEBAR:
911 : {
912 0 : const util::URL aURL (Tools::GetURL(gsHideSidebarCommandName));
913 0 : Reference<frame::XDispatch> mxDispatch (Tools::GetDispatch(mxFrame, aURL));
914 0 : if (mxDispatch.is())
915 0 : mxDispatch->dispatch(aURL, Sequence<beans::PropertyValue>());
916 0 : break;
917 : }
918 : default:
919 : {
920 : try
921 : {
922 0 : if (nIndex >= MID_FIRST_PANEL && nIndex<MID_FIRST_HIDE)
923 : {
924 0 : RequestOpenDeck();
925 0 : SwitchToDeck(mpTabBar->GetDeckIdForIndex(nIndex - MID_FIRST_PANEL));
926 : }
927 0 : else if (nIndex >=MID_FIRST_HIDE)
928 0 : if (pMenu->GetItemBits(nIndex) == MenuItemBits::CHECKABLE)
929 0 : mpTabBar->ToggleHideFlag(nIndex-MID_FIRST_HIDE);
930 : }
931 0 : catch (RuntimeException&)
932 : {
933 : }
934 : }
935 0 : break;
936 : }
937 :
938 0 : return 1;
939 : }
940 :
941 0 : void SidebarController::RequestCloseDeck()
942 : {
943 0 : mbIsDeckRequestedOpen = false;
944 0 : UpdateDeckOpenState();
945 :
946 : // remove highlight from TabBar, because Deck will be closed
947 0 : mpTabBar->RemoveDeckHighlight();
948 0 : }
949 :
950 0 : void SidebarController::RequestOpenDeck()
951 : {
952 0 : mbIsDeckRequestedOpen = true;
953 0 : UpdateDeckOpenState();
954 0 : }
955 :
956 0 : bool SidebarController::IsDeckVisible(const OUString& rsDeckId)
957 : {
958 0 : return mbIsDeckOpen && mbIsDeckOpen.get() && msCurrentDeckId == rsDeckId;
959 : }
960 :
961 0 : void SidebarController::UpdateDeckOpenState()
962 : {
963 0 : if ( ! mbIsDeckRequestedOpen)
964 : // No state requested.
965 0 : return;
966 :
967 0 : sal_Int32 nTabBarDefaultWidth = TabBar::GetDefaultWidth() * mpTabBar->GetDPIScaleFactor();
968 :
969 : // Update (change) the open state when it either has not yet been initialized
970 : // or when its value differs from the requested state.
971 0 : if ( ! mbIsDeckOpen
972 0 : || mbIsDeckOpen.get() != mbIsDeckRequestedOpen.get())
973 : {
974 0 : if (mbIsDeckRequestedOpen.get())
975 : {
976 0 : if (mnSavedSidebarWidth <= nTabBarDefaultWidth)
977 0 : SetChildWindowWidth(SidebarChildWindow::GetDefaultWidth(mpParentWindow));
978 : else
979 0 : SetChildWindowWidth(mnSavedSidebarWidth);
980 : }
981 : else
982 : {
983 0 : if ( ! mpParentWindow->IsFloatingMode())
984 0 : mnSavedSidebarWidth = SetChildWindowWidth(nTabBarDefaultWidth);
985 0 : if (mnWidthOnSplitterButtonDown > nTabBarDefaultWidth)
986 0 : mnSavedSidebarWidth = mnWidthOnSplitterButtonDown;
987 0 : mpParentWindow->SetStyle(mpParentWindow->GetStyle() & ~WB_SIZEABLE);
988 : }
989 :
990 0 : mbIsDeckOpen = mbIsDeckRequestedOpen.get();
991 0 : if (mbIsDeckOpen.get() && mpCurrentDeck)
992 0 : mpCurrentDeck->Show(mbIsDeckOpen.get());
993 0 : NotifyResize();
994 : }
995 : }
996 :
997 3609 : bool SidebarController::CanModifyChildWindowWidth()
998 : {
999 3609 : SfxSplitWindow* pSplitWindow = GetSplitWindow();
1000 3609 : if (pSplitWindow == NULL)
1001 0 : return false;
1002 :
1003 3609 : sal_uInt16 nRow (0xffff);
1004 3609 : sal_uInt16 nColumn (0xffff);
1005 3609 : if (pSplitWindow->GetWindowPos(mpParentWindow, nColumn, nRow))
1006 : {
1007 3609 : sal_uInt16 nRowCount (pSplitWindow->GetWindowCount(nColumn));
1008 3609 : return nRowCount==1;
1009 : }
1010 : else
1011 0 : return false;
1012 : }
1013 :
1014 0 : sal_Int32 SidebarController::SetChildWindowWidth (const sal_Int32 nNewWidth)
1015 : {
1016 0 : SfxSplitWindow* pSplitWindow = GetSplitWindow();
1017 0 : if (pSplitWindow == NULL)
1018 0 : return 0;
1019 :
1020 0 : sal_uInt16 nRow (0xffff);
1021 0 : sal_uInt16 nColumn (0xffff);
1022 0 : pSplitWindow->GetWindowPos(mpParentWindow, nColumn, nRow);
1023 0 : const long nColumnWidth (pSplitWindow->GetLineSize(nColumn));
1024 :
1025 0 : vcl::Window* pWindow = mpParentWindow;
1026 0 : const Size aWindowSize (pWindow->GetSizePixel());
1027 :
1028 : pSplitWindow->MoveWindow(
1029 : mpParentWindow,
1030 : Size(nNewWidth, aWindowSize.Height()),
1031 : nColumn,
1032 0 : nRow);
1033 0 : static_cast<SplitWindow*>(pSplitWindow)->Split();
1034 :
1035 0 : return static_cast<sal_Int32>(nColumnWidth);
1036 : }
1037 :
1038 16382 : void SidebarController::RestrictWidth (sal_Int32 nWidth)
1039 : {
1040 16382 : SfxSplitWindow* pSplitWindow = GetSplitWindow();
1041 16382 : if (pSplitWindow != NULL)
1042 : {
1043 13228 : const sal_uInt16 nId (pSplitWindow->GetItemId(mpParentWindow.get()));
1044 13228 : const sal_uInt16 nSetId (pSplitWindow->GetSet(nId));
1045 : pSplitWindow->SetItemSizeRange(
1046 : nSetId,
1047 13228 : Range(TabBar::GetDefaultWidth() * mpTabBar->GetDPIScaleFactor() + nWidth,
1048 26456 : gnMaximumSidebarWidth * mpTabBar->GetDPIScaleFactor()));
1049 : }
1050 16382 : }
1051 :
1052 39768 : SfxSplitWindow* SidebarController::GetSplitWindow()
1053 : {
1054 39768 : if (mpParentWindow != nullptr)
1055 : {
1056 39768 : SfxSplitWindow* pSplitWindow = dynamic_cast<SfxSplitWindow*>(mpParentWindow->GetParent());
1057 39768 : if (pSplitWindow != mpSplitWindow)
1058 : {
1059 3163 : if (mpSplitWindow != nullptr)
1060 8 : mpSplitWindow->RemoveEventListener(LINK(this, SidebarController, WindowEventHandler));
1061 :
1062 3163 : mpSplitWindow = pSplitWindow;
1063 :
1064 3163 : if (mpSplitWindow != nullptr)
1065 3155 : mpSplitWindow->AddEventListener(LINK(this, SidebarController, WindowEventHandler));
1066 : }
1067 39768 : return mpSplitWindow;
1068 : }
1069 : else
1070 0 : return NULL;
1071 : }
1072 :
1073 16012 : void SidebarController::UpdateCloseIndicator (const bool bCloseAfterDrag)
1074 : {
1075 16012 : if (mpParentWindow == nullptr)
1076 16012 : return;
1077 :
1078 16012 : if (bCloseAfterDrag)
1079 : {
1080 : // Make sure that the indicator exists.
1081 13905 : if ( ! mpCloseIndicator)
1082 : {
1083 3155 : mpCloseIndicator.reset(VclPtr<FixedImage>::Create(mpParentWindow));
1084 3155 : FixedImage* pFixedImage = static_cast<FixedImage*>(mpCloseIndicator.get());
1085 3155 : const Image aImage (Theme::GetImage(Theme::Image_CloseIndicator));
1086 3155 : pFixedImage->SetImage(aImage);
1087 3155 : pFixedImage->SetSizePixel(aImage.GetSizePixel());
1088 3155 : pFixedImage->SetBackground(Theme::GetWallpaper(Theme::Paint_DeckBackground));
1089 : }
1090 :
1091 : // Place and show the indicator.
1092 13905 : const Size aWindowSize (mpParentWindow->GetSizePixel());
1093 13905 : const Size aImageSize (mpCloseIndicator->GetSizePixel());
1094 13905 : mpCloseIndicator->SetPosPixel(
1095 : Point(
1096 13905 : aWindowSize.Width() - TabBar::GetDefaultWidth() * mpTabBar->GetDPIScaleFactor() - aImageSize.Width(),
1097 27810 : (aWindowSize.Height() - aImageSize.Height())/2));
1098 13905 : mpCloseIndicator->Show();
1099 : }
1100 : else
1101 : {
1102 : // Hide but don't delete the indicator.
1103 2107 : if (mpCloseIndicator)
1104 2107 : mpCloseIndicator->Hide();
1105 : }
1106 : }
1107 :
1108 3768 : void SidebarController::UpdateTitleBarIcons()
1109 : {
1110 3768 : if ( ! mpCurrentDeck)
1111 3768 : return;
1112 :
1113 3768 : const bool bIsHighContrastModeActive (Theme::IsHighContrastMode());
1114 3768 : const ResourceManager& rResourceManager (ResourceManager::Instance());
1115 :
1116 : // Update the deck icon.
1117 3768 : const DeckDescriptor* pDeckDescriptor = rResourceManager.GetDeckDescriptor(mpCurrentDeck->GetId());
1118 3768 : if (pDeckDescriptor != NULL && mpCurrentDeck->GetTitleBar())
1119 : {
1120 : const OUString sIconURL(
1121 : bIsHighContrastModeActive
1122 : ? pDeckDescriptor->msHighContrastTitleBarIconURL
1123 3768 : : pDeckDescriptor->msTitleBarIconURL);
1124 3768 : mpCurrentDeck->GetTitleBar()->SetIcon(Tools::GetImage(sIconURL, mxFrame));
1125 : }
1126 :
1127 : // Update the panel icons.
1128 3768 : const SharedPanelContainer& rPanels (mpCurrentDeck->GetPanels());
1129 8141 : for (SharedPanelContainer::const_iterator
1130 3768 : iPanel(rPanels.begin()), iEnd(rPanels.end());
1131 : iPanel!=iEnd;
1132 : ++iPanel)
1133 : {
1134 4373 : if ( ! *iPanel)
1135 0 : continue;
1136 4373 : if ((*iPanel)->GetTitleBar() == NULL)
1137 0 : continue;
1138 4373 : const PanelDescriptor* pPanelDescriptor = rResourceManager.GetPanelDescriptor((*iPanel)->GetId());
1139 4373 : if (pPanelDescriptor == NULL)
1140 0 : continue;
1141 : const OUString sIconURL (
1142 : bIsHighContrastModeActive
1143 : ? pPanelDescriptor->msHighContrastTitleBarIconURL
1144 4373 : : pPanelDescriptor->msTitleBarIconURL);
1145 4373 : (*iPanel)->GetTitleBar()->SetIcon(Tools::GetImage(sIconURL, mxFrame));
1146 4373 : }
1147 : }
1148 :
1149 0 : void SidebarController::ShowPanel (const Panel& rPanel)
1150 : {
1151 0 : if (mpCurrentDeck)
1152 0 : mpCurrentDeck->ShowPanel(rPanel);
1153 0 : }
1154 :
1155 648 : } } // end of namespace sfx2::sidebar
1156 :
1157 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|