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 throw (RuntimeException)
284 {
285 if (rEvent.Type.equals(FrameworkHelper::msResourceActivationEvent)
286 && rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix)
287 && rEvent.ResourceId->isBoundTo(mxViewTabBarId->getAnchor(), AnchorBindingMode_DIRECT))
288 {
289 UpdateActiveButton();
290 }
291 }
292
293
294
295
296 //----- XEventListener --------------------------------------------------------
297
disposing(const lang::EventObject & rEvent)298 void SAL_CALL ViewTabBar::disposing(
299 const lang::EventObject& rEvent)
300 throw (RuntimeException)
301 {
302 if (rEvent.Source == mxConfigurationController)
303 {
304 mxConfigurationController = NULL;
305 mxController = NULL;
306 }
307 }
308
309
310
311
312 //----- XTabBar ---------------------------------------------------------------
313
addTabBarButtonAfter(const TabBarButton & rButton,const TabBarButton & rAnchor)314 void SAL_CALL ViewTabBar::addTabBarButtonAfter (
315 const TabBarButton& rButton,
316 const TabBarButton& rAnchor)
317 throw (::com::sun::star::uno::RuntimeException)
318 {
319 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
320 AddTabBarButton(rButton, rAnchor);
321 }
322
323
324
325
appendTabBarButton(const TabBarButton & rButton)326 void SAL_CALL ViewTabBar::appendTabBarButton (const TabBarButton& rButton)
327 throw (::com::sun::star::uno::RuntimeException)
328 {
329 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
330 AddTabBarButton(rButton);
331 }
332
333
334
removeTabBarButton(const TabBarButton & rButton)335 void SAL_CALL ViewTabBar::removeTabBarButton (const TabBarButton& rButton)
336 throw (::com::sun::star::uno::RuntimeException)
337 {
338 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
339 RemoveTabBarButton(rButton);
340 }
341
342
343
344
hasTabBarButton(const TabBarButton & rButton)345 sal_Bool SAL_CALL ViewTabBar::hasTabBarButton (const TabBarButton& rButton)
346 throw (::com::sun::star::uno::RuntimeException)
347 {
348 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
349 return HasTabBarButton(rButton);
350 }
351
352
353
354
getTabBarButtons(void)355 Sequence<TabBarButton> SAL_CALL ViewTabBar::getTabBarButtons (void)
356 throw (::com::sun::star::uno::RuntimeException)
357 {
358 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
359 return GetTabBarButtons();
360 }
361
362
363
364
365 //----- XResource -------------------------------------------------------------
366
getResourceId(void)367 Reference<XResourceId> SAL_CALL ViewTabBar::getResourceId (void)
368 throw (RuntimeException)
369 {
370 return mxViewTabBarId;
371 }
372
373
374
375
isAnchorOnly(void)376 sal_Bool SAL_CALL ViewTabBar::isAnchorOnly (void)
377 throw (RuntimeException)
378 {
379 return false;
380 }
381
382
383
384
385 //----- XUnoTunnel ------------------------------------------------------------
386
getUnoTunnelId(void)387 const Sequence<sal_Int8>& ViewTabBar::getUnoTunnelId (void)
388 {
389 static Sequence<sal_Int8>* pSequence = NULL;
390 if (pSequence == NULL)
391 {
392 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
393 if (pSequence == NULL)
394 {
395 static ::com::sun::star::uno::Sequence<sal_Int8> aSequence (16);
396 rtl_createUuid((sal_uInt8*)aSequence.getArray(), 0, sal_True);
397 pSequence = &aSequence;
398 }
399 }
400 return *pSequence;
401 }
402
403
404
405
getSomething(const Sequence<sal_Int8> & rId)406 sal_Int64 SAL_CALL ViewTabBar::getSomething (const Sequence<sal_Int8>& rId)
407 throw (RuntimeException)
408 {
409 sal_Int64 nResult = 0;
410
411 if (rId.getLength() == 16
412 && rtl_compareMemory(getUnoTunnelId().getConstArray(), rId.getConstArray(), 16) == 0)
413 {
414 nResult = reinterpret_cast<sal_Int64>(this);
415 }
416
417 return nResult;
418 }
419
420
421
422
423 //-----------------------------------------------------------------------------
424
ActivatePage(void)425 bool ViewTabBar::ActivatePage (void)
426 {
427 try
428 {
429 Reference<XControllerManager> xControllerManager (mxController,UNO_QUERY_THROW);
430 Reference<XConfigurationController> xConfigurationController (
431 xControllerManager->getConfigurationController());
432 if ( ! xConfigurationController.is())
433 throw RuntimeException();
434 Reference<XView> xView;
435 try
436 {
437 xView = Reference<XView>(xConfigurationController->getResource(
438 ResourceId::create(
439 ::comphelper::getProcessComponentContext(),
440 FrameworkHelper::msCenterPaneURL)),
441 UNO_QUERY);
442 }
443 catch (DeploymentException)
444 {
445 }
446
447 Client* pIPClient = NULL;
448 if (mpViewShellBase != NULL)
449 pIPClient = dynamic_cast<Client*>(mpViewShellBase->GetIPClient());
450 if (pIPClient==NULL || ! pIPClient->IsObjectInPlaceActive())
451 {
452 sal_uInt16 nIndex (mpTabControl->GetCurPageId() - 1);
453 if (nIndex < maTabBarButtons.size())
454 {
455 xConfigurationController->requestResourceActivation(
456 maTabBarButtons[nIndex].ResourceId,
457 ResourceActivationMode_REPLACE);
458 }
459
460 return true;
461 }
462 else
463 {
464 // When we run into this else branch then we have an active OLE
465 // object. We ignore the request to switch views. Additionally
466 // we put the active tab back to the one for the current view.
467 UpdateActiveButton();
468 }
469 }
470 catch (RuntimeException&)
471 {
472 DBG_UNHANDLED_EXCEPTION();
473 }
474
475 return false;
476 }
477
478
479
480
GetHeight(void)481 int ViewTabBar::GetHeight (void)
482 {
483 int nHeight (0);
484
485 if (!maTabBarButtons.empty())
486 {
487 TabPage* pActivePage (mpTabControl->GetTabPage(
488 mpTabControl->GetCurPageId()));
489 if (pActivePage!=NULL && mpTabControl->IsReallyVisible())
490 nHeight = pActivePage->GetPosPixel().Y();
491
492 if (nHeight <= 0)
493 // Using a default when the real height can not be determined.
494 // To get correct height this method should be called when the
495 // control is visible.
496 nHeight = 21;
497 }
498
499 return nHeight;
500 }
501
502
503
504
AddTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton,const::com::sun::star::drawing::framework::TabBarButton & rAnchor)505 void ViewTabBar::AddTabBarButton (
506 const ::com::sun::star::drawing::framework::TabBarButton& rButton,
507 const ::com::sun::star::drawing::framework::TabBarButton& rAnchor)
508 {
509 sal_uInt32 nIndex;
510
511 if ( ! rAnchor.ResourceId.is()
512 || (rAnchor.ResourceId->getResourceURL().getLength() == 0
513 && rAnchor.ButtonLabel.getLength() == 0))
514 {
515 nIndex = 0;
516 }
517 else
518 {
519 for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
520 {
521 if (IsEqual(maTabBarButtons[nIndex], rAnchor))
522 {
523 ++nIndex;
524 break;
525 }
526 }
527 }
528
529 AddTabBarButton(rButton,nIndex);
530 }
531
532
533
534
AddTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton)535 void ViewTabBar::AddTabBarButton (
536 const ::com::sun::star::drawing::framework::TabBarButton& rButton)
537 {
538 AddTabBarButton(rButton, maTabBarButtons.size());
539 }
540
541
542
543
AddTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton,sal_Int32 nPosition)544 void ViewTabBar::AddTabBarButton (
545 const ::com::sun::star::drawing::framework::TabBarButton& rButton,
546 sal_Int32 nPosition)
547 {
548 if (nPosition>=0
549 && nPosition<=mpTabControl->GetPageCount())
550 {
551 sal_uInt16 nIndex ((sal_uInt16)nPosition);
552
553 // Insert the button into our local array.
554 maTabBarButtons.insert(maTabBarButtons.begin()+nIndex, rButton);
555 UpdateTabBarButtons();
556 UpdateActiveButton();
557 }
558 }
559
560
561
562
RemoveTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton)563 void ViewTabBar::RemoveTabBarButton (
564 const ::com::sun::star::drawing::framework::TabBarButton& rButton)
565 {
566 sal_uInt16 nIndex;
567 for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
568 {
569 if (IsEqual(maTabBarButtons[nIndex], rButton))
570 {
571 maTabBarButtons.erase(maTabBarButtons.begin()+nIndex);
572 UpdateTabBarButtons();
573 UpdateActiveButton();
574 break;
575 }
576 }
577 }
578
579
580
581
HasTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton)582 bool ViewTabBar::HasTabBarButton (
583 const ::com::sun::star::drawing::framework::TabBarButton& rButton)
584 {
585 bool bResult (false);
586
587 for (sal_uInt32 nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
588 {
589 if (IsEqual(maTabBarButtons[nIndex], rButton))
590 {
591 bResult = true;
592 break;
593 }
594 }
595
596 return bResult;
597 }
598
599
600
601
602 ::com::sun::star::uno::Sequence<com::sun::star::drawing::framework::TabBarButton>
GetTabBarButtons(void)603 ViewTabBar::GetTabBarButtons (void)
604 {
605 sal_uInt32 nCount (maTabBarButtons.size());
606 ::com::sun::star::uno::Sequence<com::sun::star::drawing::framework::TabBarButton>
607 aList (nCount);
608
609 for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex)
610 aList[nIndex] = maTabBarButtons[nIndex];
611
612 return aList;
613 }
614
615
616
617
UpdateActiveButton(void)618 void ViewTabBar::UpdateActiveButton (void)
619 {
620 Reference<XView> xView;
621 if (mpViewShellBase != NULL)
622 xView = FrameworkHelper::Instance(*mpViewShellBase)->GetView(
623 mxViewTabBarId->getAnchor());
624 if (xView.is())
625 {
626 Reference<XResourceId> xViewId (xView->getResourceId());
627 for (sal_uInt16 nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
628 {
629 if (maTabBarButtons[nIndex].ResourceId->compareTo(xViewId) == 0)
630 {
631 mpTabControl->SetCurPageId(nIndex+1);
632 mpTabControl->::TabControl::ActivatePage();
633 break;
634 }
635 }
636 }
637 }
638
639
640
641
UpdateTabBarButtons(void)642 void ViewTabBar::UpdateTabBarButtons (void)
643 {
644 TabBarButtonList::const_iterator iTab;
645 sal_uInt16 nPageCount (mpTabControl->GetPageCount());
646 sal_uInt16 nIndex;
647 for (iTab=maTabBarButtons.begin(),nIndex=1; iTab!=maTabBarButtons.end(); ++iTab,++nIndex)
648 {
649 // Create a new tab when there are not enough.
650 if (nPageCount < nIndex)
651 mpTabControl->InsertPage(nIndex, iTab->ButtonLabel);
652
653 // Update the tab.
654 mpTabControl->SetPageText(nIndex, iTab->ButtonLabel);
655 mpTabControl->SetHelpText(nIndex, iTab->HelpText);
656 mpTabControl->SetTabPage(nIndex, mpTabPage.get());
657 }
658
659 // Delete tabs that are no longer used.
660 for (; nIndex<=nPageCount; ++nIndex)
661 mpTabControl->RemovePage(nIndex);
662
663 mpTabPage->Hide();
664 }
665
666
667
668
669 //===== TabBarControl =========================================================
670
TabBarControl(::Window * pParentWindow,const::rtl::Reference<ViewTabBar> & rpViewTabBar)671 TabBarControl::TabBarControl (
672 ::Window* pParentWindow,
673 const ::rtl::Reference<ViewTabBar>& rpViewTabBar)
674 : ::TabControl(pParentWindow),
675 mpViewTabBar(rpViewTabBar)
676 {
677 }
678
679
680
681
Paint(const Rectangle & rRect)682 void TabBarControl::Paint (const Rectangle& rRect)
683 {
684 Color aOriginalFillColor (GetFillColor());
685 Color aOriginalLineColor (GetLineColor());
686
687 // Because the actual window background is transparent--to avoid
688 // flickering due to multiple background paintings by this and by child
689 // windows--we have to paint the background for this control explicitly:
690 // the actual control is not painted over its whole bounding box.
691 SetFillColor (GetSettings().GetStyleSettings().GetDialogColor());
692 SetLineColor ();
693 DrawRect (rRect);
694 ::TabControl::Paint (rRect);
695
696 SetFillColor (aOriginalFillColor);
697 SetLineColor (aOriginalLineColor);
698 }
699
700
701
702
ActivatePage(void)703 void TabBarControl::ActivatePage (void)
704 {
705 if (mpViewTabBar->ActivatePage())
706 {
707 // Call the parent so that the correct tab is highlighted.
708 this->::TabControl::ActivatePage();
709 }
710 }
711
712 } // end of namespace sd
713