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( ) 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
getTabControl() const122 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
insertTab()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
removeTab(sal_Int32 ID)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
activateTab(sal_Int32 ID)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
getActiveTabID()156 sal_Int32 SAL_CALL VCLXTabControl::getActiveTabID() throw (uno::RuntimeException)
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 ) 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
removeTabListener(const uno::Reference<awt::XTabListener> & xListener)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
setTabProps(sal_Int32 ID,const uno::Sequence<NamedValue> & Properties)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
getTabProps(sal_Int32 ID)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
draw(sal_Int32 nX,sal_Int32 nY)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
AddChild(uno::Reference<awt::XLayoutConstrains> const & xChild)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
addChild(const uno::Reference<awt::XLayoutConstrains> & xChild)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
removeChild(const uno::Reference<awt::XLayoutConstrains> & xChild)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
setChildrenVisible(uno::Reference<awt::XLayoutConstrains> xChild,bool visible)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
allocateArea(awt::Rectangle const & area)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
getMinimumSize()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
ProcessWindowEvent(const VclWindowEvent & _rVclWindowEvent)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
setProperty(const::rtl::OUString & PropertyName,const uno::Any & Value)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
getProperty(const::rtl::OUString & PropertyName)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