1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_extensions.hxx"
30 #include "browserlistbox.hxx"
31 #ifndef EXTENSIONS_PROPRESID_HRC
32 #include "propresid.hrc"
34 #include "proplinelistener.hxx"
35 #include "propcontrolobserver.hxx"
36 #include "linedescriptor.hxx"
37 #include "inspectorhelpwindow.hxx"
39 /** === begin UNO includes === **/
40 #include <com/sun/star/lang/DisposedException.hpp>
41 #include <com/sun/star/lang/XComponent.hpp>
42 #include <com/sun/star/inspection/PropertyControlType.hpp>
43 /** === end UNO includes === **/
44 #include <tools/debug.hxx>
45 #include <tools/diagnose_ex.h>
46 #include <comphelper/asyncnotification.hxx>
47 #include <cppuhelper/implbase1.hxx>
48 #include <vcl/svapp.hxx>
49 #include <vos/mutex.hxx>
51 //............................................................................
54 //............................................................................
56 #define FRAME_OFFSET 4
57 // TODO: find out what this is really for ... and check if it does make sense in the new
58 // browser environment
59 #define LAYOUT_HELP_WINDOW_DISTANCE_APPFONT 3
61 /** === begin UNO using === **/
62 using ::com::sun::star::uno::Any
;
63 using ::com::sun::star::uno::Exception
;
64 using ::com::sun::star::inspection::XPropertyControlContext
;
65 using ::com::sun::star::uno::Reference
;
66 using ::com::sun::star::inspection::XPropertyControl
;
67 using ::com::sun::star::uno::RuntimeException
;
68 using ::com::sun::star::lang::DisposedException
;
69 using ::com::sun::star::lang::XComponent
;
70 using ::com::sun::star::uno::UNO_QUERY
;
71 using ::com::sun::star::graphic::XGraphic
;
72 /** === end UNO using === **/
73 namespace PropertyControlType
= ::com::sun::star::inspection::PropertyControlType
;
75 //==================================================================
77 //==================================================================
85 struct ControlEvent
: public ::comphelper::AnyEvent
87 Reference
< XPropertyControl
> xControl
;
88 ControlEventType eType
;
90 ControlEvent( const Reference
< XPropertyControl
>& _rxControl
, ControlEventType _eType
)
91 :xControl( _rxControl
)
97 //==================================================================
99 //==================================================================
103 static ::osl::Mutex
& getMutex();
104 static ::rtl::Reference
< ::comphelper::AsyncEventNotifier
> s_pNotifier
;
107 static const ::rtl::Reference
< ::comphelper::AsyncEventNotifier
>&
111 SharedNotifier(); // never implemented
112 SharedNotifier( const SharedNotifier
& ); // never implemented
113 SharedNotifier
& operator=( const SharedNotifier
& ); // never implemented
116 //------------------------------------------------------------------
117 ::rtl::Reference
< ::comphelper::AsyncEventNotifier
> SharedNotifier::s_pNotifier
;
119 //------------------------------------------------------------------
120 ::osl::Mutex
& SharedNotifier::getMutex()
122 static ::osl::Mutex s_aMutex
;
126 //------------------------------------------------------------------
127 const ::rtl::Reference
< ::comphelper::AsyncEventNotifier
>& SharedNotifier::getNotifier()
129 ::osl::MutexGuard
aGuard( getMutex() );
130 if ( !s_pNotifier
.is() )
132 s_pNotifier
.set( new ::comphelper::AsyncEventNotifier
);
133 s_pNotifier
->create();
138 //==================================================================
139 //= PropertyControlContext_Impl
140 //==================================================================
141 /** implementation for of <type scope="com::sun::star::inspection">XPropertyControlContext</type>
142 which forwards all events to a non-UNO version of this interface
144 typedef ::cppu::WeakImplHelper1
< XPropertyControlContext
> PropertyControlContext_Impl_Base
;
145 class PropertyControlContext_Impl
:public PropertyControlContext_Impl_Base
146 ,public ::comphelper::IEventProcessor
156 IControlContext
* m_pContext
;
157 NotifcationMode m_eMode
;
160 /** creates an instance
162 the instance to delegate events to
164 PropertyControlContext_Impl( IControlContext
& _rContextImpl
);
166 /** disposes the context.
168 When you call this method, all subsequent callbacks to the
169 <type scope="com::sun::star::inspection">XPropertyControlContext</type> methods
170 will throw a <type scope="com::sun::star::lang">DisposedException</type>.
172 void SAL_CALL
dispose();
174 /** sets the notification mode, so that notifications recieved from the controls are
175 forwarded to our IControlContext either synchronously or asynchronously
177 the new notification mode
179 void setNotificationMode( NotifcationMode _eMode
);
181 virtual void SAL_CALL
acquire() throw();
182 virtual void SAL_CALL
release() throw();
185 ~PropertyControlContext_Impl();
187 // XPropertyControlObserver
188 virtual void SAL_CALL
focusGained( const Reference
< XPropertyControl
>& Control
) throw (RuntimeException
);
189 virtual void SAL_CALL
valueChanged( const Reference
< XPropertyControl
>& Control
) throw (RuntimeException
);
190 // XPropertyControlContext
191 virtual void SAL_CALL
activateNextControl( const Reference
< XPropertyControl
>& CurrentControl
) throw (RuntimeException
);
194 virtual void processEvent( const ::comphelper::AnyEvent
& _rEvent
);
197 /** processes the given event, i.e. notifies it to our IControlContext
201 our mutex (well, the SolarMutex) is locked
203 void impl_processEvent_throw( const ::comphelper::AnyEvent
& _rEvent
);
205 /** checks whether we're alive
207 @throws DisposedException
208 if the instance is already disposed
210 void impl_checkAlive_throw() const;
212 /** checks whether the instance is already disposed
214 bool impl_isDisposed_nothrow() const { return m_pContext
== NULL
; }
216 /** notifies the given event originating from the given control
217 @throws DisposedException
221 void impl_notify_throw( const Reference
< XPropertyControl
>& _rxControl
, ControlEventType _eType
);
224 //--------------------------------------------------------------------
225 PropertyControlContext_Impl::PropertyControlContext_Impl( IControlContext
& _rContextImpl
)
226 :m_pContext( &_rContextImpl
)
227 ,m_eMode( eAsynchronously
)
231 //--------------------------------------------------------------------
232 PropertyControlContext_Impl::~PropertyControlContext_Impl()
234 if ( !impl_isDisposed_nothrow() )
238 //--------------------------------------------------------------------
239 void PropertyControlContext_Impl::impl_checkAlive_throw() const
241 if ( impl_isDisposed_nothrow() )
242 throw DisposedException( ::rtl::OUString(), *const_cast< PropertyControlContext_Impl
* >( this ) );
245 //--------------------------------------------------------------------
246 void SAL_CALL
PropertyControlContext_Impl::dispose()
248 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
249 if ( impl_isDisposed_nothrow() )
252 SharedNotifier::getNotifier()->removeEventsForProcessor( this );
256 //--------------------------------------------------------------------
257 void PropertyControlContext_Impl::setNotificationMode( NotifcationMode _eMode
)
259 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
263 //--------------------------------------------------------------------
264 void PropertyControlContext_Impl::impl_notify_throw( const Reference
< XPropertyControl
>& _rxControl
, ControlEventType _eType
)
266 ::comphelper::AnyEventRef pEvent
;
269 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
270 impl_checkAlive_throw();
271 pEvent
= new ControlEvent( _rxControl
, _eType
);
273 if ( m_eMode
== eSynchronously
)
275 impl_processEvent_throw( *pEvent
);
280 SharedNotifier::getNotifier()->addEvent( pEvent
, this );
283 //--------------------------------------------------------------------
284 void SAL_CALL
PropertyControlContext_Impl::focusGained( const Reference
< XPropertyControl
>& Control
) throw (RuntimeException
)
286 DBG_TRACE( "PropertyControlContext_Impl: FOCUS_GAINED" );
287 impl_notify_throw( Control
, FOCUS_GAINED
);
290 //--------------------------------------------------------------------
291 void SAL_CALL
PropertyControlContext_Impl::valueChanged( const Reference
< XPropertyControl
>& Control
) throw (RuntimeException
)
293 DBG_TRACE( "PropertyControlContext_Impl: VALUE_CHANGED" );
294 impl_notify_throw( Control
, VALUE_CHANGED
);
297 //--------------------------------------------------------------------
298 void SAL_CALL
PropertyControlContext_Impl::activateNextControl( const Reference
< XPropertyControl
>& CurrentControl
) throw (RuntimeException
)
300 DBG_TRACE( "PropertyControlContext_Impl: ACTIVATE_NEXT" );
301 impl_notify_throw( CurrentControl
, ACTIVATE_NEXT
);
304 //--------------------------------------------------------------------
305 void SAL_CALL
PropertyControlContext_Impl::acquire() throw()
307 PropertyControlContext_Impl_Base::acquire();
310 //--------------------------------------------------------------------
311 void SAL_CALL
PropertyControlContext_Impl::release() throw()
313 PropertyControlContext_Impl_Base::release();
316 //--------------------------------------------------------------------
317 void PropertyControlContext_Impl::processEvent( const ::comphelper::AnyEvent
& _rEvent
)
319 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
320 if ( impl_isDisposed_nothrow() )
325 impl_processEvent_throw( _rEvent
);
327 catch( const Exception
& )
329 // can't handle otherwise, since our caller (the notification thread) does not allow
330 // for exceptions (it could itself abort only)
331 DBG_UNHANDLED_EXCEPTION();
335 //--------------------------------------------------------------------
336 void PropertyControlContext_Impl::impl_processEvent_throw( const ::comphelper::AnyEvent
& _rEvent
)
338 const ControlEvent
& rControlEvent
= static_cast< const ControlEvent
& >( _rEvent
);
339 switch ( rControlEvent
.eType
)
342 DBG_TRACE( "PropertyControlContext_Impl::processEvent: FOCUS_GAINED" );
343 m_pContext
->focusGained( rControlEvent
.xControl
);
346 DBG_TRACE( "PropertyControlContext_Impl::processEvent: VALUE_CHANGED" );
347 m_pContext
->valueChanged( rControlEvent
.xControl
);
350 DBG_TRACE( "PropertyControlContext_Impl::processEvent: ACTIVATE_NEXT" );
351 m_pContext
->activateNextControl( rControlEvent
.xControl
);
356 //==================================================================
358 //==================================================================
359 DBG_NAME(OBrowserListBox
)
360 //------------------------------------------------------------------
361 OBrowserListBox::OBrowserListBox( Window
* pParent
, WinBits nWinStyle
)
362 :Control(pParent
, nWinStyle
| WB_CLIPCHILDREN
)
363 ,m_aLinesPlayground(this,WB_DIALOGCONTROL
| WB_CLIPCHILDREN
)
364 ,m_aVScroll(this,WB_VSCROLL
|WB_REPEAT
|WB_DRAG
)
365 ,m_pHelpWindow( new InspectorHelpWindow( this ) )
366 ,m_pLineListener(NULL
)
367 ,m_pControlObserver( NULL
)
369 ,m_nCurrentPreferredHelpHeight(0)
371 ,m_bIsActive(sal_False
)
373 ,m_pControlContextImpl( new PropertyControlContext_Impl( *this ) )
375 DBG_CTOR(OBrowserListBox
,NULL
);
377 ListBox
aListBox(this,WB_DROPDOWN
);
378 aListBox
.SetPosSizePixel(Point(0,0),Size(100,100));
379 m_nRowHeight
= (sal_uInt16
)aListBox
.GetSizePixel().Height()+2;
380 SetBackground( pParent
->GetBackground() );
381 m_aLinesPlayground
.SetBackground( GetBackground() );
383 m_aLinesPlayground
.SetPosPixel(Point(0,0));
384 m_aLinesPlayground
.SetPaintTransparent(sal_True
);
385 m_aLinesPlayground
.Show();
387 m_aVScroll
.SetScrollHdl(LINK(this, OBrowserListBox
, ScrollHdl
));
390 //------------------------------------------------------------------
391 OBrowserListBox::~OBrowserListBox()
393 OSL_ENSURE( !IsModified(), "OBrowserListBox::~OBrowserListBox: still modified - should have been committed before!" );
394 // doing the commit here, while we, as well as our owner, as well as some other components,
395 // are already "half dead" (means within their dtor) is potentially dangerous.
396 // By definition, CommitModified has to be called (if necessary) before destruction
397 // #105868# - 2002-12-13 - fs@openoffice.org
399 m_pControlContextImpl
->dispose();
400 m_pControlContextImpl
.clear();
405 DBG_DTOR(OBrowserListBox
,NULL
);
408 //------------------------------------------------------------------
409 sal_Bool
OBrowserListBox::IsModified( ) const
411 sal_Bool bModified
= sal_False
;
413 if ( m_bIsActive
&& m_xActiveControl
.is() )
414 bModified
= m_xActiveControl
->isModified();
419 //------------------------------------------------------------------
420 void OBrowserListBox::CommitModified( )
422 if ( IsModified() && m_xActiveControl
.is() )
424 // for the time of this commit, notify all events synchronously
425 // #i63814# / 2006-03-31 / frank.schoenheit@sun.com
426 m_pControlContextImpl
->setNotificationMode( PropertyControlContext_Impl::eSynchronously
);
429 m_xActiveControl
->notifyModifiedValue();
431 catch( const Exception
& )
433 DBG_UNHANDLED_EXCEPTION();
435 m_pControlContextImpl
->setNotificationMode( PropertyControlContext_Impl::eAsynchronously
);
439 //------------------------------------------------------------------
440 void OBrowserListBox::ActivateListBox(sal_Bool _bActive
)
442 m_bIsActive
= _bActive
;
445 // TODO: what's the sense of this?
446 m_aVScroll
.SetThumbPos(100);
452 //------------------------------------------------------------------
453 long OBrowserListBox::impl_getPrefererredHelpHeight()
455 return HasHelpSection() ? m_pHelpWindow
->GetOptimalHeightPixel() : 0;
458 //------------------------------------------------------------------
459 void OBrowserListBox::Resize()
461 Rectangle
aPlayground( Point( 0, 0 ), GetOutputSizePixel() );
462 Size
aHelpWindowDistance( LogicToPixel( Size( 0, LAYOUT_HELP_WINDOW_DISTANCE_APPFONT
), MAP_APPFONT
) );
464 long nHelpWindowHeight
= m_nCurrentPreferredHelpHeight
= impl_getPrefererredHelpHeight();
465 bool bPositionHelpWindow
= ( nHelpWindowHeight
!= 0 );
467 Rectangle
aLinesArea( aPlayground
);
468 if ( bPositionHelpWindow
)
470 aLinesArea
.Bottom() -= nHelpWindowHeight
;
471 aLinesArea
.Bottom() -= aHelpWindowDistance
.Height();
473 m_aLinesPlayground
.SetPosSizePixel( aLinesArea
.TopLeft(), aLinesArea
.GetSize() );
477 sal_Bool bNeedScrollbar
= m_aOrderedLines
.size() > (sal_uInt32
)CalcVisibleLines();
478 if ( !bNeedScrollbar
)
480 if ( m_aVScroll
.IsVisible() )
484 m_aVScroll
.SetThumbPos( 0 );
488 Size
aVScrollSize( m_aVScroll
.GetSizePixel() );
490 // adjust the playground's width
491 aLinesArea
.Right() -= aVScrollSize
.Width();
492 m_aLinesPlayground
.SetPosSizePixel( aLinesArea
.TopLeft(), aLinesArea
.GetSize() );
494 // position the scrollbar
495 aVScrollSize
.Height() = aLinesArea
.GetHeight();
496 Point
aVScrollPos( aLinesArea
.GetWidth(), 0 );
497 m_aVScroll
.SetPosSizePixel( aVScrollPos
, aVScrollSize
);
500 for ( sal_uInt16 i
= 0; i
< m_aOrderedLines
.size(); ++i
)
501 m_aOutOfDateLines
.insert( i
);
504 EnablePaint(sal_False
);
506 EnablePaint(sal_True
);
508 // show the scrollbar
509 if ( bNeedScrollbar
)
512 // position the help window
513 if ( bPositionHelpWindow
)
515 Rectangle
aHelpArea( aPlayground
);
516 aHelpArea
.Top() = aLinesArea
.Bottom() + aHelpWindowDistance
.Height();
517 m_pHelpWindow
->SetPosSizePixel( aHelpArea
.TopLeft(), aHelpArea
.GetSize() );
521 //------------------------------------------------------------------
522 void OBrowserListBox::SetListener( IPropertyLineListener
* _pListener
)
524 m_pLineListener
= _pListener
;
527 //------------------------------------------------------------------
528 void OBrowserListBox::SetObserver( IPropertyControlObserver
* _pObserver
)
530 m_pControlObserver
= _pObserver
;
533 //------------------------------------------------------------------
534 void OBrowserListBox::EnableHelpSection( bool _bEnable
)
536 m_pHelpWindow
->Show( _bEnable
);
540 //------------------------------------------------------------------
541 bool OBrowserListBox::HasHelpSection() const
543 return m_pHelpWindow
->IsVisible();
546 //------------------------------------------------------------------
547 void OBrowserListBox::SetHelpText( const ::rtl::OUString
& _rHelpText
)
549 OSL_ENSURE( HasHelpSection(), "OBrowserListBox::SetHelpText: help section not visible!" );
550 m_pHelpWindow
->SetText( _rHelpText
);
551 if ( m_nCurrentPreferredHelpHeight
!= impl_getPrefererredHelpHeight() )
555 //------------------------------------------------------------------
556 void OBrowserListBox::SetHelpLineLimites( sal_Int32 _nMinLines
, sal_Int32 _nMaxLines
)
558 m_pHelpWindow
->SetLimits( _nMinLines
, _nMaxLines
);
561 //------------------------------------------------------------------
562 sal_uInt16
OBrowserListBox::CalcVisibleLines()
564 Size
aSize(m_aLinesPlayground
.GetOutputSizePixel());
565 sal_uInt16 nResult
= 0;
566 if (0 != m_nRowHeight
)
567 nResult
= (sal_uInt16
) aSize
.Height()/m_nRowHeight
;
572 //------------------------------------------------------------------
573 void OBrowserListBox::UpdateVScroll()
575 sal_uInt16 nLines
= CalcVisibleLines();
576 m_aVScroll
.SetPageSize(nLines
-1);
577 m_aVScroll
.SetVisibleSize(nLines
-1);
579 size_t nCount
= m_aLines
.size();
582 m_aVScroll
.SetRange(Range(0,nCount
-1));
583 m_nYOffset
= -m_aVScroll
.GetThumbPos()*m_nRowHeight
;
587 m_aVScroll
.SetRange(Range(0,0));
592 //------------------------------------------------------------------
593 void OBrowserListBox::PositionLine( sal_uInt16 _nIndex
)
595 Size
aSize(m_aLinesPlayground
.GetOutputSizePixel());
596 Point
aPos(0, m_nYOffset
);
598 aSize
.Height() = m_nRowHeight
;
600 aPos
.Y() += _nIndex
* m_nRowHeight
;
602 if ( _nIndex
< m_aOrderedLines
.size() )
604 m_aOrderedLines
[ _nIndex
]->second
.pLine
->SetPosSizePixel( aPos
, aSize
);
606 m_aOrderedLines
[ _nIndex
]->second
.pLine
->SetTitleWidth( m_nTheNameSize
+ 2 * FRAME_OFFSET
);
608 // show the line if necessary
609 if ( !m_aOrderedLines
[ _nIndex
]->second
.pLine
->IsVisible() )
610 m_aOrderedLines
[ _nIndex
]->second
.pLine
->Show();
614 //------------------------------------------------------------------
615 void OBrowserListBox::UpdatePosNSize()
617 for ( ::std::set
< sal_uInt16
>::const_iterator aLoop
= m_aOutOfDateLines
.begin();
618 aLoop
!= m_aOutOfDateLines
.end();
622 DBG_ASSERT( *aLoop
< m_aOrderedLines
.size(), "OBrowserListBox::UpdatePosNSize: invalid line index!" );
623 if ( *aLoop
< m_aOrderedLines
.size() )
624 PositionLine( *aLoop
);
626 m_aOutOfDateLines
.clear();
629 //------------------------------------------------------------------
630 void OBrowserListBox::UpdatePlayGround()
632 sal_Int32 nThumbPos
= m_aVScroll
.GetThumbPos();
633 sal_Int32 nLines
= CalcVisibleLines();
635 sal_uInt16 nEnd
= (sal_uInt16
)(nThumbPos
+ nLines
);
636 if (nEnd
>= m_aOrderedLines
.size())
637 nEnd
= (sal_uInt16
)m_aOrderedLines
.size()-1;
639 if ( !m_aOrderedLines
.empty() )
641 for ( sal_uInt16 i
= (sal_uInt16
)nThumbPos
; i
<= nEnd
; ++i
)
642 m_aOutOfDateLines
.insert( i
);
647 //------------------------------------------------------------------
648 void OBrowserListBox::UpdateAll()
653 //------------------------------------------------------------------
654 void OBrowserListBox::DisableUpdate()
656 m_bUpdate
= sal_False
;
659 //------------------------------------------------------------------
660 void OBrowserListBox::EnableUpdate()
662 m_bUpdate
= sal_True
;
666 //------------------------------------------------------------------
667 void OBrowserListBox::SetPropertyValue(const ::rtl::OUString
& _rEntryName
, const Any
& _rValue
, bool _bUnknownValue
)
669 ListBoxLines::iterator line
= m_aLines
.find( _rEntryName
);
670 if ( line
!= m_aLines
.end() )
672 if ( _bUnknownValue
)
674 Reference
< XPropertyControl
> xControl( line
->second
.pLine
->getControl() );
675 OSL_ENSURE( xControl
.is(), "OBrowserListBox::SetPropertyValue: illegal control!" );
677 xControl
->setValue( Any() );
680 impl_setControlAsPropertyValue( line
->second
, _rValue
);
684 //------------------------------------------------------------------------
685 sal_uInt16
OBrowserListBox::GetPropertyPos( const ::rtl::OUString
& _rEntryName
) const
687 sal_uInt16 nRet
= LISTBOX_ENTRY_NOTFOUND
;
688 for ( OrderedListBoxLines::const_iterator linePos
= m_aOrderedLines
.begin();
689 linePos
!= m_aOrderedLines
.end();
693 if ( (*linePos
)->first
== _rEntryName
)
695 nRet
= (sal_uInt16
)( linePos
- m_aOrderedLines
.begin() );
703 //------------------------------------------------------------------------
704 bool OBrowserListBox::impl_getBrowserLineForName( const ::rtl::OUString
& _rEntryName
, BrowserLinePointer
& _out_rpLine
) const
706 ListBoxLines::const_iterator line
= m_aLines
.find( _rEntryName
);
707 if ( line
!= m_aLines
.end() )
708 _out_rpLine
= line
->second
.pLine
;
711 return ( NULL
!= _out_rpLine
.get() );
714 //------------------------------------------------------------------------
715 void OBrowserListBox::EnablePropertyControls( const ::rtl::OUString
& _rEntryName
, sal_Int16 _nControls
, bool _bEnable
)
717 BrowserLinePointer pLine
;
718 if ( impl_getBrowserLineForName( _rEntryName
, pLine
) )
719 pLine
->EnablePropertyControls( _nControls
, _bEnable
);
722 //------------------------------------------------------------------------
723 void OBrowserListBox::EnablePropertyLine( const ::rtl::OUString
& _rEntryName
, bool _bEnable
)
725 BrowserLinePointer pLine
;
726 if ( impl_getBrowserLineForName( _rEntryName
, pLine
) )
727 pLine
->EnablePropertyLine( _bEnable
);
730 //------------------------------------------------------------------------
731 Reference
< XPropertyControl
> OBrowserListBox::GetPropertyControl( const ::rtl::OUString
& _rEntryName
)
733 BrowserLinePointer pLine
;
734 if ( impl_getBrowserLineForName( _rEntryName
, pLine
) )
735 return pLine
->getControl();
739 //------------------------------------------------------------------
740 sal_uInt16
OBrowserListBox::InsertEntry(const OLineDescriptor
& _rPropertyData
, sal_uInt16 _nPos
)
743 BrowserLinePointer
pBrowserLine( new OBrowserLine( _rPropertyData
.sName
, &m_aLinesPlayground
) );
745 ListBoxLine
aNewLine( pBrowserLine
, _rPropertyData
.xPropertyHandler
);
746 ::std::pair
< ListBoxLines::iterator
, bool > insertPoint
=
747 m_aLines
.insert( ListBoxLines::value_type( _rPropertyData
.sName
, aNewLine
) );
748 OSL_ENSURE( insertPoint
.second
, "OBrowserListBox::InsertEntry: already have another line for this name!" );
750 sal_uInt16 nInsertPos
= _nPos
;
751 if ( nInsertPos
> m_aOrderedLines
.size() )
752 nInsertPos
= EDITOR_LIST_APPEND
;
753 if ( EDITOR_LIST_APPEND
== nInsertPos
)
755 nInsertPos
= (sal_uInt16
)m_aOrderedLines
.size();
756 m_aOrderedLines
.push_back( insertPoint
.first
);
759 m_aOrderedLines
.insert( m_aOrderedLines
.begin() + nInsertPos
, insertPoint
.first
);
761 pBrowserLine
->SetTitleWidth(m_nTheNameSize
);
768 // initialize the entry
769 ChangeEntry(_rPropertyData
, nInsertPos
);
771 // update the positions of possibly affected lines
772 sal_uInt16 nUpdatePos
= nInsertPos
;
773 while ( nUpdatePos
< m_aOrderedLines
.size() )
774 m_aOutOfDateLines
.insert( nUpdatePos
++ );
780 //------------------------------------------------------------------
781 sal_Int32
OBrowserListBox::GetMinimumWidth()
783 return m_nTheNameSize
+ 2 * FRAME_OFFSET
+ (m_nRowHeight
- 4) * 8;
786 //------------------------------------------------------------------
787 sal_Int32
OBrowserListBox::GetMinimumHeight()
789 // assume that we want to display 5 rows, at least
790 sal_Int32 nMinHeight
= m_nRowHeight
* 5;
792 if ( HasHelpSection() )
794 Size
aHelpWindowDistance( LogicToPixel( Size( 0, LAYOUT_HELP_WINDOW_DISTANCE_APPFONT
), MAP_APPFONT
) );
795 nMinHeight
+= aHelpWindowDistance
.Height();
797 nMinHeight
+= m_pHelpWindow
->GetMinimalHeightPixel();
803 //------------------------------------------------------------------
804 void OBrowserListBox::ShowEntry(sal_uInt16 _nPos
)
806 if ( _nPos
< m_aOrderedLines
.size() )
808 sal_Int32 nThumbPos
= m_aVScroll
.GetThumbPos();
810 if (_nPos
< nThumbPos
)
814 sal_Int32 nLines
= CalcVisibleLines();
815 if (_nPos
>= nThumbPos
+ nLines
)
816 MoveThumbTo(_nPos
- nLines
+ 1);
822 //------------------------------------------------------------------
823 void OBrowserListBox::MoveThumbTo(sal_Int32 _nNewThumbPos
)
825 // disable painting to prevent flicker
826 m_aLinesPlayground
.EnablePaint(sal_False
);
828 sal_Int32 nDelta
= _nNewThumbPos
- m_aVScroll
.GetThumbPos();
829 // adjust the scrollbar
830 m_aVScroll
.SetThumbPos(_nNewThumbPos
);
831 sal_Int32 nThumbPos
= _nNewThumbPos
;
833 m_nYOffset
= -m_aVScroll
.GetThumbPos() * m_nRowHeight
;
835 sal_Int32 nLines
= CalcVisibleLines();
836 sal_uInt16 nEnd
= (sal_uInt16
)(nThumbPos
+ nLines
);
838 m_aLinesPlayground
.Scroll(0, -nDelta
* m_nRowHeight
, SCROLL_CHILDREN
);
842 // TODO: what's the sense of this two PositionLines? Why not just one call?
843 PositionLine(nEnd
-1);
846 else if (-1 == nDelta
)
848 PositionLine((sal_uInt16
)nThumbPos
);
850 else if (0 != nDelta
)
855 m_aLinesPlayground
.EnablePaint(sal_True
);
856 m_aLinesPlayground
.Invalidate(INVALIDATE_CHILDREN
);
859 //------------------------------------------------------------------
860 IMPL_LINK(OBrowserListBox
, ScrollHdl
, ScrollBar
*, _pScrollBar
)
862 DBG_ASSERT(_pScrollBar
== &m_aVScroll
, "OBrowserListBox::ScrollHdl: where does this come from?");
865 // disable painting to prevent flicker
866 m_aLinesPlayground
.EnablePaint(sal_False
);
868 sal_Int32 nThumbPos
= m_aVScroll
.GetThumbPos();
870 sal_Int32 nDelta
= m_aVScroll
.GetDelta();
871 m_nYOffset
= -nThumbPos
* m_nRowHeight
;
873 sal_uInt16 nEnd
= (sal_uInt16
)(nThumbPos
+ CalcVisibleLines());
875 m_aLinesPlayground
.Scroll(0, -nDelta
* m_nRowHeight
, SCROLL_CHILDREN
);
879 PositionLine(nEnd
-1);
884 PositionLine((sal_uInt16
)nThumbPos
);
886 else if (nDelta
!=0 || m_aVScroll
.GetType() == SCROLL_DONTKNOW
)
891 m_aLinesPlayground
.EnablePaint(sal_True
);
895 //------------------------------------------------------------------
896 void OBrowserListBox::buttonClicked( OBrowserLine
* _pLine
, sal_Bool _bPrimary
)
898 DBG_ASSERT( _pLine
, "OBrowserListBox::buttonClicked: invalid browser line!" );
899 if ( _pLine
&& m_pLineListener
)
901 m_pLineListener
->Clicked( _pLine
->GetEntryName(), _bPrimary
);
905 //------------------------------------------------------------------
906 void OBrowserListBox::impl_setControlAsPropertyValue( const ListBoxLine
& _rLine
, const Any
& _rPropertyValue
)
908 Reference
< XPropertyControl
> xControl( _rLine
.pLine
->getControl() );
911 if ( _rPropertyValue
.getValueType().equals( _rLine
.pLine
->getControl()->getValueType() ) )
913 xControl
->setValue( _rPropertyValue
);
918 if ( !_rLine
.xHandler
.is() )
920 ::rtl::OString
sMessage( "OBrowserListBox::impl_setControlAsPropertyValue: no handler -> no conversion (property: '" );
921 ::rtl::OUString
sPropertyName( _rLine
.pLine
->GetEntryName() );
922 sMessage
+= ::rtl::OString( sPropertyName
.getStr(), sPropertyName
.getLength(), RTL_TEXTENCODING_ASCII_US
);
923 sMessage
+= ::rtl::OString( "')!" );
924 DBG_ERROR( sMessage
);
927 if ( _rLine
.xHandler
.is() )
929 Any aControlValue
= _rLine
.xHandler
->convertToControlValue(
930 _rLine
.pLine
->GetEntryName(), _rPropertyValue
, xControl
->getValueType() );
931 xControl
->setValue( aControlValue
);
935 catch( const Exception
& )
937 DBG_UNHANDLED_EXCEPTION();
941 //------------------------------------------------------------------
942 Any
OBrowserListBox::impl_getControlAsPropertyValue( const ListBoxLine
& _rLine
) const
944 Reference
< XPropertyControl
> xControl( _rLine
.pLine
->getControl() );
949 if ( !_rLine
.xHandler
.is() )
951 ::rtl::OString
sMessage( "OBrowserListBox::impl_getControlAsPropertyValue: no handler -> no conversion (property: '" );
952 ::rtl::OUString
sPropertyName( _rLine
.pLine
->GetEntryName() );
953 sMessage
+= ::rtl::OString( sPropertyName
.getStr(), sPropertyName
.getLength(), RTL_TEXTENCODING_ASCII_US
);
954 sMessage
+= ::rtl::OString( "')!" );
955 DBG_ERROR( sMessage
);
958 if ( _rLine
.xHandler
.is() )
959 aPropertyValue
= _rLine
.xHandler
->convertToPropertyValue( _rLine
.pLine
->GetEntryName(), xControl
->getValue() );
961 aPropertyValue
= xControl
->getValue();
963 catch( const Exception
& )
965 DBG_UNHANDLED_EXCEPTION();
967 return aPropertyValue
;
970 //------------------------------------------------------------------
971 sal_uInt16
OBrowserListBox::impl_getControlPos( const Reference
< XPropertyControl
>& _rxControl
) const
973 for ( OrderedListBoxLines::const_iterator search
= m_aOrderedLines
.begin();
974 search
!= m_aOrderedLines
.end();
977 if ( (*search
)->second
.pLine
->getControl().get() == _rxControl
.get() )
978 return sal_uInt16( search
- m_aOrderedLines
.begin() );
979 DBG_ERROR( "OBrowserListBox::impl_getControlPos: invalid control - not part of any of our lines!" );
980 return (sal_uInt16
)-1;
983 //--------------------------------------------------------------------
984 void SAL_CALL
OBrowserListBox::focusGained( const Reference
< XPropertyControl
>& _rxControl
) throw (RuntimeException
)
986 DBG_TESTSOLARMUTEX();
988 DBG_ASSERT( _rxControl
.is(), "OBrowserListBox::focusGained: invalid event source!" );
989 if ( !_rxControl
.is() )
992 if ( m_pControlObserver
)
993 m_pControlObserver
->focusGained( _rxControl
);
995 m_xActiveControl
= _rxControl
;
996 ShowEntry( impl_getControlPos( m_xActiveControl
) );
999 //--------------------------------------------------------------------
1000 void SAL_CALL
OBrowserListBox::valueChanged( const Reference
< XPropertyControl
>& _rxControl
) throw (RuntimeException
)
1002 DBG_TESTSOLARMUTEX();
1004 DBG_ASSERT( _rxControl
.is(), "OBrowserListBox::valueChanged: invalid event source!" );
1005 if ( !_rxControl
.is() )
1008 if ( m_pControlObserver
)
1009 m_pControlObserver
->valueChanged( _rxControl
);
1011 if ( m_pLineListener
)
1013 const ListBoxLine
& rLine
= impl_getControlLine( _rxControl
);
1014 m_pLineListener
->Commit(
1015 rLine
.pLine
->GetEntryName(),
1016 impl_getControlAsPropertyValue( rLine
)
1021 //--------------------------------------------------------------------
1022 void SAL_CALL
OBrowserListBox::activateNextControl( const Reference
< XPropertyControl
>& _rxCurrentControl
) throw (RuntimeException
)
1024 DBG_TESTSOLARMUTEX();
1026 sal_uInt16 nLine
= impl_getControlPos( _rxCurrentControl
);
1028 // cycle forwards, 'til we've the next control which can grab the focus
1030 while ( (size_t)nLine
< m_aOrderedLines
.size() )
1032 if ( m_aOrderedLines
[nLine
]->second
.pLine
->GrabFocus() )
1037 if ( ( (size_t)nLine
>= m_aOrderedLines
.size() )
1038 && ( m_aOrderedLines
.size() > 0 )
1041 m_aOrderedLines
[0]->second
.pLine
->GrabFocus();
1044 //------------------------------------------------------------------
1047 //..............................................................
1048 void lcl_implDisposeControl_nothrow( const Reference
< XPropertyControl
>& _rxControl
)
1050 if ( !_rxControl
.is() )
1054 _rxControl
->setControlContext( NULL
);
1055 Reference
< XComponent
> xControlComponent( _rxControl
, UNO_QUERY
);
1056 if ( xControlComponent
.is() )
1057 xControlComponent
->dispose();
1059 catch( const Exception
& )
1061 DBG_UNHANDLED_EXCEPTION();
1066 //------------------------------------------------------------------
1067 void OBrowserListBox::Clear()
1069 for ( ListBoxLines::iterator loop
= m_aLines
.begin();
1070 loop
!= m_aLines
.end();
1075 loop
->second
.pLine
->Hide();
1076 // reset the listener
1077 lcl_implDisposeControl_nothrow( loop
->second
.pLine
->getControl() );
1080 clearContainer( m_aLines
);
1081 clearContainer( m_aOrderedLines
);
1084 //------------------------------------------------------------------
1085 sal_Bool
OBrowserListBox::RemoveEntry( const ::rtl::OUString
& _rName
)
1087 sal_uInt16 nPos
= GetPropertyPos( _rName
);
1088 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
1091 OrderedListBoxLines::iterator orderedPos
= m_aOrderedLines
.begin() + nPos
;
1092 BrowserLinePointer pLine
= (*orderedPos
)->second
.pLine
;
1094 lcl_implDisposeControl_nothrow( pLine
->getControl() );
1096 m_aLines
.erase( *orderedPos
);
1097 m_aOrderedLines
.erase( orderedPos
);
1098 m_aOutOfDateLines
.erase( (sal_uInt16
)m_aOrderedLines
.size() );
1099 // this index *may* have been out of date, which is obsoleted now by m_aOrderedLines shrinking
1101 // update the positions of possibly affected lines
1102 while ( nPos
< m_aOrderedLines
.size() )
1103 m_aOutOfDateLines
.insert( nPos
++ );
1109 //------------------------------------------------------------------
1110 void OBrowserListBox::ChangeEntry( const OLineDescriptor
& _rPropertyData
, sal_uInt16 nPos
)
1112 OSL_PRECOND( _rPropertyData
.Control
.is(), "OBrowserListBox::ChangeEntry: invalid control!" );
1113 if ( !_rPropertyData
.Control
.is() )
1116 if ( nPos
== EDITOR_LIST_REPLACE_EXISTING
)
1117 nPos
= GetPropertyPos( _rPropertyData
.sName
);
1119 if ( nPos
< m_aOrderedLines
.size() )
1121 Window
* pRefWindow
= NULL
;
1123 pRefWindow
= m_aOrderedLines
[nPos
-1]->second
.pLine
->GetRefWindow();
1125 // the current line and control
1126 ListBoxLine
& rLine
= m_aOrderedLines
[nPos
]->second
;
1128 // the old control and some data about it
1129 Reference
< XPropertyControl
> xControl
= rLine
.pLine
->getControl();
1130 Window
* pControlWindow
= rLine
.pLine
->getControlWindow();
1132 if ( pControlWindow
)
1133 aControlPos
= pControlWindow
->GetPosPixel();
1135 // clean up the old control
1136 lcl_implDisposeControl_nothrow( xControl
);
1138 // set the new control at the line
1139 rLine
.pLine
->setControl( _rPropertyData
.Control
);
1140 xControl
= rLine
.pLine
->getControl();
1142 if ( xControl
.is() )
1143 xControl
->setControlContext( m_pControlContextImpl
.get() );
1145 // the initial property value
1146 if ( _rPropertyData
.bUnknownValue
)
1147 xControl
->setValue( Any() );
1149 impl_setControlAsPropertyValue( rLine
, _rPropertyData
.aValue
);
1151 rLine
.pLine
->SetTitle(_rPropertyData
.DisplayName
);
1152 rLine
.xHandler
= _rPropertyData
.xPropertyHandler
;
1154 sal_uInt16 nTextWidth
= (sal_uInt16
)m_aLinesPlayground
.GetTextWidth(_rPropertyData
.DisplayName
);
1155 if (m_nTheNameSize
< nTextWidth
)
1156 m_nTheNameSize
= nTextWidth
;
1158 if ( _rPropertyData
.HasPrimaryButton
)
1160 if ( _rPropertyData
.PrimaryButtonImageURL
.getLength() )
1161 rLine
.pLine
->ShowBrowseButton( _rPropertyData
.PrimaryButtonImageURL
, true );
1162 else if ( _rPropertyData
.PrimaryButtonImage
.is() )
1163 rLine
.pLine
->ShowBrowseButton( Image( _rPropertyData
.PrimaryButtonImage
), true );
1165 rLine
.pLine
->ShowBrowseButton( true );
1167 if ( _rPropertyData
.HasSecondaryButton
)
1169 if ( _rPropertyData
.SecondaryButtonImageURL
.getLength() )
1170 rLine
.pLine
->ShowBrowseButton( _rPropertyData
.SecondaryButtonImageURL
, false );
1171 else if ( _rPropertyData
.SecondaryButtonImage
.is() )
1172 rLine
.pLine
->ShowBrowseButton( Image( _rPropertyData
.SecondaryButtonImage
), false );
1174 rLine
.pLine
->ShowBrowseButton( false );
1177 rLine
.pLine
->HideBrowseButton( false );
1179 rLine
.pLine
->SetClickListener( this );
1183 rLine
.pLine
->HideBrowseButton( true );
1184 rLine
.pLine
->HideBrowseButton( false );
1187 DBG_ASSERT( ( _rPropertyData
.IndentLevel
== 0 ) || ( _rPropertyData
.IndentLevel
== 1 ),
1188 "OBrowserListBox::ChangeEntry: unsupported indent level!" );
1189 rLine
.pLine
->IndentTitle( _rPropertyData
.IndentLevel
> 0 );
1192 rLine
.pLine
->SetTabOrder( pRefWindow
, WINDOW_ZORDER_BEHIND
);
1194 rLine
.pLine
->SetTabOrder( pRefWindow
, WINDOW_ZORDER_FIRST
);
1196 m_aOutOfDateLines
.insert( nPos
);
1197 rLine
.pLine
->SetComponentHelpIds(
1198 HelpIdUrl::getHelpId( _rPropertyData
.HelpURL
),
1199 rtl::OUStringToOString( _rPropertyData
.PrimaryButtonId
, RTL_TEXTENCODING_UTF8
),
1200 rtl::OUStringToOString( _rPropertyData
.SecondaryButtonId
, RTL_TEXTENCODING_UTF8
)
1203 if ( _rPropertyData
.bReadOnly
)
1205 rLine
.pLine
->SetReadOnly( true );
1207 // user controls (i.e. the ones not provided by the usual
1208 // XPropertyControlFactory) have no chance to know that they should be read-only,
1209 // since XPropertyHandler::describePropertyLine does not transport this
1211 // So, we manually switch this to read-only.
1212 if ( xControl
.is() && ( xControl
->getControlType() == PropertyControlType::Unknown
) )
1214 Edit
* pControlWindowAsEdit
= dynamic_cast< Edit
* >( rLine
.pLine
->getControlWindow() );
1215 if ( pControlWindowAsEdit
)
1216 pControlWindowAsEdit
->SetReadOnly( sal_True
);
1218 pControlWindowAsEdit
->Enable( sal_False
);
1224 //------------------------------------------------------------------
1225 long OBrowserListBox::PreNotify( NotifyEvent
& _rNEvt
)
1227 switch ( _rNEvt
.GetType() )
1229 case EVENT_KEYINPUT
:
1231 const KeyEvent
* pKeyEvent
= _rNEvt
.GetKeyEvent();
1232 if ( ( pKeyEvent
->GetKeyCode().GetModifier() != 0 )
1233 || ( ( pKeyEvent
->GetKeyCode().GetCode() != KEY_PAGEUP
)
1234 && ( pKeyEvent
->GetKeyCode().GetCode() != KEY_PAGEDOWN
)
1239 long nScrollOffset
= 0;
1240 if ( m_aVScroll
.IsVisible() )
1242 if ( pKeyEvent
->GetKeyCode().GetCode() == KEY_PAGEUP
)
1243 nScrollOffset
= -m_aVScroll
.GetPageSize();
1244 else if ( pKeyEvent
->GetKeyCode().GetCode() == KEY_PAGEDOWN
)
1245 nScrollOffset
= m_aVScroll
.GetPageSize();
1248 if ( nScrollOffset
)
1250 long nNewThumbPos
= m_aVScroll
.GetThumbPos() + nScrollOffset
;
1251 nNewThumbPos
= ::std::max( nNewThumbPos
, m_aVScroll
.GetRangeMin() );
1252 nNewThumbPos
= ::std::min( nNewThumbPos
, m_aVScroll
.GetRangeMax() );
1253 m_aVScroll
.DoScroll( nNewThumbPos
);
1254 nNewThumbPos
= m_aVScroll
.GetThumbPos();
1256 sal_uInt16 nFocusControlPos
= 0;
1257 sal_uInt16 nActiveControlPos
= impl_getControlPos( m_xActiveControl
);
1258 if ( nActiveControlPos
< nNewThumbPos
)
1259 nFocusControlPos
= (sal_uInt16
)nNewThumbPos
;
1260 else if ( nActiveControlPos
>= nNewThumbPos
+ CalcVisibleLines() )
1261 nFocusControlPos
= (sal_uInt16
)nNewThumbPos
+ CalcVisibleLines() - 1;
1262 if ( nFocusControlPos
)
1264 if ( nFocusControlPos
< m_aOrderedLines
.size() )
1266 m_aOrderedLines
[ nFocusControlPos
]->second
.pLine
->GrabFocus();
1269 OSL_ENSURE( false, "OBrowserListBox::PreNotify: internal error, invalid focus control position!" );
1274 // handled this. In particular, we also consume PageUp/Down events if we do not use them for scrolling,
1275 // otherwise they would be used to scroll the document view, which does not sound like it is desired by
1279 return Control::PreNotify( _rNEvt
);
1282 //------------------------------------------------------------------
1283 long OBrowserListBox::Notify( NotifyEvent
& _rNEvt
)
1285 switch ( _rNEvt
.GetType() )
1289 const CommandEvent
* pCommand
= _rNEvt
.GetCommandEvent();
1290 if ( ( COMMAND_WHEEL
== pCommand
->GetCommand() )
1291 || ( COMMAND_STARTAUTOSCROLL
== pCommand
->GetCommand() )
1292 || ( COMMAND_AUTOSCROLL
== pCommand
->GetCommand() )
1295 // interested in scroll events if we have a scrollbar
1296 if ( m_aVScroll
.IsVisible() )
1298 HandleScrollCommand( *pCommand
, NULL
, &m_aVScroll
);
1305 return Control::Notify( _rNEvt
);
1308 //............................................................................
1310 //............................................................................