1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sd.hxx"
26
27 #include "ViewTabBar.hxx"
28
29 #define USE_TAB_CONTROL
30
31 #include "ViewShell.hxx"
32 #include "ViewShellBase.hxx"
33 #include "DrawViewShell.hxx"
34 #include "FrameView.hxx"
35 #include "EventMultiplexer.hxx"
36 #include "framework/FrameworkHelper.hxx"
37 #include "framework/Pane.hxx"
38 #include "DrawController.hxx"
39
40 #include "sdresid.hxx"
41 #include "strings.hrc"
42 #include "helpids.h"
43 #include "Client.hxx"
44 #include <vcl/svapp.hxx>
45 #include <vcl/tabpage.hxx>
46 #include <vos/mutex.hxx>
47 #include <sfx2/viewfrm.hxx>
48 #include <com/sun/star/drawing/framework/ResourceId.hpp>
49 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
50 #include <com/sun/star/lang/XUnoTunnel.hpp>
51 #include <com/sun/star/lang/DisposedException.hpp>
52 #include <comphelper/processfactory.hxx>
53 #include <tools/diagnose_ex.h>
54
55 using namespace ::com::sun::star;
56 using namespace ::com::sun::star::uno;
57 using namespace ::com::sun::star::drawing::framework;
58 using ::sd::framework::FrameworkHelper;
59 using ::sd::tools::EventMultiplexerEvent;
60 using ::rtl::OUString;
61
62 namespace sd {
63
64 namespace {
IsEqual(const TabBarButton & rButton1,const TabBarButton & rButton2)65 bool IsEqual (const TabBarButton& rButton1, const TabBarButton& rButton2)
66 {
67 return (
68 (rButton1.ResourceId.is()
69 && rButton2.ResourceId.is()
70 && rButton1.ResourceId->compareTo(rButton2.ResourceId)==0)
71 || rButton1.ButtonLabel == rButton2.ButtonLabel);
72 }
73
74 class TabBarControl : public ::TabControl
75 {
76 public:
77 TabBarControl (
78 ::Window* pParentWindow,
79 const ::rtl::Reference<ViewTabBar>& rpViewTabBar);
80 virtual void Paint (const Rectangle& rRect);
81 virtual void ActivatePage (void);
82 private:
83 ::rtl::Reference<ViewTabBar> mpViewTabBar;
84 };
85
86 } // end of anonymous namespace
87
88
89
90
91
92 class ViewTabPage : public TabPage
93 {
94 public:
ViewTabPage(Window * pParent)95 ViewTabPage (Window* pParent) : TabPage(pParent) {}
Resize(void)96 virtual void Resize (void)
97 { SetPosSizePixel(Point(0,0),GetParent()->GetOutputSizePixel()); }
98 };
99
100
101
102
103 //===== ViewTabBar ============================================================
104
ViewTabBar(const Reference<XResourceId> & rxViewTabBarId,const Reference<frame::XController> & rxController)105 ViewTabBar::ViewTabBar (
106 const Reference<XResourceId>& rxViewTabBarId,
107 const Reference<frame::XController>& rxController)
108 : ViewTabBarInterfaceBase(maMutex),
109 mpTabControl(new TabBarControl(GetAnchorWindow(rxViewTabBarId,rxController), this)),
110 mxController(rxController),
111 maTabBarButtons(),
112 mpTabPage(NULL),
113 mxViewTabBarId(rxViewTabBarId),
114 mpViewShellBase(NULL)
115 {
116 // Set one new tab page for all tab entries. We need it only to
117 // determine the height of the tab bar.
118 mpTabPage.reset(new TabPage (mpTabControl.get()));
119 mpTabPage->Hide();
120
121 // add some space before the tabitems
122 mpTabControl->SetItemsOffset(Point(5, 3));
123
124 // Tunnel through the controller and use the ViewShellBase to obtain the
125 // view frame.
126 try
127 {
128 Reference<lang::XUnoTunnel> xTunnel (mxController, UNO_QUERY_THROW);
129 DrawController* pController = reinterpret_cast<DrawController*>(
130 xTunnel->getSomething(DrawController::getUnoTunnelId()));
131 mpViewShellBase = pController->GetViewShellBase();
132 }
133 catch(RuntimeException&)
134 {}
135
136 // Register as listener at XConfigurationController.
137 Reference<XControllerManager> xControllerManager (mxController, UNO_QUERY);
138 if (xControllerManager.is())
139 {
140 mxConfigurationController = xControllerManager->getConfigurationController();
141 if (mxConfigurationController.is())
142 {
143 mxConfigurationController->addConfigurationChangeListener(
144 this,
145 FrameworkHelper::msResourceActivationEvent,
146 Any());
147 }
148 }
149
150 mpTabControl->Show();
151
152 if (mpViewShellBase != NULL
153 && rxViewTabBarId->isBoundToURL(
154 FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
155 {
156 mpViewShellBase->SetViewTabBar(this);
157 }
158 }
159
160
161
162
~ViewTabBar(void)163 ViewTabBar::~ViewTabBar (void)
164 {
165 }
166
167
168
169
disposing(void)170 void ViewTabBar::disposing (void)
171 {
172 if (mpViewShellBase != NULL
173 && mxViewTabBarId->isBoundToURL(
174 FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
175 {
176 mpViewShellBase->SetViewTabBar(NULL);
177 }
178
179 if (mxConfigurationController.is())
180 {
181 // Unregister listener from XConfigurationController.
182 try
183 {
184 mxConfigurationController->removeConfigurationChangeListener(this);
185 }
186 catch (lang::DisposedException e)
187 {
188 // Receiving a disposed exception is the normal case. Is there
189 // a way to avoid it?
190 }
191 mxConfigurationController = NULL;
192 }
193
194 {
195 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
196 // Set all references to the one tab page to NULL and delete the page.
197 for (sal_uInt16 nIndex=0; nIndex<mpTabControl->GetPageCount(); ++nIndex)
198 mpTabControl->SetTabPage(nIndex, NULL);
199 mpTabPage.reset();
200 mpTabControl.reset();
201 }
202
203 mxController = NULL;
204 }
205
206
207
208
GetTabControl(void) const209 ::boost::shared_ptr< ::TabControl> ViewTabBar::GetTabControl (void) const
210 {
211 return mpTabControl;
212 }
213
214
215
216
GetAnchorWindow(const Reference<XResourceId> & rxViewTabBarId,const Reference<frame::XController> & rxController)217 ::Window* ViewTabBar::GetAnchorWindow(
218 const Reference<XResourceId>& rxViewTabBarId,
219 const Reference<frame::XController>& rxController)
220 {
221 ::Window* pWindow = NULL;
222 ViewShellBase* pBase = NULL;
223
224 // Tunnel through the controller and use the ViewShellBase to obtain the
225 // view frame.
226 try
227 {
228 Reference<lang::XUnoTunnel> xTunnel (rxController, UNO_QUERY_THROW);
229 DrawController* pController = reinterpret_cast<DrawController*>(
230 xTunnel->getSomething(DrawController::getUnoTunnelId()));
231 pBase = pController->GetViewShellBase();
232 }
233 catch(RuntimeException&)
234 {}
235
236 // The ViewTabBar supports at the moment only the center pane.
237 if (rxViewTabBarId.is()
238 && rxViewTabBarId->isBoundToURL(
239 FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
240 {
241 if (pBase != NULL && pBase->GetViewFrame() != NULL)
242 pWindow = &pBase->GetViewFrame()->GetWindow();
243 }
244
245 // The rest is (at the moment) just for the emergency case.
246 if (pWindow == NULL)
247 {
248 Reference<XPane> xPane;
249 try
250 {
251 Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY_THROW);
252 Reference<XConfigurationController> xCC (
253 xControllerManager->getConfigurationController());
254 if (xCC.is())
255 xPane = Reference<XPane>(xCC->getResource(rxViewTabBarId->getAnchor()), UNO_QUERY);
256 }
257 catch (RuntimeException&)
258 {}
259
260 // Tunnel through the XWindow to the VCL side.
261 try
262 {
263 Reference<lang::XUnoTunnel> xTunnel (xPane, UNO_QUERY_THROW);
264 framework::Pane* pPane = reinterpret_cast<framework::Pane*>(
265 xTunnel->getSomething(framework::Pane::getUnoTunnelId()));
266 if (pPane != NULL)
267 pWindow = pPane->GetWindow()->GetParent();
268 }
269 catch (RuntimeException&)
270 {}
271 }
272
273 return pWindow;
274 }
275
276
277
278
279 //----- XConfigurationChangeListener ------------------------------------------
280
notifyConfigurationChange(const ConfigurationChangeEvent & rEvent)281 void SAL_CALL ViewTabBar::notifyConfigurationChange (
282 const ConfigurationChangeEvent& rEvent)
283 {
284 if (rEvent.Type.equals(FrameworkHelper::msResourceActivationEvent)
285 && rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix)
286 && rEvent.ResourceId->isBoundTo(mxViewTabBarId->getAnchor(), AnchorBindingMode_DIRECT))
287 {
288 UpdateActiveButton();
289 }
290 }
291
292
293
294
295 //----- XEventListener --------------------------------------------------------
296
disposing(const lang::EventObject & rEvent)297 void SAL_CALL ViewTabBar::disposing(
298 const lang::EventObject& rEvent)
299 {
300 if (rEvent.Source == mxConfigurationController)
301 {
302 mxConfigurationController = NULL;
303 mxController = NULL;
304 }
305 }
306
307
308
309
310 //----- XTabBar ---------------------------------------------------------------
311
addTabBarButtonAfter(const TabBarButton & rButton,const TabBarButton & rAnchor)312 void SAL_CALL ViewTabBar::addTabBarButtonAfter (
313 const TabBarButton& rButton,
314 const TabBarButton& rAnchor)
315 {
316 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
317 AddTabBarButton(rButton, rAnchor);
318 }
319
320
321
322
appendTabBarButton(const TabBarButton & rButton)323 void SAL_CALL ViewTabBar::appendTabBarButton (const TabBarButton& rButton)
324 {
325 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
326 AddTabBarButton(rButton);
327 }
328
329
330
removeTabBarButton(const TabBarButton & rButton)331 void SAL_CALL ViewTabBar::removeTabBarButton (const TabBarButton& rButton)
332 {
333 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
334 RemoveTabBarButton(rButton);
335 }
336
337
338
339
hasTabBarButton(const TabBarButton & rButton)340 sal_Bool SAL_CALL ViewTabBar::hasTabBarButton (const TabBarButton& rButton)
341 {
342 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
343 return HasTabBarButton(rButton);
344 }
345
346
347
348
getTabBarButtons(void)349 Sequence<TabBarButton> SAL_CALL ViewTabBar::getTabBarButtons (void)
350 {
351 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
352 return GetTabBarButtons();
353 }
354
355
356
357
358 //----- XResource -------------------------------------------------------------
359
getResourceId(void)360 Reference<XResourceId> SAL_CALL ViewTabBar::getResourceId (void)
361 {
362 return mxViewTabBarId;
363 }
364
365
366
367
isAnchorOnly(void)368 sal_Bool SAL_CALL ViewTabBar::isAnchorOnly (void)
369 {
370 return false;
371 }
372
373
374
375
376 //----- XUnoTunnel ------------------------------------------------------------
377
getUnoTunnelId(void)378 const Sequence<sal_Int8>& ViewTabBar::getUnoTunnelId (void)
379 {
380 static Sequence<sal_Int8>* pSequence = NULL;
381 if (pSequence == NULL)
382 {
383 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
384 if (pSequence == NULL)
385 {
386 static ::com::sun::star::uno::Sequence<sal_Int8> aSequence (16);
387 rtl_createUuid((sal_uInt8*)aSequence.getArray(), 0, sal_True);
388 pSequence = &aSequence;
389 }
390 }
391 return *pSequence;
392 }
393
394
395
396
getSomething(const Sequence<sal_Int8> & rId)397 sal_Int64 SAL_CALL ViewTabBar::getSomething (const Sequence<sal_Int8>& rId)
398 {
399 sal_Int64 nResult = 0;
400
401 if (rId.getLength() == 16
402 && rtl_compareMemory(getUnoTunnelId().getConstArray(), rId.getConstArray(), 16) == 0)
403 {
404 nResult = reinterpret_cast<sal_Int64>(this);
405 }
406
407 return nResult;
408 }
409
410
411
412
413 //-----------------------------------------------------------------------------
414
ActivatePage(void)415 bool ViewTabBar::ActivatePage (void)
416 {
417 try
418 {
419 Reference<XControllerManager> xControllerManager (mxController,UNO_QUERY_THROW);
420 Reference<XConfigurationController> xConfigurationController (
421 xControllerManager->getConfigurationController());
422 if ( ! xConfigurationController.is())
423 throw RuntimeException();
424 Reference<XView> xView;
425 try
426 {
427 xView = Reference<XView>(xConfigurationController->getResource(
428 ResourceId::create(
429 ::comphelper::getProcessComponentContext(),
430 FrameworkHelper::msCenterPaneURL)),
431 UNO_QUERY);
432 }
433 catch (DeploymentException)
434 {
435 }
436
437 Client* pIPClient = NULL;
438 if (mpViewShellBase != NULL)
439 pIPClient = dynamic_cast<Client*>(mpViewShellBase->GetIPClient());
440 if (pIPClient==NULL || ! pIPClient->IsObjectInPlaceActive())
441 {
442 sal_uInt16 nIndex (mpTabControl->GetCurPageId() - 1);
443 if (nIndex < maTabBarButtons.size())
444 {
445 xConfigurationController->requestResourceActivation(
446 maTabBarButtons[nIndex].ResourceId,
447 ResourceActivationMode_REPLACE);
448 }
449
450 return true;
451 }
452 else
453 {
454 // When we run into this else branch then we have an active OLE
455 // object. We ignore the request to switch views. Additionally
456 // we put the active tab back to the one for the current view.
457 UpdateActiveButton();
458 }
459 }
460 catch (RuntimeException&)
461 {
462 DBG_UNHANDLED_EXCEPTION();
463 }
464
465 return false;
466 }
467
468
469
470
GetHeight(void)471 int ViewTabBar::GetHeight (void)
472 {
473 int nHeight (0);
474
475 if (!maTabBarButtons.empty())
476 {
477 TabPage* pActivePage (mpTabControl->GetTabPage(
478 mpTabControl->GetCurPageId()));
479 if (pActivePage!=NULL && mpTabControl->IsReallyVisible())
480 nHeight = pActivePage->GetPosPixel().Y();
481
482 if (nHeight <= 0)
483 // Using a default when the real height can not be determined.
484 // To get correct height this method should be called when the
485 // control is visible.
486 nHeight = 21;
487 }
488
489 return nHeight;
490 }
491
492
493
494
AddTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton,const::com::sun::star::drawing::framework::TabBarButton & rAnchor)495 void ViewTabBar::AddTabBarButton (
496 const ::com::sun::star::drawing::framework::TabBarButton& rButton,
497 const ::com::sun::star::drawing::framework::TabBarButton& rAnchor)
498 {
499 sal_uInt32 nIndex;
500
501 if ( ! rAnchor.ResourceId.is()
502 || (rAnchor.ResourceId->getResourceURL().getLength() == 0
503 && rAnchor.ButtonLabel.getLength() == 0))
504 {
505 nIndex = 0;
506 }
507 else
508 {
509 for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
510 {
511 if (IsEqual(maTabBarButtons[nIndex], rAnchor))
512 {
513 ++nIndex;
514 break;
515 }
516 }
517 }
518
519 AddTabBarButton(rButton,nIndex);
520 }
521
522
523
524
AddTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton)525 void ViewTabBar::AddTabBarButton (
526 const ::com::sun::star::drawing::framework::TabBarButton& rButton)
527 {
528 AddTabBarButton(rButton, maTabBarButtons.size());
529 }
530
531
532
533
AddTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton,sal_Int32 nPosition)534 void ViewTabBar::AddTabBarButton (
535 const ::com::sun::star::drawing::framework::TabBarButton& rButton,
536 sal_Int32 nPosition)
537 {
538 if (nPosition>=0
539 && nPosition<=mpTabControl->GetPageCount())
540 {
541 sal_uInt16 nIndex ((sal_uInt16)nPosition);
542
543 // Insert the button into our local array.
544 maTabBarButtons.insert(maTabBarButtons.begin()+nIndex, rButton);
545 UpdateTabBarButtons();
546 UpdateActiveButton();
547 }
548 }
549
550
551
552
RemoveTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton)553 void ViewTabBar::RemoveTabBarButton (
554 const ::com::sun::star::drawing::framework::TabBarButton& rButton)
555 {
556 sal_uInt16 nIndex;
557 for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
558 {
559 if (IsEqual(maTabBarButtons[nIndex], rButton))
560 {
561 maTabBarButtons.erase(maTabBarButtons.begin()+nIndex);
562 UpdateTabBarButtons();
563 UpdateActiveButton();
564 break;
565 }
566 }
567 }
568
569
570
571
HasTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton)572 bool ViewTabBar::HasTabBarButton (
573 const ::com::sun::star::drawing::framework::TabBarButton& rButton)
574 {
575 bool bResult (false);
576
577 for (sal_uInt32 nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
578 {
579 if (IsEqual(maTabBarButtons[nIndex], rButton))
580 {
581 bResult = true;
582 break;
583 }
584 }
585
586 return bResult;
587 }
588
589
590
591
592 ::com::sun::star::uno::Sequence<com::sun::star::drawing::framework::TabBarButton>
GetTabBarButtons(void)593 ViewTabBar::GetTabBarButtons (void)
594 {
595 sal_uInt32 nCount (maTabBarButtons.size());
596 ::com::sun::star::uno::Sequence<com::sun::star::drawing::framework::TabBarButton>
597 aList (nCount);
598
599 for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex)
600 aList[nIndex] = maTabBarButtons[nIndex];
601
602 return aList;
603 }
604
605
606
607
UpdateActiveButton(void)608 void ViewTabBar::UpdateActiveButton (void)
609 {
610 Reference<XView> xView;
611 if (mpViewShellBase != NULL)
612 xView = FrameworkHelper::Instance(*mpViewShellBase)->GetView(
613 mxViewTabBarId->getAnchor());
614 if (xView.is())
615 {
616 Reference<XResourceId> xViewId (xView->getResourceId());
617 for (sal_uInt16 nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
618 {
619 if (maTabBarButtons[nIndex].ResourceId->compareTo(xViewId) == 0)
620 {
621 mpTabControl->SetCurPageId(nIndex+1);
622 mpTabControl->::TabControl::ActivatePage();
623 break;
624 }
625 }
626 }
627 }
628
629
630
631
UpdateTabBarButtons(void)632 void ViewTabBar::UpdateTabBarButtons (void)
633 {
634 TabBarButtonList::const_iterator iTab;
635 sal_uInt16 nPageCount (mpTabControl->GetPageCount());
636 sal_uInt16 nIndex;
637 for (iTab=maTabBarButtons.begin(),nIndex=1; iTab!=maTabBarButtons.end(); ++iTab,++nIndex)
638 {
639 // Create a new tab when there are not enough.
640 if (nPageCount < nIndex)
641 mpTabControl->InsertPage(nIndex, iTab->ButtonLabel);
642
643 // Update the tab.
644 mpTabControl->SetPageText(nIndex, iTab->ButtonLabel);
645 mpTabControl->SetHelpText(nIndex, iTab->HelpText);
646 mpTabControl->SetTabPage(nIndex, mpTabPage.get());
647 }
648
649 // Delete tabs that are no longer used.
650 for (; nIndex<=nPageCount; ++nIndex)
651 mpTabControl->RemovePage(nIndex);
652
653 mpTabPage->Hide();
654 }
655
656
657
658
659 //===== TabBarControl =========================================================
660
TabBarControl(::Window * pParentWindow,const::rtl::Reference<ViewTabBar> & rpViewTabBar)661 TabBarControl::TabBarControl (
662 ::Window* pParentWindow,
663 const ::rtl::Reference<ViewTabBar>& rpViewTabBar)
664 : ::TabControl(pParentWindow),
665 mpViewTabBar(rpViewTabBar)
666 {
667 }
668
669
670
671
Paint(const Rectangle & rRect)672 void TabBarControl::Paint (const Rectangle& rRect)
673 {
674 Color aOriginalFillColor (GetFillColor());
675 Color aOriginalLineColor (GetLineColor());
676
677 // Because the actual window background is transparent--to avoid
678 // flickering due to multiple background paintings by this and by child
679 // windows--we have to paint the background for this control explicitly:
680 // the actual control is not painted over its whole bounding box.
681 SetFillColor (GetSettings().GetStyleSettings().GetDialogColor());
682 SetLineColor ();
683 DrawRect (rRect);
684 ::TabControl::Paint (rRect);
685
686 SetFillColor (aOriginalFillColor);
687 SetLineColor (aOriginalLineColor);
688 }
689
690
691
692
ActivatePage(void)693 void TabBarControl::ActivatePage (void)
694 {
695 if (mpViewTabBar->ActivatePage())
696 {
697 // Call the parent so that the correct tab is highlighted.
698 this->::TabControl::ActivatePage();
699 }
700 }
701
702 } // end of namespace sd
703