xref: /trunk/main/toolkit/source/awt/vclxtabcontrol.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 #include "vclxtabcontrol.hxx"
25 
26 #include <com/sun/star/awt/PosSize.hpp>
27 #include <sal/macros.h>
28 #include <toolkit/helper/property.hxx>
29 #include <toolkit/helper/vclunohelper.hxx>
30 #include <vcl/tabctrl.hxx>
31 #include <vcl/tabpage.hxx>
32 
33 #include "forward.hxx"
34 
35 namespace layoutimpl
36 {
37 
38 using namespace ::com::sun::star::lang;
39 using namespace ::com::sun::star::beans;
40 using namespace ::com::sun::star;
41 
ChildProps(VCLXTabControl::ChildData * pData)42 VCLXTabControl::ChildProps::ChildProps( VCLXTabControl::ChildData *pData )
43 {
44     addProp( RTL_CONSTASCII_USTRINGPARAM( "Title" ),
45              ::getCppuType( static_cast< const rtl::OUString* >( NULL ) ),
46              &(pData->maTitle) );
47 }
48 
ChildData(uno::Reference<awt::XLayoutConstrains> const & xChild)49 VCLXTabControl::ChildData::ChildData( uno::Reference< awt::XLayoutConstrains > const& xChild )
50     : Box_Base::ChildData( xChild )
51     , maTitle()
52 {
53 }
54 
55 VCLXTabControl::ChildData*
createChild(uno::Reference<awt::XLayoutConstrains> const & xChild)56 VCLXTabControl::createChild( uno::Reference< awt::XLayoutConstrains > const& xChild )
57 {
58     return new ChildData( xChild );
59 }
60 
61 VCLXTabControl::ChildProps*
createChildProps(Box_Base::ChildData * pData)62 VCLXTabControl::createChildProps( Box_Base::ChildData *pData )
63 {
64     return new ChildProps( static_cast<VCLXTabControl::ChildData*> ( pData ) );
65 }
66 
67 DBG_NAME( VCLXTabControl );
68 
69 #if !defined (__GNUC__)
70 #define __PRETTY_FUNCTION__ __FUNCTION__
71 #endif /* !__GNUC__ */
72 
VCLXTabControl()73 VCLXTabControl::VCLXTabControl()
74   : VCLXWindow()
75   , VCLXTabControl_Base()
76   , Box_Base()
77   , mTabId (1)
78   , bRealized (false)
79 {
80 #ifndef __SUNPRO_CC
81     OSL_TRACE ("\n********%s:%x", __PRETTY_FUNCTION__, this);
82 #endif
83     DBG_CTOR( VCLXTabControl, NULL );
84 }
85 
~VCLXTabControl()86 VCLXTabControl::~VCLXTabControl()
87 {
88     DBG_DTOR( VCLXTabControl, NULL );
89 }
90 
91 IMPLEMENT_2_FORWARD_XINTERFACE2( VCLXTabControl, VCLXWindow, Container, VCLXTabControl_Base );
92 
93 IMPLEMENT_FORWARD_XTYPEPROVIDER2( VCLXTabControl, VCLXWindow, VCLXTabControl_Base );
94 
dispose()95 void SAL_CALL VCLXTabControl::dispose( )
96 {
97     {
98         ::vos::OGuard aGuard( GetMutex() );
99 
100         EventObject aDisposeEvent;
101         aDisposeEvent.Source = W3K_EXPLICIT_CAST (*this);
102 //            maTabListeners.disposeAndClear( aDisposeEvent );
103     }
104 
105     VCLXWindow::dispose();
106 }
107 
108 #if 0
109 void SAL_CALL VCLXTabControl::addTabListener( const Reference< XTabListener >& listener )
110 {
111     if ( listener.is() )
112         maTabListeners.addInterface( listener );
113 }
114 
115 void SAL_CALL VCLXTabControl::removeTabListener( const Reference< XTabListener >& listener )
116 {
117     if ( listener.is() )
118         maTabListeners.removeInterface( listener );
119 }
120 #endif
121 
getTabControl() const122 TabControl *VCLXTabControl::getTabControl() const
123 {
124     TabControl *pTabControl = static_cast< TabControl* >( GetWindow() );
125     if ( pTabControl )
126         return pTabControl;
127     throw uno::RuntimeException();
128 }
129 
insertTab()130 sal_Int32 SAL_CALL VCLXTabControl::insertTab()
131 {
132     TabControl *pTabControl = getTabControl();
133     sal_uInt16 id = sal::static_int_cast< sal_uInt16 >( mTabId++ );
134     rtl::OUString title (RTL_CONSTASCII_USTRINGPARAM( "" ) );
135     pTabControl->InsertPage( id, title.getStr(), TAB_APPEND );
136     pTabControl->SetTabPage( id, new TabPage( pTabControl ) );
137     return id;
138 }
139 
removeTab(sal_Int32 ID)140 void SAL_CALL VCLXTabControl::removeTab( sal_Int32 ID )
141 {
142     TabControl *pTabControl = getTabControl();
143     if ( pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >( ID ) ) == NULL )
144         throw IndexOutOfBoundsException();
145     pTabControl->RemovePage( sal::static_int_cast< sal_uInt16 >( ID ) );
146 }
147 
activateTab(sal_Int32 ID)148 void SAL_CALL VCLXTabControl::activateTab( sal_Int32 ID )
149 {
150     TabControl *pTabControl = getTabControl();
151     if ( pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >( ID ) ) == NULL )
152         throw IndexOutOfBoundsException();
153     pTabControl->SelectTabPage( sal::static_int_cast< sal_uInt16 >( ID ) );
154 }
155 
getActiveTabID()156 sal_Int32 SAL_CALL VCLXTabControl::getActiveTabID()
157 {
158     return getTabControl()->GetCurPageId( );
159 }
160 
addTabListener(const uno::Reference<awt::XTabListener> & xListener)161 void SAL_CALL VCLXTabControl::addTabListener( const uno::Reference< awt::XTabListener >& xListener )
162 {
163     for ( std::list< uno::Reference
164               < awt::XTabListener > >::const_iterator it
165               = mxTabListeners.begin(); it != mxTabListeners.end(); it++ )
166     {
167         if ( *it == xListener )
168             // already added
169             return;
170     }
171     mxTabListeners.push_back( xListener );
172 }
173 
removeTabListener(const uno::Reference<awt::XTabListener> & xListener)174 void SAL_CALL VCLXTabControl::removeTabListener( const uno::Reference< awt::XTabListener >& xListener )
175 {
176     for ( std::list< uno::Reference
177               < awt::XTabListener > >::iterator it
178               = mxTabListeners.begin(); it != mxTabListeners.end(); it++ )
179     {
180         if ( *it == xListener )
181         {
182             mxTabListeners.erase( it );
183             break;
184         }
185     }
186 }
187 
setTabProps(sal_Int32 ID,const uno::Sequence<NamedValue> & Properties)188 void SAL_CALL VCLXTabControl::setTabProps( sal_Int32 ID, const uno::Sequence< NamedValue >& Properties )
189 {
190     TabControl *pTabControl = getTabControl();
191     if ( pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >( ID ) ) == NULL )
192         throw IndexOutOfBoundsException();
193 
194     for ( int i = 0; i < Properties.getLength(); i++ )
195     {
196         const rtl::OUString &name = Properties[i].Name;
197         const uno::Any &value = Properties[i].Value;
198 
199         if ( name  == rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ) )
200         {
201             rtl::OUString title = value.get<rtl::OUString>();
202             pTabControl->SetPageText( sal::static_int_cast< sal_uInt16 >( ID ), title.getStr() );
203         }
204     }
205 }
206 
getTabProps(sal_Int32 ID)207 uno::Sequence< NamedValue > SAL_CALL VCLXTabControl::getTabProps( sal_Int32 ID )
208 {
209     TabControl *pTabControl = getTabControl();
210     if ( pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >( ID ) ) == NULL )
211         throw IndexOutOfBoundsException();
212 
213 #define ADD_PROP( seq, i, name, val ) {                                \
214         NamedValue value;                                                  \
215         value.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( name ) ); \
216         value.Value = uno::makeAny( val );                                      \
217         seq[i] = value;                                                    \
218     }
219 
220     uno::Sequence< NamedValue > props( 2 );
221     ADD_PROP( props, 0, "Title", rtl::OUString( pTabControl->GetPageText( sal::static_int_cast< sal_uInt16 >( ID ) ) ) );
222     ADD_PROP( props, 1, "Position", pTabControl->GetPagePos( sal::static_int_cast< sal_uInt16 >( ID ) ) );
223 #undef ADD_PROP
224     return props;
225 }
226 
227 // TODO: draw tab border here
draw(sal_Int32 nX,sal_Int32 nY)228 void SAL_CALL VCLXTabControl::draw( sal_Int32 nX, sal_Int32 nY )
229 {
230     ::vos::OGuard aGuard( GetMutex() );
231 
232     TabControl *pTabControl = getTabControl();
233     TabPage *pTabPage = pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >(  getActiveTabID() ) );
234     if ( pTabPage )
235     {
236         ::Point aPos( nX, nY );
237         ::Size  aSize = pTabPage->GetSizePixel();
238 
239         OutputDevice* pDev = VCLUnoHelper::GetOutputDevice( getGraphics() );
240         aPos  = pDev->PixelToLogic( aPos );
241         aSize = pDev->PixelToLogic( aSize );
242 
243         pTabPage->Draw( pDev, aPos, aSize, 0 );
244     }
245 
246     VCLXWindow::draw( nX, nY );
247 }
248 
AddChild(uno::Reference<awt::XLayoutConstrains> const & xChild)249 void VCLXTabControl::AddChild (uno::Reference< awt::XLayoutConstrains > const& xChild)
250 
251 {
252 #ifndef __SUNPRO_CC
253     OSL_TRACE ("%s: children: %d", __PRETTY_FUNCTION__, maChildren.size ());
254 #endif
255     mIdMap[ xChild ] = mTabId++;
256     Box_Base::AddChild( xChild );
257 #ifndef __SUNPRO_CC
258     OSL_TRACE ("%s: children: %d", __PRETTY_FUNCTION__, maChildren.size ());
259 #endif
260 }
261 
addChild(const uno::Reference<awt::XLayoutConstrains> & xChild)262 void SAL_CALL VCLXTabControl::addChild(
263     const uno::Reference< awt::XLayoutConstrains > &xChild )
264 {
265     mIdMap[ xChild ] = insertTab();
266     Box_Base::addChild( xChild );
267 }
268 
removeChild(const uno::Reference<awt::XLayoutConstrains> & xChild)269 void SAL_CALL VCLXTabControl::removeChild( const uno::Reference< awt::XLayoutConstrains > &xChild )
270 {
271     removeTab( mIdMap[xChild] );
272     mIdMap[ xChild ] = -1;
273     Box_Base::removeChild( xChild );
274 }
275 
setChildrenVisible(uno::Reference<awt::XLayoutConstrains> xChild,bool visible)276 static void setChildrenVisible( uno::Reference < awt::XLayoutConstrains > xChild, bool visible )
277 {
278     uno::Reference< awt::XWindow > xWin( xChild, uno::UNO_QUERY);
279     if ( xWin.is() )
280     {
281         xWin->setVisible( visible );
282     }
283 
284     uno::Reference < awt::XLayoutContainer > xCont( xChild, uno::UNO_QUERY );
285     if ( xCont.is())
286     {
287         uno::Sequence< uno::Reference < awt::XLayoutConstrains > > children = xCont->getChildren();
288         for ( int i = 0; i < children.getLength(); i++ )
289         {
290             setChildrenVisible( children[i], visible );
291         }
292     }
293 }
294 
allocateArea(awt::Rectangle const & area)295 void SAL_CALL VCLXTabControl::allocateArea (awt::Rectangle const &area)
296 {
297 #ifndef __SUNPRO_CC
298     OSL_TRACE ("\n%s", __PRETTY_FUNCTION__);
299 #endif
300     maAllocation = area;
301 
302     TabControl *pTabControl = getTabControl();
303 
304 // FIXME: this is wrong. We just want to set tab controls pos/size for
305 // the tabs menu, otherwise, it gets events that should go to children
306 // (I guess we could solve this by making the tabcontrol as the actual
307 // XWindow parent of its children, when importing...)  Not sure about
308 // TabPage drawing... That doesn't work on gtk+; just ignoring that.
309 // LATER: Nah, the proper fix is to get the XWindow hierarchy
310 // straight.
311 
312 #if 0
313     setPosSize( area.X, area.Y, area.Width, area.Height, awt::PosSize::POSSIZE );
314 #else
315     awt::Size currentSize = getSize();
316     awt::Size requestedSize (area.Width, area.Height);
317 //    requestedSize.Height = getHeightForWidth( area.Width );
318 
319     awt::Size minimumSize = getMinimumSize();
320     if (requestedSize.Width < minimumSize.Width)
321         requestedSize.Width = minimumSize.Width;
322     if (requestedSize.Height < minimumSize.Height)
323         requestedSize.Height = minimumSize.Height;
324 
325     Size pageSize = static_cast<TabControl*> (GetWindow ())->GetTabPageSizePixel ();
326     awt::Size pageBasedSize (0, 0);
327     pageBasedSize.Width = pageSize.Width ();
328     pageBasedSize.Height = pageSize.Height ();
329 
330     const int wc = 0;
331     const int hc = 20;
332     static int pwc = 0;
333     static int phc = 40;
334 
335     if (requestedSize.Width < pageBasedSize.Width)
336         requestedSize.Width = pageBasedSize.Width + wc;
337     if (requestedSize.Height < pageBasedSize.Height)
338         requestedSize.Height = pageBasedSize.Height + hc;
339 
340     Size windowSize = GetWindow()->GetSizePixel();
341     Window *parent = GetWindow()->GetParent();
342     Size parentSize = parent->GetSizePixel();
343 
344 #ifndef __SUNPRO_CC
345 #ifdef GCC_MAJOR
346     OSL_TRACE ("\n%s", __PRETTY_FUNCTION__);
347 #endif /* GCC_MAJOR */
348     OSL_TRACE ("%s: cursize: %d ,%d", __FUNCTION__, currentSize.Width, currentSize.Height );
349     OSL_TRACE ("%s: area: %d, %d", __FUNCTION__, area.Width, area.Height );
350     OSL_TRACE ("%s: minimum: %d, %d", __FUNCTION__, minimumSize.Width, minimumSize.Height );
351     OSL_TRACE ("%s: requestedSize: %d, %d", __FUNCTION__, requestedSize.Width, requestedSize.Height );
352     OSL_TRACE ("%s: pageBasedSize: %d, %d", __FUNCTION__, pageBasedSize.Width, pageBasedSize.Height );
353 
354     //OSL_TRACE ("%s: parent: %d, %d", __FUNCTION__, parentSize.Width(), parentSize.Height() );
355     //OSL_TRACE ("%s: window: %d, %d", __FUNCTION__, windowSize.Width(), windowSize.Height() );
356 #endif
357 
358     //bRealized = false;
359     if (!bRealized)
360     {
361         setPosSize( area.X, area.Y, requestedSize.Width, requestedSize.Height, awt::PosSize::POSSIZE );
362         bRealized = true;
363     }
364     else
365     {
366         if ( requestedSize.Width > currentSize.Width + 10)
367             setPosSize( 0, 0, requestedSize.Width, 0, awt::PosSize::WIDTH );
368         if ( requestedSize.Height > currentSize.Height + 10)
369             setPosSize( 0, 0, 0, requestedSize.Height, awt::PosSize::HEIGHT );
370     }
371 #endif
372 
373     if (pageBasedSize.Width > parentSize.Width ()
374         || pageBasedSize.Height > parentSize.Height ())
375         //parent->SetSizePixel ( Size (pageBasedSize.Width, pageBasedSize.Height));
376         //parent->SetSizePixel ( Size (pageBasedSize.Width + pwc, pageBasedSize.Height + phc));
377         parent->SetSizePixel ( Size (requestedSize.Width + pwc, requestedSize.Height + phc));
378 
379     // FIXME: we can save cycles by setting visibility more sensibly. Having
380     // it here does makes it easier when changing tabs (just needs a recalc())
381     unsigned i = 0;
382     for ( std::list<Box_Base::ChildData *>::const_iterator it
383               = maChildren.begin(); it != maChildren.end(); it++, i++ )
384     {
385         ChildData *child = static_cast<VCLXTabControl::ChildData*> ( *it );
386         uno::Reference
387               < awt::XLayoutConstrains > xChild( child->mxChild );
388         if ( xChild.is() )
389         {
390             uno::Reference< awt::XWindow > xWin( xChild, uno::UNO_QUERY );
391             bool active = (i+1 == (unsigned) getActiveTabID());
392 
393             // HACK: since our layout:: container don't implement XWindow, we have no easy
394             // way to set them invisible; lets just set all their children as such :P
395 #if 0
396             if ( xWin.is() )
397                 xWin->setVisible( active );
398 #else
399             setChildrenVisible( xChild, active );
400 #endif
401 
402             if ( active )
403             {
404                 ::Rectangle label_rect = pTabControl->GetTabBounds( sal::static_int_cast< sal_uInt16 >( i+1 ) );
405                 ::Rectangle page_rect = pTabControl->GetTabPageBounds( sal::static_int_cast< sal_uInt16 >( i+1 ) );
406 
407                 awt::Rectangle childRect;
408                 childRect.X = page_rect.Left();
409                 childRect.Y = SAL_MAX( label_rect.Bottom(), page_rect.Top() );
410                 childRect.Width = page_rect.Right() - page_rect.Left();
411                 childRect.Height = page_rect.Bottom() - childRect.Y;
412 
413                 allocateChildAt( xChild, childRect );
414             }
415         }
416     }
417 }
418 
getMinimumSize()419 awt::Size SAL_CALL VCLXTabControl::getMinimumSize()
420 {
421     awt::Size requestedSize = VCLXWindow::getMinimumSize();
422     awt::Size childrenSize( 0, 0 );
423 
424     TabControl* pTabControl = static_cast< TabControl* >( GetWindow() );
425     if ( !pTabControl )
426         return requestedSize;
427 
428     // calculate size to accommodate all children
429     unsigned i = 0;
430     for ( std::list<Box_Base::ChildData *>::const_iterator it
431               = maChildren.begin(); it != maChildren.end(); it++, i++ )
432     {
433         ChildData *child = static_cast<VCLXTabControl::ChildData*> ( *it );
434         if ( child->mxChild.is() )
435         {
436             // set the title prop here...
437             pTabControl->SetPageText( sal::static_int_cast< sal_uInt16 >( i+1 ), child->maTitle.getStr() );
438 
439             awt::Size childSize( child->mxChild->getMinimumSize() );
440             childrenSize.Width = SAL_MAX( childSize.Width, childrenSize.Width );
441             childrenSize.Height = SAL_MAX( childSize.Height, childrenSize.Height );
442         }
443     }
444 
445 #ifndef __SUNPRO_CC
446 #ifdef GCC_MAJOR
447     OSL_TRACE ("\n%s", __PRETTY_FUNCTION__);
448 #endif /* GCC_MAJOR */
449     OSL_TRACE ("%s: children: %d", __FUNCTION__, i);
450     OSL_TRACE ("%s: childrenSize: %d, %d", __FUNCTION__, childrenSize.Width, childrenSize.Height );
451 #endif
452 
453     requestedSize.Width += childrenSize.Width;
454     requestedSize.Height += childrenSize.Height + 20;
455 
456     maRequisition = requestedSize;
457     return requestedSize;
458 }
459 
ProcessWindowEvent(const VclWindowEvent & _rVclWindowEvent)460 void VCLXTabControl::ProcessWindowEvent( const VclWindowEvent& _rVclWindowEvent )
461 {
462     ::vos::OClearableGuard aGuard( GetMutex() );
463     TabControl* pTabControl = static_cast< TabControl* >( GetWindow() );
464     if ( !pTabControl )
465         return;
466 
467     switch ( _rVclWindowEvent.GetId() )
468     {
469         case VCLEVENT_TABPAGE_ACTIVATE:
470             forceRecalc();
471         case VCLEVENT_TABPAGE_DEACTIVATE:
472         case VCLEVENT_TABPAGE_INSERTED:
473         case VCLEVENT_TABPAGE_REMOVED:
474         case VCLEVENT_TABPAGE_REMOVEDALL:
475         case VCLEVENT_TABPAGE_PAGETEXTCHANGED:
476         {
477             sal_uLong page = (sal_uLong) _rVclWindowEvent.GetData();
478             for ( std::list< uno::Reference
479                       < awt::XTabListener > >::iterator it
480                       = mxTabListeners.begin(); it != mxTabListeners.end(); it++)
481             {
482                 uno::Reference
483                     < awt::XTabListener > listener = *it;
484 
485                 switch ( _rVclWindowEvent.GetId() )
486                 {
487 
488                     case VCLEVENT_TABPAGE_ACTIVATE:
489                         listener->activated( page );
490                         break;
491                     case VCLEVENT_TABPAGE_DEACTIVATE:
492                         listener->deactivated( page );
493                         break;
494                     case VCLEVENT_TABPAGE_INSERTED:
495                         listener->inserted( page );
496                         break;
497                     case VCLEVENT_TABPAGE_REMOVED:
498                         listener->removed( page );
499                         break;
500                     case VCLEVENT_TABPAGE_REMOVEDALL:
501                         for ( int i = 1; i < mTabId; i++)
502                         {
503                             if ( pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >( i ) ) )
504                                 listener->removed( i );
505                         }
506                         break;
507                     case VCLEVENT_TABPAGE_PAGETEXTCHANGED:
508                         listener->changed( page, getTabProps( page ) );
509                         break;
510                 }
511             }
512             break;
513         }
514         default:
515             aGuard.clear();
516             VCLXWindow::ProcessWindowEvent( _rVclWindowEvent );
517             break;
518     }
519 }
520 
setProperty(const::rtl::OUString & PropertyName,const uno::Any & Value)521 void SAL_CALL VCLXTabControl::setProperty( const ::rtl::OUString& PropertyName, const uno::Any &Value )
522 {
523     VCLXWindow::setProperty( PropertyName, Value );
524 }
525 
getProperty(const::rtl::OUString & PropertyName)526 uno::Any SAL_CALL VCLXTabControl::getProperty( const ::rtl::OUString& PropertyName )
527 {
528     return VCLXWindow::getProperty( PropertyName );
529 }
530 
531 } // namespace layoutimpl
532