xref: /trunk/main/sd/source/ui/view/ViewTabBar.cxx (revision 45c5a00162811bd03b87fcb4fe9996782f2b59ec)
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 {
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:
95     ViewTabPage (Window* pParent) : TabPage(pParent) {}
96     virtual void Resize (void)
97     { SetPosSizePixel(Point(0,0),GetParent()->GetOutputSizePixel()); }
98 };
99 
100 
101 
102 
103 //===== ViewTabBar ============================================================
104 
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 
163 ViewTabBar::~ViewTabBar (void)
164 {
165 }
166 
167 
168 
169 
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 
209 ::boost::shared_ptr< ::TabControl> ViewTabBar::GetTabControl (void) const
210 {
211     return mpTabControl;
212 }
213 
214 
215 
216 
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 
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 
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 
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 
323 void SAL_CALL ViewTabBar::appendTabBarButton (const TabBarButton& rButton)
324 {
325     const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
326     AddTabBarButton(rButton);
327 }
328 
329 
330 
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 
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 
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 
360 Reference<XResourceId> SAL_CALL ViewTabBar::getResourceId (void)
361 {
362     return mxViewTabBarId;
363 }
364 
365 
366 
367 
368 sal_Bool SAL_CALL ViewTabBar::isAnchorOnly (void)
369 {
370     return false;
371 }
372 
373 
374 
375 
376 //----- XUnoTunnel ------------------------------------------------------------
377 
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 
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 
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 
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 
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 
525 void ViewTabBar::AddTabBarButton (
526     const ::com::sun::star::drawing::framework::TabBarButton& rButton)
527 {
528     AddTabBarButton(rButton, maTabBarButtons.size());
529 }
530 
531 
532 
533 
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 
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 
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>
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 
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 
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 
661 TabBarControl::TabBarControl (
662     ::Window* pParentWindow,
663     const ::rtl::Reference<ViewTabBar>& rpViewTabBar)
664     : ::TabControl(pParentWindow),
665       mpViewTabBar(rpViewTabBar)
666 {
667 }
668 
669 
670 
671 
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 
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