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 
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 
49 VCLXTabControl::ChildData::ChildData( uno::Reference< awt::XLayoutConstrains > const& xChild )
50     : Box_Base::ChildData( xChild )
51     , maTitle()
52 {
53 }
54 
55 VCLXTabControl::ChildData*
56 VCLXTabControl::createChild( uno::Reference< awt::XLayoutConstrains > const& xChild )
57 {
58     return new ChildData( xChild );
59 }
60 
61 VCLXTabControl::ChildProps*
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 
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 
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 
95 void SAL_CALL VCLXTabControl::dispose( ) throw(uno::RuntimeException)
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 ) throw (uno::RuntimeException)
110 {
111     if ( listener.is() )
112         maTabListeners.addInterface( listener );
113 }
114 
115 void SAL_CALL VCLXTabControl::removeTabListener( const Reference< XTabListener >& listener ) throw (uno::RuntimeException)
116 {
117     if ( listener.is() )
118         maTabListeners.removeInterface( listener );
119 }
120 #endif
121 
122 TabControl *VCLXTabControl::getTabControl() const throw (uno::RuntimeException)
123 {
124     TabControl *pTabControl = static_cast< TabControl* >( GetWindow() );
125     if ( pTabControl )
126         return pTabControl;
127     throw uno::RuntimeException();
128 }
129 
130 sal_Int32 SAL_CALL VCLXTabControl::insertTab() throw (uno::RuntimeException)
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 
140 void SAL_CALL VCLXTabControl::removeTab( sal_Int32 ID ) throw (uno::RuntimeException, IndexOutOfBoundsException)
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 
148 void SAL_CALL VCLXTabControl::activateTab( sal_Int32 ID ) throw (uno::RuntimeException, IndexOutOfBoundsException)
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 
156 sal_Int32 SAL_CALL VCLXTabControl::getActiveTabID() throw (uno::RuntimeException)
157 {
158     return getTabControl()->GetCurPageId( );
159 }
160 
161 void SAL_CALL VCLXTabControl::addTabListener( const uno::Reference< awt::XTabListener >& xListener ) throw (uno::RuntimeException)
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 
174 void SAL_CALL VCLXTabControl::removeTabListener( const uno::Reference< awt::XTabListener >& xListener ) throw (uno::RuntimeException)
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 
188 void SAL_CALL VCLXTabControl::setTabProps( sal_Int32 ID, const uno::Sequence< NamedValue >& Properties ) throw (uno::RuntimeException, IndexOutOfBoundsException)
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 
207 uno::Sequence< NamedValue > SAL_CALL VCLXTabControl::getTabProps( sal_Int32 ID )
208     throw (IndexOutOfBoundsException, uno::RuntimeException)
209 {
210     TabControl *pTabControl = getTabControl();
211     if ( pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >( ID ) ) == NULL )
212         throw IndexOutOfBoundsException();
213 
214 #define ADD_PROP( seq, i, name, val ) {                                \
215         NamedValue value;                                                  \
216         value.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( name ) ); \
217         value.Value = uno::makeAny( val );                                      \
218         seq[i] = value;                                                    \
219     }
220 
221     uno::Sequence< NamedValue > props( 2 );
222     ADD_PROP( props, 0, "Title", rtl::OUString( pTabControl->GetPageText( sal::static_int_cast< sal_uInt16 >( ID ) ) ) );
223     ADD_PROP( props, 1, "Position", pTabControl->GetPagePos( sal::static_int_cast< sal_uInt16 >( ID ) ) );
224 #undef ADD_PROP
225     return props;
226 }
227 
228 // TODO: draw tab border here
229 void SAL_CALL VCLXTabControl::draw( sal_Int32 nX, sal_Int32 nY ) throw(uno::RuntimeException)
230 {
231     ::vos::OGuard aGuard( GetMutex() );
232 
233     TabControl *pTabControl = getTabControl();
234     TabPage *pTabPage = pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >(  getActiveTabID() ) );
235     if ( pTabPage )
236     {
237         ::Point aPos( nX, nY );
238         ::Size  aSize = pTabPage->GetSizePixel();
239 
240 		OutputDevice* pDev = VCLUnoHelper::GetOutputDevice( getGraphics() );
241         aPos  = pDev->PixelToLogic( aPos );
242         aSize = pDev->PixelToLogic( aSize );
243 
244         pTabPage->Draw( pDev, aPos, aSize, 0 );
245     }
246 
247     VCLXWindow::draw( nX, nY );
248 }
249 
250 void VCLXTabControl::AddChild (uno::Reference< awt::XLayoutConstrains > const& xChild)
251 
252 {
253 #ifndef __SUNPRO_CC
254     OSL_TRACE ("%s: children: %d", __PRETTY_FUNCTION__, maChildren.size ());
255 #endif
256     mIdMap[ xChild ] = mTabId++;
257     Box_Base::AddChild( xChild );
258 #ifndef __SUNPRO_CC
259     OSL_TRACE ("%s: children: %d", __PRETTY_FUNCTION__, maChildren.size ());
260 #endif
261 }
262 
263 void SAL_CALL VCLXTabControl::addChild(
264     const uno::Reference< awt::XLayoutConstrains > &xChild )
265     throw (uno::RuntimeException, awt::MaxChildrenException)
266 {
267     mIdMap[ xChild ] = insertTab();
268     Box_Base::addChild( xChild );
269 }
270 
271 void SAL_CALL VCLXTabControl::removeChild( const uno::Reference< awt::XLayoutConstrains > &xChild )
272     throw (uno::RuntimeException)
273 {
274     removeTab( mIdMap[xChild] );
275     mIdMap[ xChild ] = -1;
276     Box_Base::removeChild( xChild );
277 }
278 
279 static void setChildrenVisible( uno::Reference < awt::XLayoutConstrains > xChild, bool visible )
280 {
281     uno::Reference< awt::XWindow > xWin( xChild, uno::UNO_QUERY);
282     if ( xWin.is() )
283     {
284         xWin->setVisible( visible );
285     }
286 
287     uno::Reference < awt::XLayoutContainer > xCont( xChild, uno::UNO_QUERY );
288     if ( xCont.is())
289     {
290         uno::Sequence< uno::Reference < awt::XLayoutConstrains > > children = xCont->getChildren();
291         for ( int i = 0; i < children.getLength(); i++ )
292         {
293             setChildrenVisible( children[i], visible );
294         }
295     }
296 }
297 
298 void SAL_CALL VCLXTabControl::allocateArea (awt::Rectangle const &area)
299     throw (uno::RuntimeException)
300 {
301 #ifndef __SUNPRO_CC
302     OSL_TRACE ("\n%s", __PRETTY_FUNCTION__);
303 #endif
304     maAllocation = area;
305 
306     TabControl *pTabControl = getTabControl();
307 
308 // FIXME: this is wrong. We just want to set tab controls pos/size for
309 // the tabs menu, otherwise, it gets events that should go to children
310 // (I guess we could solve this by making the tabcontrol as the actual
311 // XWindow parent of its children, when importing...)  Not sure about
312 // TabPage drawing... That doesn't work on gtk+; just ignoring that.
313 // LATER: Nah, the proper fix is to get the XWindow hierarchy
314 // straight.
315 
316 #if 0
317     setPosSize( area.X, area.Y, area.Width, area.Height, awt::PosSize::POSSIZE );
318 #else
319     awt::Size currentSize = getSize();
320     awt::Size requestedSize (area.Width, area.Height);
321 //    requestedSize.Height = getHeightForWidth( area.Width );
322 
323     awt::Size minimumSize = getMinimumSize();
324     if (requestedSize.Width < minimumSize.Width)
325         requestedSize.Width = minimumSize.Width;
326     if (requestedSize.Height < minimumSize.Height)
327         requestedSize.Height = minimumSize.Height;
328 
329     Size pageSize = static_cast<TabControl*> (GetWindow ())->GetTabPageSizePixel ();
330     awt::Size pageBasedSize (0, 0);
331     pageBasedSize.Width = pageSize.Width ();
332     pageBasedSize.Height = pageSize.Height ();
333 
334     const int wc = 0;
335     const int hc = 20;
336     static int pwc = 0;
337     static int phc = 40;
338 
339     if (requestedSize.Width < pageBasedSize.Width)
340         requestedSize.Width = pageBasedSize.Width + wc;
341     if (requestedSize.Height < pageBasedSize.Height)
342         requestedSize.Height = pageBasedSize.Height + hc;
343 
344     Size windowSize = GetWindow()->GetSizePixel();
345     Window *parent = GetWindow()->GetParent();
346     Size parentSize = parent->GetSizePixel();
347 
348 #ifndef __SUNPRO_CC
349 #ifdef GCC_MAJOR
350     OSL_TRACE ("\n%s", __PRETTY_FUNCTION__);
351 #endif /* GCC_MAJOR */
352     OSL_TRACE ("%s: cursize: %d ,%d", __FUNCTION__, currentSize.Width, currentSize.Height );
353     OSL_TRACE ("%s: area: %d, %d", __FUNCTION__, area.Width, area.Height );
354     OSL_TRACE ("%s: minimum: %d, %d", __FUNCTION__, minimumSize.Width, minimumSize.Height );
355     OSL_TRACE ("%s: requestedSize: %d, %d", __FUNCTION__, requestedSize.Width, requestedSize.Height );
356     OSL_TRACE ("%s: pageBasedSize: %d, %d", __FUNCTION__, pageBasedSize.Width, pageBasedSize.Height );
357 
358     //OSL_TRACE ("%s: parent: %d, %d", __FUNCTION__, parentSize.Width(), parentSize.Height() );
359     //OSL_TRACE ("%s: window: %d, %d", __FUNCTION__, windowSize.Width(), windowSize.Height() );
360 #endif
361 
362 	//bRealized = false;
363     if (!bRealized)
364     {
365         setPosSize( area.X, area.Y, requestedSize.Width, requestedSize.Height, awt::PosSize::POSSIZE );
366         bRealized = true;
367     }
368     else
369     {
370         if ( requestedSize.Width > currentSize.Width + 10)
371             setPosSize( 0, 0, requestedSize.Width, 0, awt::PosSize::WIDTH );
372         if ( requestedSize.Height > currentSize.Height + 10)
373             setPosSize( 0, 0, 0, requestedSize.Height, awt::PosSize::HEIGHT );
374     }
375 #endif
376 
377     if (pageBasedSize.Width > parentSize.Width ()
378         || pageBasedSize.Height > parentSize.Height ())
379         //parent->SetSizePixel ( Size (pageBasedSize.Width, pageBasedSize.Height));
380         //parent->SetSizePixel ( Size (pageBasedSize.Width + pwc, pageBasedSize.Height + phc));
381         parent->SetSizePixel ( Size (requestedSize.Width + pwc, requestedSize.Height + phc));
382 
383     // FIXME: we can save cycles by setting visibility more sensibly. Having
384     // it here does makes it easier when changing tabs (just needs a recalc())
385     unsigned i = 0;
386     for ( std::list<Box_Base::ChildData *>::const_iterator it
387               = maChildren.begin(); it != maChildren.end(); it++, i++ )
388     {
389         ChildData *child = static_cast<VCLXTabControl::ChildData*> ( *it );
390         uno::Reference
391               < awt::XLayoutConstrains > xChild( child->mxChild );
392         if ( xChild.is() )
393         {
394             uno::Reference< awt::XWindow > xWin( xChild, uno::UNO_QUERY );
395             bool active = (i+1 == (unsigned) getActiveTabID());
396 
397             // HACK: since our layout:: container don't implement XWindow, we have no easy
398             // way to set them invisible; lets just set all their children as such :P
399 #if 0
400             if ( xWin.is() )
401                 xWin->setVisible( active );
402 #else
403             setChildrenVisible( xChild, active );
404 #endif
405 
406             if ( active )
407             {
408                 ::Rectangle label_rect = pTabControl->GetTabBounds( sal::static_int_cast< sal_uInt16 >( i+1 ) );
409                 ::Rectangle page_rect = pTabControl->GetTabPageBounds( sal::static_int_cast< sal_uInt16 >( i+1 ) );
410 
411                 awt::Rectangle childRect;
412                 childRect.X = page_rect.Left();
413                 childRect.Y = SAL_MAX( label_rect.Bottom(), page_rect.Top() );
414                 childRect.Width = page_rect.Right() - page_rect.Left();
415                 childRect.Height = page_rect.Bottom() - childRect.Y;
416 
417                 allocateChildAt( xChild, childRect );
418             }
419         }
420     }
421 }
422 
423 awt::Size SAL_CALL VCLXTabControl::getMinimumSize()
424     throw(uno::RuntimeException)
425 {
426     awt::Size requestedSize = VCLXWindow::getMinimumSize();
427     awt::Size childrenSize( 0, 0 );
428 
429     TabControl* pTabControl = static_cast< TabControl* >( GetWindow() );
430     if ( !pTabControl )
431         return requestedSize;
432 
433     // calculate size to accomodate all children
434     unsigned i = 0;
435     for ( std::list<Box_Base::ChildData *>::const_iterator it
436               = maChildren.begin(); it != maChildren.end(); it++, i++ )
437     {
438         ChildData *child = static_cast<VCLXTabControl::ChildData*> ( *it );
439         if ( child->mxChild.is() )
440         {
441             // set the title prop here...
442             pTabControl->SetPageText( sal::static_int_cast< sal_uInt16 >( i+1 ), child->maTitle.getStr() );
443 
444             awt::Size childSize( child->mxChild->getMinimumSize() );
445             childrenSize.Width = SAL_MAX( childSize.Width, childrenSize.Width );
446             childrenSize.Height = SAL_MAX( childSize.Height, childrenSize.Height );
447         }
448     }
449 
450 #ifndef __SUNPRO_CC
451 #ifdef GCC_MAJOR
452     OSL_TRACE ("\n%s", __PRETTY_FUNCTION__);
453 #endif /* GCC_MAJOR */
454     OSL_TRACE ("%s: children: %d", __FUNCTION__, i);
455     OSL_TRACE ("%s: childrenSize: %d, %d", __FUNCTION__, childrenSize.Width, childrenSize.Height );
456 #endif
457 
458     requestedSize.Width += childrenSize.Width;
459     requestedSize.Height += childrenSize.Height + 20;
460 
461     maRequisition = requestedSize;
462     return requestedSize;
463 }
464 
465 void VCLXTabControl::ProcessWindowEvent( const VclWindowEvent& _rVclWindowEvent )
466 {
467     ::vos::OClearableGuard aGuard( GetMutex() );
468     TabControl* pTabControl = static_cast< TabControl* >( GetWindow() );
469     if ( !pTabControl )
470         return;
471 
472     switch ( _rVclWindowEvent.GetId() )
473     {
474         case VCLEVENT_TABPAGE_ACTIVATE:
475             forceRecalc();
476         case VCLEVENT_TABPAGE_DEACTIVATE:
477         case VCLEVENT_TABPAGE_INSERTED:
478         case VCLEVENT_TABPAGE_REMOVED:
479         case VCLEVENT_TABPAGE_REMOVEDALL:
480         case VCLEVENT_TABPAGE_PAGETEXTCHANGED:
481         {
482             sal_uLong page = (sal_uLong) _rVclWindowEvent.GetData();
483             for ( std::list< uno::Reference
484                       < awt::XTabListener > >::iterator it
485                       = mxTabListeners.begin(); it != mxTabListeners.end(); it++)
486             {
487                 uno::Reference
488                     < awt::XTabListener > listener = *it;
489 
490                 switch ( _rVclWindowEvent.GetId() )
491                 {
492 
493                     case VCLEVENT_TABPAGE_ACTIVATE:
494                         listener->activated( page );
495                         break;
496                     case VCLEVENT_TABPAGE_DEACTIVATE:
497                         listener->deactivated( page );
498                         break;
499                     case VCLEVENT_TABPAGE_INSERTED:
500                         listener->inserted( page );
501                         break;
502                     case VCLEVENT_TABPAGE_REMOVED:
503                         listener->removed( page );
504                         break;
505                     case VCLEVENT_TABPAGE_REMOVEDALL:
506                         for ( int i = 1; i < mTabId; i++)
507                         {
508                             if ( pTabControl->GetTabPage( sal::static_int_cast< sal_uInt16 >( i ) ) )
509                                 listener->removed( i );
510                         }
511                         break;
512                     case VCLEVENT_TABPAGE_PAGETEXTCHANGED:
513                         listener->changed( page, getTabProps( page ) );
514                         break;
515                 }
516             }
517             break;
518         }
519         default:
520             aGuard.clear();
521             VCLXWindow::ProcessWindowEvent( _rVclWindowEvent );
522             break;
523     }
524 }
525 
526 void SAL_CALL VCLXTabControl::setProperty( const ::rtl::OUString& PropertyName, const uno::Any &Value ) throw(uno::RuntimeException)
527 {
528     VCLXWindow::setProperty( PropertyName, Value );
529 }
530 
531 uno::Any SAL_CALL VCLXTabControl::getProperty( const ::rtl::OUString& PropertyName ) throw(uno::RuntimeException)
532 {
533     return VCLXWindow::getProperty( PropertyName );
534 }
535 
536 } // namespace layoutimpl
537