xref: /trunk/main/vcl/source/window/arrange.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "precompiled_vcl.hxx"
29 
30 #include "svdata.hxx"
31 
32 #include "vcl/arrange.hxx"
33 #include "vcl/edit.hxx"
34 #include "vcl/svapp.hxx"
35 
36 #include "com/sun/star/beans/PropertyValue.hpp"
37 #include "com/sun/star/awt/Rectangle.hpp"
38 
39 #include "osl/diagnose.h"
40 
41 using namespace vcl;
42 using namespace com::sun::star;
43 
44 // ----------------------------------------
45 // vcl::WindowArranger
46 //-----------------------------------------
47 
48 long WindowArranger::getDefaultBorder()
49 {
50     ImplSVData* pSVData = ImplGetSVData();
51     long nResult = pSVData->maAppData.mnDefaultLayoutBorder;
52     if( nResult < 0 )
53     {
54         OutputDevice* pDefDev = Application::GetDefaultDevice();
55         if( pDefDev )
56         {
57             Size aBorder( pDefDev->LogicToPixel( Size( 3, 3 ), MapMode( MAP_APPFONT ) ) );
58             nResult = pSVData->maAppData.mnDefaultLayoutBorder = aBorder.Height();
59         }
60     }
61     return nResult > 0 ? nResult : 0;
62 }
63 
64 WindowArranger::~WindowArranger()
65 {}
66 
67 void WindowArranger::setParent( WindowArranger* i_pParent )
68 {
69     OSL_VERIFY( i_pParent->m_pParentWindow == m_pParentWindow || m_pParentWindow == NULL );
70 
71     m_pParentArranger = i_pParent;
72     m_pParentWindow = i_pParent->m_pParentWindow;
73     setParentWindow( m_pParentWindow );
74 }
75 
76 void WindowArranger::setParentWindow( Window* i_pNewParent )
77 {
78     m_pParentWindow = i_pNewParent;
79 
80     size_t nEle = countElements();
81     for( size_t i = 0; i < nEle; i++ )
82     {
83         Element* pEle = getElement( i );
84         if( pEle ) // sanity check
85         {
86             #if OSL_DEBUG_LEVEL > 0
87             if( pEle->m_pElement )
88             {
89                 OSL_VERIFY( pEle->m_pElement->GetParent() == i_pNewParent );
90             }
91             #endif
92             if( pEle->m_pChild )
93                 pEle->m_pChild->setParentWindow( i_pNewParent );
94         }
95     }
96 }
97 
98 void WindowArranger::show( bool i_bShow, bool i_bImmediateUpdate )
99 {
100     size_t nEle = countElements();
101     for( size_t i = 0; i < nEle; i++ )
102     {
103         Element* pEle = getElement( i );
104         if( pEle ) // sanity check
105         {
106             pEle->m_bHidden = ! i_bShow;
107             if( pEle->m_pElement )
108                 pEle->m_pElement->Show( i_bShow );
109             if( pEle->m_pChild.get() )
110                 pEle->m_pChild->show( i_bShow, false );
111         }
112     }
113     if( m_pParentArranger )
114     {
115         nEle = m_pParentArranger->countElements();
116         for( size_t i = 0; i < nEle; i++ )
117         {
118             Element* pEle = m_pParentArranger->getElement( i );
119             if( pEle && pEle->m_pChild.get() == this )
120             {
121                 pEle->m_bHidden = ! i_bShow;
122                 break;
123             }
124         }
125     }
126     if( i_bImmediateUpdate )
127     {
128         // find the topmost parent
129         WindowArranger* pResize = this;
130         while( pResize->m_pParentArranger )
131             pResize = pResize->m_pParentArranger;
132         pResize->resize();
133     }
134 }
135 
136 bool WindowArranger::isVisible() const
137 {
138     size_t nEle = countElements();
139     for( size_t i = 0; i < nEle; i++ )
140     {
141         const Element* pEle = getConstElement( i );
142         if( pEle->isVisible() )
143             return true;
144     }
145     return false;
146 }
147 
148 bool WindowArranger::Element::isVisible() const
149 {
150     bool bVisible = false;
151     if( ! m_bHidden )
152     {
153         if( m_pElement )
154             bVisible = m_pElement->IsVisible();
155         else if( m_pChild )
156             bVisible = m_pChild->isVisible();
157     }
158     return bVisible;
159 }
160 
161 sal_Int32 WindowArranger::Element::getExpandPriority() const
162 {
163     sal_Int32 nPrio = m_nExpandPriority;
164     if( m_pChild && m_nExpandPriority >= 0 )
165     {
166         size_t nElements = m_pChild->countElements();
167         for( size_t i = 0; i < nElements; i++ )
168         {
169             sal_Int32 nCPrio = m_pChild->getExpandPriority( i );
170             if( nCPrio > nPrio )
171                 nPrio = nCPrio;
172         }
173     }
174     return nPrio;
175 }
176 
177 Size WindowArranger::Element::getOptimalSize( WindowSizeType i_eType ) const
178 {
179     Size aResult;
180     if( ! m_bHidden )
181     {
182         bool bVisible = false;
183         if( m_pElement && m_pElement->IsVisible() )
184         {
185             aResult = m_pElement->GetOptimalSize( i_eType );
186             bVisible = true;
187         }
188         else if( m_pChild && m_pChild->isVisible() )
189         {
190             aResult = m_pChild->getOptimalSize( i_eType );
191             bVisible = true;
192         }
193         if( bVisible )
194         {
195             if( aResult.Width() < m_aMinSize.Width() )
196                 aResult.Width() = m_aMinSize.Width();
197             if( aResult.Height() < m_aMinSize.Height() )
198                 aResult.Height() = m_aMinSize.Height();
199             aResult.Width() += getBorderValue( m_nLeftBorder ) + getBorderValue( m_nRightBorder );
200             aResult.Height() += getBorderValue( m_nTopBorder ) + getBorderValue( m_nBottomBorder );
201         }
202     }
203 
204     return aResult;
205 }
206 
207 void WindowArranger::Element::setPosSize( const Point& i_rPos, const Size& i_rSize )
208 {
209     Point aPoint( i_rPos );
210     Size aSize( i_rSize );
211     aPoint.X() += getBorderValue( m_nLeftBorder );
212     aPoint.Y() += getBorderValue( m_nTopBorder );
213     aSize.Width() -= getBorderValue( m_nLeftBorder ) + getBorderValue( m_nRightBorder );
214     aSize.Height() -= getBorderValue( m_nTopBorder ) + getBorderValue( m_nBottomBorder );
215     if( m_pElement )
216         m_pElement->SetPosSizePixel( aPoint, aSize );
217     else if( m_pChild )
218         m_pChild->setManagedArea( Rectangle( aPoint, aSize ) );
219 }
220 
221 uno::Sequence< beans::PropertyValue > WindowArranger::getProperties() const
222 {
223     uno::Sequence< beans::PropertyValue > aRet( 3 );
224     aRet[0].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OuterBorder" ) );
225     aRet[0].Value = uno::makeAny( sal_Int32( getBorderValue( m_nOuterBorder ) ) );
226     aRet[1].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ManagedArea" ) );
227     awt::Rectangle aArea( m_aManagedArea.getX(), m_aManagedArea.getY(), m_aManagedArea.getWidth(), m_aManagedArea.getHeight() );
228     aRet[1].Value = uno::makeAny( aArea );
229     aRet[2].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Visible" ) );
230     aRet[2].Value = uno::makeAny( sal_Bool( isVisible() ) );
231     return aRet;
232 }
233 
234 void WindowArranger::setProperties( const uno::Sequence< beans::PropertyValue >& i_rProps )
235 {
236     const beans::PropertyValue* pProps = i_rProps.getConstArray();
237     bool bResize = false;
238     for( sal_Int32 i = 0; i < i_rProps.getLength(); i++ )
239     {
240         if( pProps[i].Name.equalsAscii( "OuterBorder" ) )
241         {
242             sal_Int32 nVal = 0;
243             if( pProps[i].Value >>= nVal )
244             {
245                 if( getBorderValue( m_nOuterBorder ) != nVal )
246                 {
247                     m_nOuterBorder = nVal;
248                     bResize = true;
249                 }
250             }
251         }
252         else if( pProps[i].Name.equalsAscii( "ManagedArea" ) )
253         {
254             awt::Rectangle aArea( 0, 0, 0, 0 );
255             if( pProps[i].Value >>= aArea )
256             {
257                 m_aManagedArea.setX( aArea.X );
258                 m_aManagedArea.setY( aArea.Y );
259                 m_aManagedArea.setWidth( aArea.Width );
260                 m_aManagedArea.setHeight( aArea.Height );
261                 bResize = true;
262             }
263         }
264         else if( pProps[i].Name.equalsAscii( "Visible" ) )
265         {
266             sal_Bool bVal = sal_False;
267             if( pProps[i].Value >>= bVal )
268             {
269                 show( bVal, false );
270                 bResize = true;
271             }
272         }
273     }
274     if( bResize )
275         resize();
276 }
277 
278 
279 // ----------------------------------------
280 // vcl::RowOrColumn
281 //-----------------------------------------
282 
283 RowOrColumn::~RowOrColumn()
284 {
285     for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin();
286          it != m_aElements.end(); ++it )
287     {
288         it->deleteChild();
289     }
290 }
291 
292 Size RowOrColumn::getOptimalSize( WindowSizeType i_eType ) const
293 {
294     Size aRet( 0, 0 );
295     long nDistance = getBorderValue( m_nBorderWidth );
296     for( std::vector< WindowArranger::Element >::const_iterator it = m_aElements.begin();
297          it != m_aElements.end(); ++it )
298     {
299         if( it->isVisible() )
300         {
301             // get the size of type of the managed element
302             Size aElementSize( it->getOptimalSize( i_eType ) );
303             if( m_bColumn )
304             {
305                 // add the distance between elements
306                 aRet.Height() += nDistance;
307                 // check if the width needs adjustment
308                 if( aRet.Width() < aElementSize.Width() )
309                     aRet.Width() = aElementSize.Width();
310                 aRet.Height() += aElementSize.Height();
311             }
312             else
313             {
314                 // add the distance between elements
315                 aRet.Width() += nDistance;
316                 // check if the height needs adjustment
317                 if( aRet.Height() < aElementSize.Height() )
318                     aRet.Height() = aElementSize.Height();
319                 aRet.Width() += aElementSize.Width();
320             }
321         }
322     }
323 
324     if( aRet.Width() != 0 || aRet.Height() != 0 )
325     {
326         // subtract the border for the first element
327         if( m_bColumn )
328             aRet.Height() -= nDistance;
329         else
330             aRet.Width() -= nDistance;
331 
332         // add the outer border
333         long nOuterBorder = getBorderValue( m_nOuterBorder );
334         aRet.Width() += 2*nOuterBorder;
335         aRet.Height() += 2*nOuterBorder;
336     }
337 
338     return aRet;
339 }
340 
341 void RowOrColumn::distributeRowWidth( std::vector<Size>& io_rSizes, long /*i_nUsedWidth*/, long i_nExtraWidth )
342 {
343     if( ! io_rSizes.empty() && io_rSizes.size() == m_aElements.size() )
344     {
345         // find all elements with the highest expand priority
346         size_t nElements = m_aElements.size();
347         std::vector< size_t > aIndices;
348         sal_Int32 nHighPrio = 0;
349         for( size_t i = 0; i < nElements; i++ )
350         {
351             if( m_aElements[ i ].isVisible() )
352             {
353                 sal_Int32 nCurPrio = m_aElements[ i ].getExpandPriority();
354                 if( nCurPrio > nHighPrio )
355                 {
356                     aIndices.clear();
357                     nHighPrio = nCurPrio;
358                 }
359                 if( nCurPrio == nHighPrio )
360                     aIndices.push_back( i );
361             }
362         }
363 
364         // distribute extra space evenly among collected elements
365         nElements = aIndices.size();
366         if( nElements > 0 )
367         {
368             long nDelta = i_nExtraWidth / nElements;
369             for( size_t i = 0; i < nElements; i++ )
370             {
371                 io_rSizes[ aIndices[i] ].Width() += nDelta;
372                 i_nExtraWidth -= nDelta;
373             }
374             // add the last pixels to the last row element
375             if( i_nExtraWidth > 0 && nElements > 0 )
376                 io_rSizes[aIndices.back()].Width() += i_nExtraWidth;
377         }
378     }
379 }
380 
381 void RowOrColumn::distributeColumnHeight( std::vector<Size>& io_rSizes, long /*i_nUsedHeight*/, long i_nExtraHeight )
382 {
383     if( ! io_rSizes.empty() && io_rSizes.size() == m_aElements.size() )
384     {
385         // find all elements with the highest expand priority
386         size_t nElements = m_aElements.size();
387         std::vector< size_t > aIndices;
388         sal_Int32 nHighPrio = 3;
389         for( size_t i = 0; i < nElements; i++ )
390         {
391             if( m_aElements[ i ].isVisible() )
392             {
393                 sal_Int32 nCurPrio = m_aElements[ i ].getExpandPriority();
394                 if( nCurPrio > nHighPrio )
395                 {
396                     aIndices.clear();
397                     nHighPrio = nCurPrio;
398                 }
399                 if( nCurPrio == nHighPrio )
400                     aIndices.push_back( i );
401             }
402         }
403 
404         // distribute extra space evenly among collected elements
405         nElements = aIndices.size();
406         if( nElements > 0 )
407         {
408             long nDelta = i_nExtraHeight / nElements;
409             for( size_t i = 0; i < nElements; i++ )
410             {
411                 io_rSizes[ aIndices[i] ].Height() += nDelta;
412                 i_nExtraHeight -= nDelta;
413             }
414             // add the last pixels to the last row element
415             if( i_nExtraHeight > 0 && nElements > 0 )
416                 io_rSizes[aIndices.back()].Height() += i_nExtraHeight;
417         }
418     }
419 }
420 
421 void RowOrColumn::resize()
422 {
423     // check if we can get optimal size, else fallback to minimal size
424     Size aOptSize( getOptimalSize( WINDOWSIZE_PREFERRED ) );
425     WindowSizeType eType = WINDOWSIZE_PREFERRED;
426     if( m_bColumn )
427     {
428         if( aOptSize.Height() > m_aManagedArea.GetHeight() )
429             eType = WINDOWSIZE_MINIMUM;
430     }
431     else
432     {
433         if( aOptSize.Width() > m_aManagedArea.GetWidth() )
434             eType = WINDOWSIZE_MINIMUM;
435     }
436 
437     size_t nElements = m_aElements.size();
438     // get all element sizes for sizing
439     std::vector<Size> aElementSizes( nElements );
440     long nDistance = getBorderValue( m_nBorderWidth );
441     long nOuterBorder = getBorderValue( m_nOuterBorder );
442     long nUsedWidth = 2*nOuterBorder - (nElements ? nDistance : 0);
443     for( size_t i = 0; i < nElements; i++ )
444     {
445         if( m_aElements[i].isVisible() )
446         {
447             aElementSizes[i] = m_aElements[i].getOptimalSize( eType );
448             if( m_bColumn )
449             {
450                 aElementSizes[i].Width() = m_aManagedArea.GetWidth() - 2 * nOuterBorder;
451                 nUsedWidth += aElementSizes[i].Height() + nDistance;
452             }
453             else
454             {
455                 aElementSizes[i].Height() = m_aManagedArea.GetHeight() - 2 * nOuterBorder;
456                 nUsedWidth += aElementSizes[i].Width() + nDistance;
457             }
458         }
459     }
460 
461     long nExtraWidth = (m_bColumn ? m_aManagedArea.GetHeight() : m_aManagedArea.GetWidth()) - nUsedWidth;
462     if( nExtraWidth > 0 )
463     {
464         if( m_bColumn )
465             distributeColumnHeight( aElementSizes, nUsedWidth, nExtraWidth );
466         else
467             distributeRowWidth( aElementSizes, nUsedWidth, nExtraWidth );
468     }
469 
470     // get starting position
471     Point aElementPos( m_aManagedArea.TopLeft() );
472     // outer border
473     aElementPos.X() += nOuterBorder;
474     aElementPos.Y() += nOuterBorder;
475 
476     // position managed windows
477     for( size_t i = 0; i < nElements; i++ )
478     {
479         // get the size of type of the managed element
480         if( m_aElements[i].isVisible() )
481         {
482             m_aElements[i].setPosSize( aElementPos, aElementSizes[i] );
483             if( m_bColumn )
484                 aElementPos.Y() += nDistance + aElementSizes[i].Height();
485             else
486                 aElementPos.X() += nDistance + aElementSizes[i].Width();
487         }
488     }
489 }
490 
491 size_t RowOrColumn::addWindow( Window* i_pWindow, sal_Int32 i_nExpandPrio, const Size& i_rMinSize, size_t i_nIndex )
492 {
493     size_t nIndex = i_nIndex;
494     if( i_nIndex >= m_aElements.size() )
495     {
496         nIndex = m_aElements.size();
497         m_aElements.push_back( WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio, i_rMinSize ) );
498     }
499     else
500     {
501         std::vector< WindowArranger::Element >::iterator it = m_aElements.begin();
502         while( i_nIndex-- )
503             ++it;
504         m_aElements.insert( it, WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio, i_rMinSize ) );
505     }
506     return nIndex;
507 }
508 
509 size_t RowOrColumn::addChild( boost::shared_ptr<WindowArranger> const & i_pChild, sal_Int32 i_nExpandPrio, size_t i_nIndex )
510 {
511     size_t nIndex = i_nIndex;
512     if( i_nIndex >= m_aElements.size() )
513     {
514         nIndex = m_aElements.size();
515         m_aElements.push_back( WindowArranger::Element( NULL, i_pChild, i_nExpandPrio ) );
516     }
517     else
518     {
519         std::vector< WindowArranger::Element >::iterator it = m_aElements.begin();
520         while( i_nIndex-- )
521             ++it;
522         m_aElements.insert( it, WindowArranger::Element( NULL, i_pChild, i_nExpandPrio ) );
523     }
524     return nIndex;
525 }
526 
527 void RowOrColumn::remove( Window* i_pWindow )
528 {
529     if( i_pWindow )
530     {
531         for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin();
532             it != m_aElements.end(); ++it )
533         {
534             if( it->m_pElement == i_pWindow )
535             {
536                 m_aElements.erase( it );
537                 return;
538             }
539         }
540     }
541 }
542 
543 void RowOrColumn::remove( boost::shared_ptr<WindowArranger> const & i_pChild )
544 {
545     if( i_pChild )
546     {
547         for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin();
548             it != m_aElements.end(); ++it )
549         {
550             if( it->m_pChild == i_pChild )
551             {
552                 m_aElements.erase( it );
553                 return;
554             }
555         }
556     }
557 }
558 
559 // ----------------------------------------
560 // vcl::LabeledElement
561 //-----------------------------------------
562 
563 LabeledElement::~LabeledElement()
564 {
565     m_aLabel.deleteChild();
566     m_aElement.deleteChild();
567 }
568 
569 Size LabeledElement::getOptimalSize( WindowSizeType i_eType ) const
570 {
571     Size aRet( m_aLabel.getOptimalSize( WINDOWSIZE_MINIMUM ) );
572     if( aRet.Width() != 0 )
573     {
574         if( m_nLabelColumnWidth != 0 )
575             aRet.Width() = m_nLabelColumnWidth;
576         else
577             aRet.Width() += getBorderValue( m_nDistance );
578     }
579     Size aElementSize( m_aElement.getOptimalSize( i_eType ) );
580     aRet.Width() += aElementSize.Width();
581     if( aElementSize.Height() > aRet.Height() )
582         aRet.Height() = aElementSize.Height();
583     if( aRet.Height() != 0 )
584         aRet.Height() += 2 * getBorderValue( m_nOuterBorder );
585 
586     return aRet;
587 }
588 
589 void LabeledElement::resize()
590 {
591     Size aLabelSize( m_aLabel.getOptimalSize( WINDOWSIZE_MINIMUM ) );
592     Size aElementSize( m_aElement.getOptimalSize( WINDOWSIZE_PREFERRED ) );
593     long nDistance = getBorderValue( m_nDistance );
594     long nOuterBorder = getBorderValue( m_nOuterBorder );
595     if( nDistance + aLabelSize.Width() + aElementSize.Width() > m_aManagedArea.GetWidth() )
596         aElementSize = m_aElement.getOptimalSize( WINDOWSIZE_MINIMUM );
597 
598     // align label and element vertically in LabeledElement
599     long nYOff = (m_aManagedArea.GetHeight() - 2*nOuterBorder - aLabelSize.Height()) / 2;
600     Point aPos( m_aManagedArea.Left(),
601                 m_aManagedArea.Top() + nOuterBorder + nYOff );
602     Size aSize( aLabelSize );
603     if( m_nLabelColumnWidth != 0 )
604         aSize.Width() = m_nLabelColumnWidth;
605     m_aLabel.setPosSize( aPos, aSize );
606 
607     aPos.X() += aSize.Width() + nDistance;
608     nYOff = (m_aManagedArea.GetHeight() - 2*nOuterBorder - aElementSize.Height()) / 2;
609     aPos.Y() = m_aManagedArea.Top() + nOuterBorder + nYOff;
610     aSize.Width() = aElementSize.Width();
611     aSize.Height() = m_aManagedArea.GetHeight() - 2*nOuterBorder;
612 
613     // label style
614     // 0: position left and right
615     // 1: keep the element close to label and grow it
616     // 2: keep the element close and don't grow it
617     if( m_nLabelStyle == 0)
618     {
619         if( aPos.X() + aSize.Width() < m_aManagedArea.Right() )
620             aPos.X() = m_aManagedArea.Right() - aSize.Width();
621     }
622     else if( m_nLabelStyle == 1 )
623     {
624         if( aPos.X() + aSize.Width() < m_aManagedArea.Right() )
625             aSize.Width() = m_aManagedArea.Right() - aPos.X();
626     }
627     m_aElement.setPosSize( aPos, aSize );
628 }
629 
630 void LabeledElement::setLabel( Window* i_pLabel )
631 {
632     m_aLabel.m_pElement = i_pLabel;
633     m_aLabel.m_pChild.reset();
634 }
635 
636 void LabeledElement::setLabel( boost::shared_ptr<WindowArranger> const & i_pLabel )
637 {
638     m_aLabel.m_pElement = NULL;
639     m_aLabel.m_pChild = i_pLabel;
640 }
641 
642 void LabeledElement::setElement( Window* i_pElement )
643 {
644     m_aElement.m_pElement = i_pElement;
645     m_aElement.m_pChild.reset();
646 }
647 
648 void LabeledElement::setElement( boost::shared_ptr<WindowArranger> const & i_pElement )
649 {
650     m_aElement.m_pElement = NULL;
651     m_aElement.m_pChild = i_pElement;
652 }
653 
654 // ----------------------------------------
655 // vcl::LabelColumn
656 //-----------------------------------------
657 LabelColumn::~LabelColumn()
658 {
659 }
660 
661 long LabelColumn::getLabelWidth() const
662 {
663     long nWidth = 0;
664 
665     size_t nEle = countElements();
666     for( size_t i = 0; i < nEle; i++ )
667     {
668         const Element* pEle = getConstElement( i );
669         if( pEle && pEle->m_pChild.get() )
670         {
671             const LabeledElement* pLabel = dynamic_cast< const LabeledElement* >(pEle->m_pChild.get());
672             if( pLabel )
673             {
674                 Window* pLW = pLabel->getWindow( 0 );
675                 if( pLW )
676                 {
677                     Size aLabSize( pLW->GetOptimalSize( WINDOWSIZE_MINIMUM ) );
678                     long nLB = 0;
679                     pLabel->getBorders(0, &nLB);
680                     aLabSize.Width() += getBorderValue( nLB );
681                     if( aLabSize.Width() > nWidth )
682                         nWidth = aLabSize.Width();
683                 }
684             }
685         }
686     }
687     return nWidth + getBorderValue( getBorderWidth() );
688 }
689 
690 Size LabelColumn::getOptimalSize( WindowSizeType i_eType ) const
691 {
692     long nWidth = getLabelWidth();
693     long nOuterBorder = getBorderValue( m_nOuterBorder );
694     Size aColumnSize;
695 
696     // every child is a LabeledElement
697     size_t nEle = countElements();
698     for( size_t i = 0; i < nEle; i++ )
699     {
700         Size aElementSize;
701         const Element* pEle = getConstElement( i );
702         if( pEle && pEle->m_pChild.get() )
703         {
704             const LabeledElement* pLabel = dynamic_cast< const LabeledElement* >(pEle->m_pChild.get());
705             if( pLabel ) // we have a label
706             {
707                 aElementSize = pLabel->getLabelSize( WINDOWSIZE_MINIMUM );
708                 if( aElementSize.Width() )
709                     aElementSize.Width() = nWidth;
710                 Size aSize( pLabel->getElementSize( i_eType ) );
711                 aElementSize.Width() += aSize.Width();
712                 if( aSize.Height() > aElementSize.Height() )
713                     aElementSize.Height() = aSize.Height();
714             }
715             else // a non label, just treat it as a row
716             {
717                 aElementSize = pEle->getOptimalSize( i_eType );
718             }
719         }
720         else if( pEle && pEle->m_pElement ) // a general window, treat is as a row
721         {
722             aElementSize = pEle->getOptimalSize( i_eType );
723         }
724         if( aElementSize.Width() )
725         {
726             aElementSize.Width() += 2*nOuterBorder;
727             if( aElementSize.Width() > aColumnSize.Width() )
728                 aColumnSize.Width() = aElementSize.Width();
729         }
730         if( aElementSize.Height() )
731         {
732             aColumnSize.Height() += getBorderValue( getBorderWidth() ) + aElementSize.Height();
733         }
734     }
735     if( nEle > 0 && aColumnSize.Height() )
736     {
737         aColumnSize.Height() -= getBorderValue( getBorderWidth() ); // for the first element
738         aColumnSize.Height() += 2*nOuterBorder;
739     }
740     return aColumnSize;
741 }
742 
743 void LabelColumn::resize()
744 {
745     long nWidth = getLabelWidth();
746     size_t nEle = countElements();
747     for( size_t i = 0; i < nEle; i++ )
748     {
749         Element* pEle = getElement( i );
750         if( pEle && pEle->m_pChild.get() )
751         {
752             LabeledElement* pLabel = dynamic_cast< LabeledElement* >(pEle->m_pChild.get());
753             if( pLabel )
754                 pLabel->setLabelColumnWidth( nWidth );
755         }
756     }
757     RowOrColumn::resize();
758 }
759 
760 size_t LabelColumn::addRow( Window* i_pLabel, boost::shared_ptr<WindowArranger> const& i_rElement, long i_nIndent )
761 {
762     boost::shared_ptr< LabeledElement > xLabel( new LabeledElement( this, 1 ) );
763     xLabel->setLabel( i_pLabel );
764     xLabel->setBorders( 0, i_nIndent, 0, 0, 0 );
765     xLabel->setElement( i_rElement );
766     size_t nIndex = addChild( xLabel );
767     resize();
768     return nIndex;
769 }
770 
771 size_t LabelColumn::addRow( Window* i_pLabel, Window* i_pElement, long i_nIndent, const Size& i_rElementMinSize )
772 {
773     boost::shared_ptr< LabeledElement > xLabel( new LabeledElement( this, 1 ) );
774     xLabel->setLabel( i_pLabel );
775     xLabel->setBorders( 0, i_nIndent, 0, 0, 0 );
776     xLabel->setElement( i_pElement );
777     xLabel->setMinimumSize( 1, i_rElementMinSize );
778     size_t nIndex = addChild( xLabel );
779     resize();
780     return nIndex;
781 }
782 
783 // ----------------------------------------
784 // vcl::Indenter
785 //-----------------------------------------
786 
787 Indenter::~Indenter()
788 {
789     m_aElement.deleteChild();
790 }
791 
792 Size Indenter::getOptimalSize( WindowSizeType i_eType ) const
793 {
794     Size aSize( m_aElement.getOptimalSize( i_eType ) );
795     long nOuterBorder = getBorderValue( m_nOuterBorder );
796     long nIndent = getBorderValue( m_nIndent );
797     aSize.Width()  += 2*nOuterBorder + nIndent;
798     aSize.Height() += 2*nOuterBorder;
799     return aSize;
800 }
801 
802 void Indenter::resize()
803 {
804     long nOuterBorder = getBorderValue( m_nOuterBorder );
805     long nIndent = getBorderValue( m_nIndent );
806     Point aPt( m_aManagedArea.TopLeft() );
807     aPt.X() += nOuterBorder + nIndent;
808     aPt.Y() += nOuterBorder;
809     Size aSz( m_aManagedArea.GetSize() );
810     aSz.Width()  -= 2*nOuterBorder + nIndent;
811     aSz.Height() -= 2*nOuterBorder;
812     m_aElement.setPosSize( aPt, aSz );
813 }
814 
815 void Indenter::setWindow( Window* i_pWindow, sal_Int32 i_nExpandPrio )
816 {
817     OSL_VERIFY( (m_aElement.m_pElement == 0 && m_aElement.m_pChild == 0) || i_pWindow == 0 );
818     OSL_VERIFY( i_pWindow == 0 || i_pWindow->GetParent() == m_pParentWindow );
819     m_aElement.m_pElement = i_pWindow;
820     m_aElement.m_nExpandPriority = i_nExpandPrio;
821 }
822 
823 void Indenter::setChild( boost::shared_ptr<WindowArranger> const & i_pChild, sal_Int32 i_nExpandPrio )
824 {
825     OSL_VERIFY( (m_aElement.m_pElement == 0 && m_aElement.m_pChild == 0 ) || i_pChild == 0 );
826     m_aElement.m_pChild = i_pChild;
827     m_aElement.m_nExpandPriority = i_nExpandPrio;
828 }
829 
830 // ----------------------------------------
831 // vcl::MatrixArranger
832 //-----------------------------------------
833 MatrixArranger::~MatrixArranger()
834 {
835 }
836 
837 Size MatrixArranger::getOptimalSize( WindowSizeType i_eType,
838                                      std::vector<long>& o_rColumnWidths, std::vector<long>& o_rRowHeights,
839                                      std::vector<sal_Int32>& o_rColumnPrio, std::vector<sal_Int32>& o_rRowPrio
840                                     ) const
841 {
842     long nOuterBorder = getBorderValue( m_nOuterBorder );
843     Size aMatrixSize( 2*nOuterBorder, 2*nOuterBorder );
844 
845     // first find out the current number of rows and columns
846     sal_uInt32 nRows = 0, nColumns = 0;
847     for( std::vector< MatrixElement >::const_iterator it = m_aElements.begin();
848             it != m_aElements.end(); ++it )
849     {
850         if( it->m_nX >= nColumns )
851             nColumns = it->m_nX+1;
852         if( it->m_nY >= nRows )
853             nRows = it->m_nY+1;
854     }
855 
856     // now allocate row and column depth vectors
857     o_rColumnWidths = std::vector< long >( nColumns, 0 );
858     o_rRowHeights   = std::vector< long >( nRows, 0 );
859     o_rColumnPrio   = std::vector< sal_Int32 >( nColumns, 0 );
860     o_rRowPrio      = std::vector< sal_Int32 >( nRows, 0 );
861 
862     // get sizes an allocate them into rows/columns
863     for( std::vector< MatrixElement >::const_iterator it = m_aElements.begin();
864             it != m_aElements.end(); ++it )
865     {
866         Size aSize( it->getOptimalSize( i_eType ) );
867         if( aSize.Width() > o_rColumnWidths[ it->m_nX ] )
868             o_rColumnWidths[ it->m_nX ] = aSize.Width();
869         if( aSize.Height() > o_rRowHeights[ it->m_nY ] )
870             o_rRowHeights[ it->m_nY ] = aSize.Height();
871         if( it->m_nExpandPriority > o_rColumnPrio[ it->m_nX ] )
872             o_rColumnPrio[ it->m_nX ] = it->m_nExpandPriority;
873         if( it->m_nExpandPriority > o_rRowPrio[ it->m_nY ] )
874             o_rRowPrio[ it->m_nY ] = it->m_nExpandPriority;
875     }
876 
877     // add up sizes
878     long nDistanceX = getBorderValue( m_nBorderX );
879     long nDistanceY = getBorderValue( m_nBorderY );
880     for( sal_uInt32 i = 0; i < nColumns; i++ )
881         aMatrixSize.Width() += o_rColumnWidths[i] + nDistanceX;
882     if( nColumns > 0 )
883         aMatrixSize.Width() -= nDistanceX;
884 
885     for( sal_uInt32 i = 0; i < nRows; i++ )
886         aMatrixSize.Height() += o_rRowHeights[i] + nDistanceY;
887     if( nRows > 0 )
888         aMatrixSize.Height() -= nDistanceY;
889 
890     return aMatrixSize;
891 }
892 
893 Size MatrixArranger::getOptimalSize( WindowSizeType i_eType ) const
894 {
895     std::vector<long> aColumnWidths, aRowHeights;
896     std::vector<sal_Int32> aColumnPrio, aRowPrio;
897     return getOptimalSize( i_eType, aColumnWidths, aRowHeights, aColumnPrio, aRowPrio );
898 }
899 
900 void MatrixArranger::distributeExtraSize( std::vector<long>& io_rSizes, const std::vector<sal_Int32>& i_rPrios, long i_nExtraWidth )
901 {
902     if( ! io_rSizes.empty()  && io_rSizes.size() == i_rPrios.size() ) // sanity check
903     {
904         // find all elements with the highest expand priority
905         size_t nElements = io_rSizes.size();
906         std::vector< size_t > aIndices;
907         sal_Int32 nHighPrio = 0;
908         for( size_t i = 0; i < nElements; i++ )
909         {
910             sal_Int32 nCurPrio = i_rPrios[ i ];
911             if( nCurPrio > nHighPrio )
912             {
913                 aIndices.clear();
914                 nHighPrio = nCurPrio;
915             }
916             if( nCurPrio == nHighPrio )
917                 aIndices.push_back( i );
918         }
919 
920         // distribute extra space evenly among collected elements
921         nElements = aIndices.size();
922         if( nElements > 0 )
923         {
924             long nDelta = i_nExtraWidth / nElements;
925             for( size_t i = 0; i < nElements; i++ )
926             {
927                 io_rSizes[ aIndices[i] ] += nDelta;
928                 i_nExtraWidth -= nDelta;
929             }
930             // add the last pixels to the last row element
931             if( i_nExtraWidth > 0 && nElements > 0 )
932                 io_rSizes[aIndices.back()] += i_nExtraWidth;
933         }
934     }
935 }
936 
937 
938 void MatrixArranger::resize()
939 {
940     // assure that we have at least one row and column
941     if( m_aElements.empty() )
942         return;
943 
944     // check if we can get optimal size, else fallback to minimal size
945     std::vector<long> aColumnWidths, aRowHeights;
946     std::vector<sal_Int32> aColumnPrio, aRowPrio;
947     Size aOptSize( getOptimalSize( WINDOWSIZE_PREFERRED, aColumnWidths, aRowHeights, aColumnPrio, aRowPrio ) );
948     if( aOptSize.Height() > m_aManagedArea.GetHeight() ||
949         aOptSize.Width() > m_aManagedArea.GetWidth() )
950     {
951         std::vector<long> aMinColumnWidths, aMinRowHeights;
952         getOptimalSize( WINDOWSIZE_MINIMUM, aMinColumnWidths, aMinRowHeights, aColumnPrio, aRowPrio );
953         if( aOptSize.Height() > m_aManagedArea.GetHeight() )
954             aRowHeights = aMinRowHeights;
955         if( aOptSize.Width() > m_aManagedArea.GetWidth() )
956             aColumnWidths = aMinColumnWidths;
957     }
958 
959     // distribute extra space available
960     long nExtraSize = m_aManagedArea.GetWidth();
961     for( size_t i = 0; i < aColumnWidths.size(); ++i )
962         nExtraSize -= aColumnWidths[i] + m_nBorderX;
963     if( nExtraSize > 0 )
964         distributeExtraSize( aColumnWidths, aColumnPrio, nExtraSize );
965     nExtraSize =  m_aManagedArea.GetHeight();
966     for( size_t i = 0; i < aRowHeights.size(); ++i )
967         nExtraSize -= aRowHeights[i] + m_nBorderY;
968     if( nExtraSize > 0 )
969         distributeExtraSize( aRowHeights, aRowPrio, nExtraSize );
970 
971     // prepare offsets
972     long nDistanceX = getBorderValue( m_nBorderX );
973     long nDistanceY = getBorderValue( m_nBorderY );
974     long nOuterBorder = getBorderValue( m_nOuterBorder );
975     std::vector<long> aColumnX( aColumnWidths.size() );
976     aColumnX[0] = m_aManagedArea.Left() + nOuterBorder;
977     for( size_t i = 1; i < aColumnX.size(); i++ )
978         aColumnX[i] = aColumnX[i-1] + aColumnWidths[i-1] + nDistanceX;
979 
980     std::vector<long> aRowY( aRowHeights.size() );
981     aRowY[0] = m_aManagedArea.Top() + nOuterBorder;
982     for( size_t i = 1; i < aRowY.size(); i++ )
983         aRowY[i] = aRowY[i-1] + aRowHeights[i-1] + nDistanceY;
984 
985     // now iterate over the elements and assign their positions
986     for( std::vector< MatrixElement >::iterator it = m_aElements.begin();
987          it != m_aElements.end(); ++it )
988     {
989         Point aCellPos( aColumnX[it->m_nX], aRowY[it->m_nY] );
990         Size  aCellSize( aColumnWidths[it->m_nX], aRowHeights[it->m_nY] );
991         it->setPosSize( aCellPos, aCellSize );
992     }
993 }
994 
995 size_t MatrixArranger::addWindow( Window* i_pWindow, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio, const Size& i_rMinSize )
996 {
997     sal_uInt64 nMapValue = getMap( i_nX, i_nY );
998     std::map< sal_uInt64, size_t >::const_iterator it = m_aMatrixMap.find( nMapValue );
999     size_t nIndex = 0;
1000     if( it == m_aMatrixMap.end() )
1001     {
1002         m_aMatrixMap[ nMapValue ] = nIndex = m_aElements.size();
1003         m_aElements.push_back( MatrixElement( i_pWindow, i_nX, i_nY, boost::shared_ptr<WindowArranger>(), i_nExpandPrio, i_rMinSize ) );
1004     }
1005     else
1006     {
1007         MatrixElement& rEle( m_aElements[ it->second ] );
1008         rEle.m_pElement = i_pWindow;
1009         rEle.m_pChild.reset();
1010         rEle.m_nExpandPriority = i_nExpandPrio;
1011         rEle.m_aMinSize = i_rMinSize;
1012         rEle.m_nX = i_nX;
1013         rEle.m_nY = i_nY;
1014         nIndex = it->second;
1015     }
1016     return nIndex;
1017 }
1018 
1019 void MatrixArranger::remove( Window* i_pWindow )
1020 {
1021     if( i_pWindow )
1022     {
1023         for( std::vector< MatrixElement >::iterator it = m_aElements.begin();
1024             it != m_aElements.end(); ++it )
1025         {
1026             if( it->m_pElement == i_pWindow )
1027             {
1028                 m_aMatrixMap.erase( getMap( it->m_nX, it->m_nY ) );
1029                 m_aElements.erase( it );
1030                 return;
1031             }
1032         }
1033     }
1034 }
1035 
1036 size_t MatrixArranger::addChild( boost::shared_ptr<WindowArranger> const &i_pChild, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio )
1037 {
1038     sal_uInt64 nMapValue = getMap( i_nX, i_nY );
1039     std::map< sal_uInt64, size_t >::const_iterator it = m_aMatrixMap.find( nMapValue );
1040     size_t nIndex = 0;
1041     if( it == m_aMatrixMap.end() )
1042     {
1043         m_aMatrixMap[ nMapValue ] = nIndex = m_aElements.size();
1044         m_aElements.push_back( MatrixElement( NULL, i_nX, i_nY, i_pChild, i_nExpandPrio ) );
1045     }
1046     else
1047     {
1048         MatrixElement& rEle( m_aElements[ it->second ] );
1049         rEle.m_pElement = 0;
1050         rEle.m_pChild = i_pChild;
1051         rEle.m_nExpandPriority = i_nExpandPrio;
1052         rEle.m_nX = i_nX;
1053         rEle.m_nY = i_nY;
1054         nIndex = it->second;
1055     }
1056     return nIndex;
1057 }
1058 
1059 void MatrixArranger::remove( boost::shared_ptr<WindowArranger> const &i_pChild )
1060 {
1061     if( i_pChild )
1062     {
1063         for( std::vector< MatrixElement >::iterator it = m_aElements.begin();
1064             it != m_aElements.end(); ++it )
1065         {
1066             if( it->m_pChild == i_pChild )
1067             {
1068                 m_aMatrixMap.erase( getMap( it->m_nX, it->m_nY ) );
1069                 m_aElements.erase( it );
1070                 return;
1071             }
1072         }
1073     }
1074 }
1075 
1076