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