xref: /trunk/main/svtools/source/control/toolbarmenu.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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 
29 // MARKER(update_precomp.py): autogen include statement, do not remove
30 #include "precompiled_svtools.hxx"
31 
32 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
33 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
34 #include <comphelper/processfactory.hxx>
35 
36 #include <vcl/dockwin.hxx>
37 #include <vcl/decoview.hxx>
38 #include <vcl/image.hxx>
39 #include <vcl/taskpanelist.hxx>
40 #include <vcl/toolbox.hxx>
41 
42 #include "svtools/valueset.hxx"
43 #include "svtools/toolbarmenu.hxx"
44 #include "toolbarmenuimp.hxx"
45 
46 using ::rtl::OUString;
47 using namespace ::com::sun::star::uno;
48 using namespace ::com::sun::star::lang;
49 using namespace ::com::sun::star::frame;
50 using namespace ::com::sun::star::accessibility;
51 
52 namespace svtools {
53 
54 // --------------------------------------------------------------------
55 
56 static Window* GetTopMostParentSystemWindow( Window* pWindow )
57 {
58     OSL_ASSERT( pWindow );
59     if ( pWindow )
60     {
61         // ->manually search topmost system window
62         // required because their might be another system window between this and the top window
63         pWindow = pWindow->GetParent();
64         SystemWindow* pTopMostSysWin = NULL;
65         while ( pWindow )
66         {
67             if ( pWindow->IsSystemWindow() )
68                 pTopMostSysWin = (SystemWindow*)pWindow;
69             pWindow = pWindow->GetParent();
70         }
71         pWindow = pTopMostSysWin;
72         OSL_ASSERT( pWindow );
73         return pWindow;
74     }
75 
76     return NULL;
77 }
78 
79 // --------------------------------------------------------------------
80 
81 void ToolbarMenuEntry::init( int nEntryId, MenuItemBits nBits )
82 {
83     mnEntryId = nEntryId;
84     mnBits = nBits;
85 
86     mbHasText = false;
87     mbHasImage = false;
88     mbChecked = false;
89     mbEnabled = true;
90 
91     mpControl = NULL;
92 }
93 
94 // --------------------------------------------------------------------
95 
96 ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const String& rText, MenuItemBits nBits )
97 : mrMenu( rMenu )
98 {
99     init( nEntryId, nBits );
100 
101     maText = rText;
102     mbHasText = true;
103 }
104 
105 // --------------------------------------------------------------------
106 
107 ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const Image& rImage, MenuItemBits nBits )
108 : mrMenu( rMenu )
109 {
110     init( nEntryId, nBits );
111 
112     maImage = rImage;
113     mbHasImage = true;
114 }
115 
116 // --------------------------------------------------------------------
117 
118 ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const Image& rImage, const String& rText, MenuItemBits nBits )
119 : mrMenu( rMenu )
120 {
121     init( nEntryId, nBits );
122 
123     maText = rText;
124     mbHasText = true;
125 
126     maImage = rImage;
127     mbHasImage = true;
128 }
129 
130 // --------------------------------------------------------------------
131 
132 ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, Control* pControl, MenuItemBits nBits )
133 : mrMenu( rMenu )
134 {
135     init( nEntryId, nBits );
136 
137     if( pControl )
138     {
139         mpControl = pControl;
140         mpControl->Show();
141     }
142 }
143 
144 // --------------------------------------------------------------------
145 
146 ToolbarMenuEntry::~ToolbarMenuEntry()
147 {
148     if( mxAccContext.is() )
149     {
150         Reference< XComponent > xComponent( mxAccContext, UNO_QUERY );
151         if( xComponent.is() )
152             xComponent->dispose();
153         mxAccContext.clear();
154     }
155     delete mpControl;
156 }
157 
158 // --------------------------------------------------------------------
159 
160 const Reference< XAccessibleContext >& ToolbarMenuEntry::GetAccessible( bool bCreate /* = false */ )
161 {
162     if( !mxAccContext.is() && bCreate )
163     {
164         if( mpControl )
165         {
166             mxAccContext = Reference< XAccessibleContext >( mpControl->GetAccessible( sal_True ), UNO_QUERY );
167         }
168         else
169         {
170             mxAccContext = Reference< XAccessibleContext >( new ToolbarMenuEntryAcc( this ) );
171         }
172     }
173 
174     return mxAccContext;
175 }
176 
177 // --------------------------------------------------------------------
178 
179 sal_Int32 ToolbarMenuEntry::getAccessibleChildCount() throw (RuntimeException)
180 {
181     if( mpControl )
182     {
183         const Reference< XAccessibleContext >& xContext = GetAccessible( true );
184         if( xContext.is() )
185         {
186             return xContext->getAccessibleChildCount();
187         }
188     }
189     return 1;
190 }
191 
192 // --------------------------------------------------------------------
193 
194 Reference< XAccessible > ToolbarMenuEntry::getAccessibleChild( sal_Int32 index ) throw (IndexOutOfBoundsException, RuntimeException)
195 {
196     const Reference< XAccessibleContext >& xContext = GetAccessible( true );
197     if( mpControl )
198     {
199         if( xContext.is() )
200         {
201             return xContext->getAccessibleChild(index);
202         }
203     }
204     else if( index == 0 )
205     {
206         Reference< XAccessible > xRet( xContext, UNO_QUERY );
207         if( xRet.is() )
208             return xRet;
209     }
210 
211     throw IndexOutOfBoundsException();
212 }
213 
214 // --------------------------------------------------------------------
215 
216 ToolbarMenu_Impl::ToolbarMenu_Impl( ToolbarMenu& rMenu, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame )
217 : mrMenu( rMenu )
218 , mxFrame( xFrame )
219 , mxServiceManager( ::comphelper::getProcessServiceFactory() )
220 , mnCheckPos(0)
221 , mnImagePos(0)
222 , mnTextPos(0)
223 , mnHighlightedEntry(-1)
224 , mnSelectedEntry(-1)
225 , mnLastColumn(0)
226 {
227 }
228 
229 // --------------------------------------------------------------------
230 
231 ToolbarMenu_Impl::~ToolbarMenu_Impl()
232 {
233     setAccessible( 0 );
234 }
235 
236 // --------------------------------------------------------------------
237 
238 void ToolbarMenu_Impl::setAccessible( ToolbarMenuAcc* pAccessible )
239 {
240     if( mxAccessible.get() != pAccessible )
241     {
242         if( mxAccessible.is() )
243             mxAccessible->dispose();
244 
245         mxAccessible.set( pAccessible );
246     }
247 }
248 
249 // -----------------------------------------------------------------------
250 
251 void ToolbarMenu_Impl::fireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue )
252 {
253     if( mxAccessible.is() )
254         mxAccessible->FireAccessibleEvent( nEventId, rOldValue, rNewValue );
255 }
256 
257 // -----------------------------------------------------------------------
258 
259 bool ToolbarMenu_Impl::hasAccessibleListeners()
260 {
261     return( mxAccessible.is() && mxAccessible->HasAccessibleListeners() );
262 }
263 
264 // --------------------------------------------------------------------
265 
266 sal_Int32 ToolbarMenu_Impl::getAccessibleChildCount() throw (RuntimeException)
267 {
268     sal_Int32 nCount = 0;
269     const int nEntryCount = maEntryVector.size();
270     for( int nEntry = 0; nEntry < nEntryCount; nEntry++ )
271     {
272         ToolbarMenuEntry* pEntry = maEntryVector[nEntry];
273         if( pEntry )
274         {
275             if( pEntry->mpControl )
276             {
277                 nCount += pEntry->getAccessibleChildCount();
278             }
279             else
280             {
281                 nCount += 1;
282             }
283         }
284     }
285 
286     return nCount;
287 }
288 
289 // --------------------------------------------------------------------
290 
291 Reference< XAccessible > ToolbarMenu_Impl::getAccessibleChild( sal_Int32 index ) throw (IndexOutOfBoundsException, RuntimeException)
292 {
293     const int nEntryCount = maEntryVector.size();
294     for( int nEntry = 0; nEntry < nEntryCount; nEntry++ )
295     {
296         ToolbarMenuEntry* pEntry = maEntryVector[nEntry];
297         if( pEntry )
298         {
299             const sal_Int32 nCount = pEntry->getAccessibleChildCount();
300             if( index < nCount )
301             {
302                 return pEntry->getAccessibleChild( index );
303             }
304             index -= nCount;
305         }
306     }
307 
308     throw IndexOutOfBoundsException();
309 }
310 
311 // --------------------------------------------------------------------
312 
313 Reference< XAccessible > ToolbarMenu_Impl::getAccessibleChild( Control* pControl, sal_Int32 childIndex ) throw (IndexOutOfBoundsException, RuntimeException)
314 {
315     const int nEntryCount = maEntryVector.size();
316     for( int nEntry = 0; nEntry < nEntryCount; nEntry++ )
317     {
318         ToolbarMenuEntry* pEntry = maEntryVector[nEntry];
319         if( pEntry && (pEntry->mpControl == pControl) )
320         {
321             return pEntry->getAccessibleChild( childIndex );
322         }
323     }
324 
325     throw IndexOutOfBoundsException();
326 }
327 
328 // --------------------------------------------------------------------
329 
330 void ToolbarMenu_Impl::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
331 {
332     const int nEntryCount = maEntryVector.size();
333     for( int nEntry = 0; nEntry < nEntryCount; nEntry++ )
334     {
335         ToolbarMenuEntry* pEntry = maEntryVector[nEntry];
336         if( pEntry )
337         {
338             const sal_Int32 nCount = pEntry->getAccessibleChildCount();
339             if( nChildIndex < nCount )
340             {
341                 if( pEntry->mpControl )
342                 {
343                     Reference< XAccessibleSelection > xSel( pEntry->GetAccessible(true), UNO_QUERY_THROW );
344                     xSel->selectAccessibleChild(nChildIndex);
345                 }
346                 else if( pEntry->mnEntryId != TITLE_ID )
347                 {
348                     mrMenu.implSelectEntry( nEntry );
349                 }
350                 return;
351             }
352             nChildIndex -= nCount;
353         }
354     }
355 
356     throw IndexOutOfBoundsException();
357 }
358 
359 // --------------------------------------------------------------------
360 
361 sal_Bool ToolbarMenu_Impl::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
362 {
363     const int nEntryCount = maEntryVector.size();
364     for( int nEntry = 0; nEntry < nEntryCount; nEntry++ )
365     {
366         ToolbarMenuEntry* pEntry = maEntryVector[nEntry];
367         if( pEntry )
368         {
369             const sal_Int32 nCount = pEntry->getAccessibleChildCount();
370             if( nChildIndex < nCount )
371             {
372                 if( mnHighlightedEntry == nEntry )
373                 {
374                     if( pEntry->mpControl )
375                     {
376                         Reference< XAccessibleSelection > xSel( pEntry->GetAccessible(true), UNO_QUERY_THROW );
377                         xSel->isAccessibleChildSelected(nChildIndex);
378                     }
379                     return true;
380                 }
381                 else
382                 {
383                     return false;
384                 }
385             }
386             nChildIndex -= nCount;
387         }
388     }
389 
390     throw IndexOutOfBoundsException();
391 }
392 
393 // --------------------------------------------------------------------
394 
395 void ToolbarMenu_Impl::clearAccessibleSelection()
396 {
397     if( mnHighlightedEntry != -1 )
398     {
399         mrMenu.implHighlightEntry( mnHighlightedEntry, false );
400         mnHighlightedEntry = -1;
401     }
402 }
403 
404 
405 // --------------------------------------------------------------------
406 
407 void ToolbarMenu_Impl::notifyHighlightedEntry()
408 {
409     if( hasAccessibleListeners() )
410     {
411         ToolbarMenuEntry* pEntry = implGetEntry( mnHighlightedEntry );
412         if( pEntry && pEntry->mbEnabled && (pEntry->mnEntryId != TITLE_ID) )
413         {
414             Any aNew;
415             Any aOld( mxOldSelection );
416             if( pEntry->mpControl )
417             {
418                 sal_Int32 nChildIndex = 0;
419                 // todo: if other controls than ValueSet are allowed, addapt this code
420                 ValueSet* pValueSet = dynamic_cast< ValueSet* >( pEntry->mpControl );
421                 if( pValueSet )
422                     nChildIndex = static_cast< sal_Int32 >( pValueSet->GetItemPos( pValueSet->GetSelectItemId() ) );
423 
424                 if( nChildIndex >= pEntry->getAccessibleChildCount() )
425                     return;
426 
427                 aNew <<= getAccessibleChild( pEntry->mpControl, nChildIndex );
428             }
429             else
430             {
431                 aNew <<= pEntry->GetAccessible(true);
432             }
433 
434             fireAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOld, aNew );
435             fireAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, aOld, aNew );
436             fireAccessibleEvent( AccessibleEventId::STATE_CHANGED, Any(), Any( AccessibleStateType::FOCUSED ) );
437             aNew >>= mxOldSelection;
438         }
439     }
440 }
441 
442 // --------------------------------------------------------------------
443 
444 ToolbarMenuEntry* ToolbarMenu_Impl::implGetEntry( int nEntry ) const
445 {
446     if( (nEntry < 0) || (nEntry >= (int)maEntryVector.size() ) )
447         return NULL;
448 
449     return maEntryVector[nEntry];
450 }
451 
452 
453 // --------------------------------------------------------------------
454 
455 IMPL_LINK( ToolbarMenu, HighlightHdl, Control *, pControl )
456 {
457     (void)pControl;
458     mpImpl->notifyHighlightedEntry();
459     return 0;
460 }
461 
462 // ====================================================================
463 
464 ToolbarMenu::ToolbarMenu( const Reference< XFrame >& rFrame, Window* pParentWindow, WinBits nBits )
465 : DockingWindow(pParentWindow, nBits)
466 {
467     implInit(rFrame);
468 }
469 
470 // --------------------------------------------------------------------
471 
472 ToolbarMenu::ToolbarMenu( const Reference< XFrame >& rFrame, Window* pParentWindow, const ResId& rResId )
473 : DockingWindow(pParentWindow, rResId)
474 {
475     implInit(rFrame);
476 }
477 
478 // --------------------------------------------------------------------
479 
480 void ToolbarMenu::implInit(const Reference< XFrame >& rFrame)
481 {
482     mpImpl = new ToolbarMenu_Impl( *this, rFrame );
483 
484     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
485     SetControlBackground( rStyleSettings.GetMenuColor() );
486 
487     initWindow();
488 
489     Window* pWindow = GetTopMostParentSystemWindow( this );
490     if ( pWindow )
491         ((SystemWindow *)pWindow)->GetTaskPaneList()->AddWindow( this );
492 }
493 
494 // --------------------------------------------------------------------
495 
496 ToolbarMenu::~ToolbarMenu()
497 {
498     Window* pWindow = GetTopMostParentSystemWindow( this );
499     if ( pWindow )
500         ((SystemWindow *)pWindow)->GetTaskPaneList()->RemoveWindow( this );
501 
502     if ( mpImpl->mxStatusListener.is() )
503     {
504         mpImpl->mxStatusListener->dispose();
505         mpImpl->mxStatusListener.clear();
506     }
507 
508     // delete all menu entries
509     const int nEntryCount = mpImpl->maEntryVector.size();
510     int nEntry;
511     for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
512     {
513         delete mpImpl->maEntryVector[nEntry];
514     }
515 
516     delete mpImpl;
517 }
518 
519 // --------------------------------------------------------------------
520 
521 int ToolbarMenu::getSelectedEntryId() const
522 {
523     ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnSelectedEntry );
524     return pEntry ? pEntry->mnEntryId : -1;
525 }
526 
527 // --------------------------------------------------------------------
528 
529 int ToolbarMenu::getHighlightedEntryId() const
530 {
531     ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnHighlightedEntry );
532     return pEntry ? pEntry->mnEntryId : -1;
533 }
534 
535 // --------------------------------------------------------------------
536 
537 void ToolbarMenu::checkEntry( int nEntryId, bool bChecked )
538 {
539     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
540     if( pEntry && pEntry->mbChecked != bChecked )
541     {
542         pEntry->mbChecked = bChecked;
543         Invalidate();
544     }
545 }
546 
547 // --------------------------------------------------------------------
548 
549 bool ToolbarMenu::isEntryChecked( int nEntryId ) const
550 {
551     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
552     return pEntry && pEntry->mbChecked;
553 }
554 
555 // --------------------------------------------------------------------
556 
557 void ToolbarMenu::enableEntry( int nEntryId, bool bEnable )
558 {
559     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
560     if( pEntry && pEntry->mbEnabled != bEnable )
561     {
562         pEntry->mbEnabled = bEnable;
563         if( pEntry->mpControl )
564         {
565             pEntry->mpControl->Enable( bEnable );
566 
567             // hack for the valueset to make it paint itself anew
568             pEntry->mpControl->Resize();
569         }
570         Invalidate();
571     }
572 }
573 
574 // --------------------------------------------------------------------
575 
576 bool ToolbarMenu::isEntryEnabled( int nEntryId ) const
577 {
578     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
579     return pEntry && pEntry->mbEnabled;
580 }
581 
582 // --------------------------------------------------------------------
583 
584 void ToolbarMenu::setEntryText( int nEntryId, const String& rStr )
585 {
586     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
587     if( pEntry && pEntry->maText != rStr )
588     {
589         pEntry->maText = rStr;
590         mpImpl->maSize = implCalcSize();
591         if( IsVisible() )
592             Invalidate();
593     }
594 }
595 
596 // --------------------------------------------------------------------
597 
598 const String& ToolbarMenu::getEntryText( int nEntryId ) const
599 {
600     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
601     if( pEntry )
602         return pEntry->maText;
603     else
604     {
605         static String aEmptyStr;
606         return aEmptyStr;
607     }
608 }
609 
610 // --------------------------------------------------------------------
611 
612 void ToolbarMenu::setEntryImage( int nEntryId, const Image& rImage )
613 {
614     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
615     if( pEntry && pEntry->maImage != rImage )
616     {
617         pEntry->maImage = rImage;
618         mpImpl->maSize = implCalcSize();
619         if( IsVisible() )
620             Invalidate();
621     }
622 }
623 
624 // --------------------------------------------------------------------
625 
626 const Image& ToolbarMenu::getEntryImage( int nEntryId ) const
627 {
628     ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId );
629     if( pEntry )
630         return pEntry->maImage;
631     else
632     {
633         static Image aEmptyImage;
634         return aEmptyImage;
635     }
636 }
637 
638 // --------------------------------------------------------------------
639 
640 void ToolbarMenu::initWindow()
641 {
642     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
643 
644     SetPointFont( rStyleSettings.GetMenuFont() );
645     SetBackground( Wallpaper( GetControlBackground() ) );
646     SetTextColor( rStyleSettings.GetMenuTextColor() );
647     SetTextFillColor();
648     SetLineColor();
649 
650     mpImpl->maSize = implCalcSize();
651 }
652 
653 // --------------------------------------------------------------------
654 
655 Size ToolbarMenu::implCalcSize()
656 {
657     const long nFontHeight = GetTextHeight();
658     long nExtra = nFontHeight/4;
659 
660     Size aSz;
661     Size aMaxImgSz;
662     long nMaxTextWidth = 0;
663     long nMinMenuItemHeight = nFontHeight+2;
664     sal_Bool bCheckable = sal_False;
665 
666     const int nEntryCount = mpImpl->maEntryVector.size();
667     int nEntry;
668 
669     const StyleSettings& rSettings = GetSettings().GetStyleSettings();
670     const bool bUseImages = rSettings.GetUseImagesInMenus();
671 
672     // get maximum image size
673     if( bUseImages )
674     {
675         for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
676         {
677             ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry];
678             if( pEntry && pEntry->mbHasImage )
679             {
680                 Size aImgSz( pEntry->maImage.GetSizePixel() );
681                 nMinMenuItemHeight = std::max( nMinMenuItemHeight, aImgSz.Height() + 6 );
682                 aMaxImgSz.Width() = std::max( aMaxImgSz.Width(), aImgSz.Width() );
683             }
684         }
685     }
686 
687     mpImpl->mnCheckPos = nExtra;
688     mpImpl->mnImagePos = nExtra;
689     mpImpl->mnTextPos = mpImpl->mnImagePos + aMaxImgSz.Width();
690 
691     if ( aMaxImgSz.Width() )
692         mpImpl->mnTextPos += std::max( nExtra, 7L );
693     if ( bCheckable )
694         mpImpl->mnTextPos += 16;
695 
696     // set heights, calc maximum width
697     for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
698     {
699         ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry];
700 
701         if( pEntry )
702         {
703             if ( ( pEntry->mnBits ) & ( MIB_RADIOCHECK | MIB_CHECKABLE ) )
704                 bCheckable = sal_True;
705 
706             // Text:
707             if( pEntry->mbHasText || pEntry->mbHasImage )
708             {
709                 pEntry->maSize.Height() = nMinMenuItemHeight;
710 
711                 if( pEntry->mbHasText )
712                 {
713                     long nTextWidth = GetCtrlTextWidth( pEntry->maText ) + mpImpl->mnTextPos + nExtra;
714                     nMaxTextWidth = std::max( nTextWidth, nMaxTextWidth );
715                 }
716             }
717             // Control:
718             else if( pEntry->mpControl )
719             {
720                 Size aControlSize( pEntry->mpControl->GetOutputSizePixel() );
721 
722                 nMaxTextWidth = std::max( aControlSize.Width(), nMaxTextWidth );
723                 pEntry->maSize.Height() = aControlSize.Height() + 1;
724             }
725 
726         }
727     }
728 
729     aSz.Width() = nMaxTextWidth + (BORDER_X<<1);
730 
731     // positionate controls
732     int nY = BORDER_Y;
733     for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
734     {
735         ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry];
736 
737         if( pEntry )
738         {
739             pEntry->maSize.Width() = nMaxTextWidth;
740 
741             if( pEntry->mpControl )
742             {
743                 Size aControlSize( pEntry->mpControl->GetOutputSizePixel() );
744                 Point aControlPos( (aSz.Width() - aControlSize.Width())>>1, nY);
745 
746                 pEntry->mpControl->SetPosPixel( aControlPos );
747 
748                 pEntry->maRect = Rectangle( aControlPos, aControlSize );
749             }
750             else
751             {
752                 pEntry->maRect = Rectangle( Point( 0, nY ), pEntry->maSize );
753             }
754 
755             nY += pEntry->maSize.Height();
756         }
757         else
758         {
759             nY += SEPARATOR_HEIGHT;
760         }
761     }
762 
763     aSz.Height() += nY + BORDER_Y;
764 
765     return aSz;
766 }
767 
768 // --------------------------------------------------------------------
769 
770 void ToolbarMenu::highlightFirstEntry()
771 {
772     implChangeHighlightEntry( 0 );
773 }
774 
775 // --------------------------------------------------------------------
776 
777 void ToolbarMenu::GetFocus()
778 {
779     if( mpImpl->mnHighlightedEntry == -1 )
780         implChangeHighlightEntry( 0 );
781 
782     DockingWindow::GetFocus();
783 }
784 
785 // --------------------------------------------------------------------
786 
787 void ToolbarMenu::LoseFocus()
788 {
789     if( mpImpl->mnHighlightedEntry != -1 )
790         implChangeHighlightEntry( -1 );
791 
792     DockingWindow::LoseFocus();
793 }
794 
795 // --------------------------------------------------------------------
796 
797 void ToolbarMenu::appendEntry( int nEntryId, const String& rStr, MenuItemBits nItemBits )
798 {
799     appendEntry( new ToolbarMenuEntry( *this, nEntryId, rStr, nItemBits ) );
800 }
801 
802 // --------------------------------------------------------------------
803 
804 void ToolbarMenu::appendEntry( int nEntryId, const Image& rImage, MenuItemBits nItemBits )
805 {
806     appendEntry( new ToolbarMenuEntry( *this, nEntryId, rImage, nItemBits ) );
807 }
808 
809 // --------------------------------------------------------------------
810 
811 void ToolbarMenu::appendEntry( int nEntryId, const String& rStr, const Image& rImage, MenuItemBits nItemBits )
812 {
813     appendEntry( new ToolbarMenuEntry( *this, nEntryId, rImage, rStr, nItemBits ) );
814 }
815 
816 // --------------------------------------------------------------------
817 
818 void ToolbarMenu::appendEntry( int nEntryId, Control* pControl, MenuItemBits nItemBits )
819 {
820     appendEntry( new ToolbarMenuEntry( *this, nEntryId, pControl, nItemBits ) );
821 }
822 
823 // --------------------------------------------------------------------
824 
825 void ToolbarMenu::appendEntry( ToolbarMenuEntry* pEntry )
826 {
827     mpImpl->maEntryVector.push_back( pEntry );
828     mpImpl->maSize = implCalcSize();
829     if( IsVisible() )
830         Invalidate();
831 }
832 
833 // --------------------------------------------------------------------
834 
835 void ToolbarMenu::appendSeparator()
836 {
837     appendEntry( 0 );
838 }
839 
840 // --------------------------------------------------------------------
841 
842 /** creates an empty ValueSet that is initialized and can be inserted with appendEntry. */
843 ValueSet* ToolbarMenu::createEmptyValueSetControl()
844 {
845     ValueSet* pSet = new ValueSet( this, WB_TABSTOP | WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NOBORDER | WB_NO_DIRECTSELECT );
846     pSet->EnableFullItemMode( sal_False );
847     pSet->SetColor( GetControlBackground() );
848     pSet->SetHighlightHdl( LINK( this, ToolbarMenu, HighlightHdl ) );
849     return pSet;
850 }
851 
852 // --------------------------------------------------------------------
853 
854 ToolbarMenuEntry* ToolbarMenu::implGetEntry( int nEntry ) const
855 {
856     return mpImpl->implGetEntry( nEntry );
857 }
858 
859 // --------------------------------------------------------------------
860 
861 ToolbarMenuEntry* ToolbarMenu::implSearchEntry( int nEntryId ) const
862 {
863     const int nEntryCount = mpImpl->maEntryVector.size();
864     int nEntry;
865     for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
866     {
867         ToolbarMenuEntry* p = mpImpl->maEntryVector[nEntry];
868         if( p && p->mnEntryId == nEntryId )
869         {
870             return p;
871         }
872     }
873 
874     return NULL;
875 }
876 
877 // --------------------------------------------------------------------
878 
879 void ToolbarMenu::implHighlightEntry( int nHighlightEntry, bool bHighlight )
880 {
881     Size    aSz( GetOutputSizePixel() );
882     long    nX = 0, nY = 0;
883 
884     const int nEntryCount = mpImpl->maEntryVector.size();
885     int nEntry;
886     for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
887     {
888         ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry];
889         if( pEntry && (nEntry == nHighlightEntry) )
890         {
891             // no highlights for controls only items
892             if( pEntry->mpControl )
893             {
894                 if( !bHighlight )
895                 {
896                     ValueSet* pValueSet = dynamic_cast< ValueSet* >( pEntry->mpControl );
897                     if( pValueSet )
898                     {
899                         pValueSet->SetNoSelection();
900                     }
901                 }
902                 break;
903             }
904 
905             bool bRestoreLineColor = false;
906             Color oldLineColor;
907             bool bDrawItemRect = true;
908 
909             Rectangle aItemRect( Point( nX, nY ), Size( aSz.Width(), pEntry->maSize.Height() ) );
910             if ( pEntry->mnBits & MIB_POPUPSELECT )
911             {
912                 long nFontHeight = GetTextHeight();
913                 aItemRect.Right() -= nFontHeight + nFontHeight/4;
914             }
915 
916             if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
917             {
918                 Size aPxSize( GetOutputSizePixel() );
919                 Push( PUSH_CLIPREGION );
920                 IntersectClipRegion( Rectangle( Point( nX, nY ), Size( aSz.Width(), pEntry->maSize.Height() ) ) );
921                 Rectangle aCtrlRect( Point( nX, 0 ), Size( aPxSize.Width()-nX, aPxSize.Height() ) );
922                 DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
923                                    aCtrlRect,
924                                    CTRL_STATE_ENABLED,
925                                    ImplControlValue(),
926                                    OUString() );
927                 if( bHighlight && IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) )
928                 {
929                     bDrawItemRect = false;
930                     if( sal_False == DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM,
931                                                     aItemRect,
932                                                     CTRL_STATE_SELECTED | ( pEntry->mbEnabled? CTRL_STATE_ENABLED: 0 ),
933                                                     ImplControlValue(),
934                                                     OUString() ) )
935                     {
936                         bDrawItemRect = bHighlight;
937                     }
938                 }
939                 else
940                     bDrawItemRect = bHighlight;
941                 Pop();
942             }
943             if( bDrawItemRect )
944             {
945                 if ( bHighlight )
946                 {
947                     if( pEntry->mbEnabled )
948                         SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
949                     else
950                     {
951                         SetFillColor();
952                         oldLineColor = GetLineColor();
953                         SetLineColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
954                         bRestoreLineColor = true;
955                     }
956                 }
957                 else
958                     SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
959 
960                 DrawRect( aItemRect );
961             }
962             implPaint( pEntry, bHighlight );
963             if( bRestoreLineColor )
964                 SetLineColor( oldLineColor );
965             break;
966         }
967 
968         nY += pEntry ? pEntry->maSize.Height() : SEPARATOR_HEIGHT;
969     }
970 }
971 
972 // --------------------------------------------------------------------
973 
974 void ToolbarMenu::implSelectEntry( int nSelectedEntry )
975 {
976     mpImpl->mnSelectedEntry = nSelectedEntry;
977 
978     ToolbarMenuEntry* pEntry = NULL;
979     if( nSelectedEntry != -1 )
980         pEntry = mpImpl->maEntryVector[ nSelectedEntry ];
981 
982     if( pEntry )
983         mpImpl->maSelectHdl.Call( this );
984 }
985 
986 // --------------------------------------------------------------------
987 
988 void ToolbarMenu::MouseButtonDown( const MouseEvent& rMEvt )
989 {
990     implHighlightEntry( rMEvt, true );
991 
992     implSelectEntry( mpImpl->mnHighlightedEntry );
993 }
994 
995 // --------------------------------------------------------------------
996 
997 void ToolbarMenu::MouseButtonUp( const MouseEvent& )
998 {
999 }
1000 
1001 // --------------------------------------------------------------------
1002 
1003 void ToolbarMenu::MouseMove( const MouseEvent& rMEvt )
1004 {
1005     if ( !IsVisible() )
1006         return;
1007 
1008     implHighlightEntry( rMEvt, false );
1009 }
1010 
1011 // --------------------------------------------------------------------
1012 
1013 void ToolbarMenu::implHighlightEntry( const MouseEvent& rMEvt, bool bMBDown )
1014 {
1015     long nY = 0;
1016     long nMouseY = rMEvt.GetPosPixel().Y();
1017     Size aOutSz = GetOutputSizePixel();
1018     if ( ( nMouseY >= 0 ) && ( nMouseY < aOutSz.Height() ) )
1019     {
1020         bool bHighlighted = sal_False;
1021 
1022         const int nEntryCount = mpImpl->maEntryVector.size();
1023         int nEntry;
1024         for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
1025         {
1026             ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry];
1027             if( pEntry )
1028             {
1029                 long nOldY = nY;
1030                 nY += pEntry->maSize.Height();
1031 
1032                 if( pEntry->mnEntryId != TITLE_ID )
1033                 {
1034                     if ( ( nOldY <= nMouseY ) && ( nY > nMouseY ) )
1035                     {
1036                         if( bMBDown )
1037                         {
1038                             if( nEntry != mpImpl->mnHighlightedEntry )
1039                             {
1040                                 implChangeHighlightEntry( nEntry );
1041                             }
1042                         }
1043                         else
1044                         {
1045                             if ( nEntry != mpImpl->mnHighlightedEntry )
1046                             {
1047                                 implChangeHighlightEntry( nEntry );
1048                             }
1049                         }
1050                         bHighlighted = true;
1051                     }
1052                 }
1053             }
1054             else
1055             {
1056                 nY += SEPARATOR_HEIGHT;
1057             }
1058         }
1059         if ( !bHighlighted )
1060             implChangeHighlightEntry( -1 );
1061     }
1062     else
1063     {
1064         implChangeHighlightEntry( -1 );
1065     }
1066 }
1067 
1068 // --------------------------------------------------------------------
1069 
1070 void ToolbarMenu::implChangeHighlightEntry( int nEntry )
1071 {
1072     if( mpImpl->mnHighlightedEntry != -1 )
1073     {
1074         implHighlightEntry( mpImpl->mnHighlightedEntry, false );
1075     }
1076 
1077     mpImpl->mnHighlightedEntry = nEntry;
1078     Invalidate();
1079 
1080     if( mpImpl->mnHighlightedEntry != -1 )
1081     {
1082         implHighlightEntry( mpImpl->mnHighlightedEntry, true );
1083     }
1084 
1085     mpImpl->notifyHighlightedEntry();
1086 }
1087 
1088 // --------------------------------------------------------------------
1089 
1090 static bool implCheckSubControlCursorMove( Control* pControl, bool bUp, int& nLastColumn )
1091 {
1092     ValueSet* pValueSet = dynamic_cast< ValueSet* >( pControl );
1093     if( pValueSet )
1094     {
1095         sal_uInt16 nItemPos = pValueSet->GetItemPos( pValueSet->GetSelectItemId() );
1096         if( nItemPos != VALUESET_ITEM_NOTFOUND )
1097         {
1098             const sal_uInt16 nColCount = pValueSet->GetColCount();
1099             const sal_uInt16 nLine = nItemPos / nColCount;
1100 
1101             nLastColumn = nItemPos - (nLine * nColCount);
1102 
1103             if( bUp )
1104             {
1105                 return nLine > 0;
1106             }
1107             else
1108             {
1109                 const sal_uInt16 nLineCount = (pValueSet->GetItemCount() + nColCount - 1) / nColCount;
1110                 return (nLine+1) < nLineCount;
1111             }
1112         }
1113     }
1114 
1115     return false;
1116 }
1117 
1118 // --------------------------------------------------------------------
1119 
1120 ToolbarMenuEntry* ToolbarMenu::implCursorUpDown( bool bUp, bool bHomeEnd )
1121 {
1122     int n = 0, nLoop = 0;
1123     if( !bHomeEnd )
1124     {
1125         n = mpImpl->mnHighlightedEntry;
1126         if( n == -1 )
1127         {
1128             if( bUp )
1129                 n = 0;
1130             else
1131                 n = mpImpl->maEntryVector.size()-1;
1132         }
1133         else
1134         {
1135             // if we have a currently selected entry and
1136             // cursor keys are used than check if this entry
1137             // has a control that can use those cursor keys
1138             ToolbarMenuEntry* pData = mpImpl->maEntryVector[n];
1139             if( pData && pData->mpControl && !pData->mbHasText )
1140             {
1141                 if( implCheckSubControlCursorMove( pData->mpControl, bUp, mpImpl->mnLastColumn ) )
1142                     return pData;
1143             }
1144         }
1145         nLoop = n;
1146     }
1147     else
1148     {
1149         // absolute positioning
1150         if( bUp )
1151         {
1152             n = mpImpl->maEntryVector.size();
1153             nLoop = n-1;
1154         }
1155         else
1156         {
1157             n = -1;
1158             nLoop = mpImpl->maEntryVector.size()-1;
1159         }
1160     }
1161 
1162     do
1163     {
1164         if( bUp )
1165         {
1166             if ( n )
1167                 n--;
1168             else
1169                 if( mpImpl->mnHighlightedEntry == -1 )
1170                     n = mpImpl->maEntryVector.size()-1;
1171                 else
1172                     break;
1173         }
1174         else
1175         {
1176             if( n < ((int)mpImpl->maEntryVector.size()-1) )
1177                 n++;
1178             else
1179                 if( mpImpl->mnHighlightedEntry == -1 )
1180                     n = 0;
1181                 else
1182                     break;
1183         }
1184 
1185         ToolbarMenuEntry* pData = mpImpl->maEntryVector[n];
1186         if( pData && (pData->mnEntryId != TITLE_ID) )
1187         {
1188             implChangeHighlightEntry( n );
1189             return pData;
1190         }
1191     } while ( n != nLoop );
1192 
1193     return 0;
1194 }
1195 
1196 // --------------------------------------------------------------------
1197 
1198 void ToolbarMenu_Impl::implHighlightControl( sal_uInt16 nCode, Control* pControl )
1199 {
1200     ValueSet* pValueSet = dynamic_cast< ValueSet* >( pControl );
1201     if( pValueSet )
1202     {
1203         const sal_uInt16 nItemCount = pValueSet->GetItemCount();
1204         sal_uInt16 nItemPos = VALUESET_ITEM_NOTFOUND;
1205         switch( nCode )
1206         {
1207         case KEY_UP:
1208         {
1209             const sal_uInt16 nColCount = pValueSet->GetColCount();
1210             const sal_uInt16 nLastLine = nItemCount / nColCount;
1211             nItemPos = std::min( ((nLastLine-1) * nColCount) + mnLastColumn, nItemCount-1 );
1212             break;
1213         }
1214         case KEY_DOWN:
1215             nItemPos = std::min( mnLastColumn, nItemCount-1 );
1216             break;
1217         case KEY_END:
1218             nItemPos = nItemCount -1;
1219             break;
1220         case KEY_HOME:
1221             nItemPos = 0;
1222             break;
1223         }
1224         pValueSet->SelectItem( pValueSet->GetItemId( nItemPos ) );
1225         notifyHighlightedEntry();
1226     }
1227 }
1228 
1229 // --------------------------------------------------------------------
1230 
1231 void ToolbarMenu::KeyInput( const KeyEvent& rKEvent )
1232 {
1233     Control* pForwardControl = 0;
1234     sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode();
1235     switch ( nCode )
1236     {
1237         case KEY_UP:
1238         case KEY_DOWN:
1239         {
1240             int nOldEntry = mpImpl->mnHighlightedEntry;
1241             ToolbarMenuEntry*p = implCursorUpDown( nCode == KEY_UP, false );
1242             if( p && p->mpControl )
1243             {
1244                 if( nOldEntry != mpImpl->mnHighlightedEntry )
1245                 {
1246                     mpImpl->implHighlightControl( nCode, p->mpControl );
1247                 }
1248                 else
1249                 {
1250                     // in case we are in a system floating window, GrabFocus does not work :-/
1251                     pForwardControl = p->mpControl;
1252                 }
1253             }
1254         }
1255         break;
1256         case KEY_END:
1257         case KEY_HOME:
1258         {
1259             ToolbarMenuEntry* p = implCursorUpDown( nCode == KEY_END, true );
1260             if( p && p->mpControl )
1261             {
1262                 mpImpl->implHighlightControl( nCode, p->mpControl );
1263             }
1264         }
1265         break;
1266         case KEY_F6:
1267         case KEY_ESCAPE:
1268         {
1269             // Ctrl-F6 acts like ESC here, the menu bar however will then put the focus in the document
1270             if( nCode == KEY_F6 && !rKEvent.GetKeyCode().IsMod1() )
1271                 break;
1272 
1273             implSelectEntry( -1 );
1274         }
1275         break;
1276 
1277         case KEY_RETURN:
1278         {
1279             ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnHighlightedEntry );
1280             if ( pEntry && pEntry->mbEnabled && (pEntry->mnEntryId != TITLE_ID) )
1281             {
1282                 if( pEntry->mpControl )
1283                 {
1284                     pForwardControl = pEntry->mpControl;
1285                 }
1286                 else
1287                 {
1288                     implSelectEntry( mpImpl->mnHighlightedEntry );
1289                 }
1290             }
1291         }
1292         break;
1293         default:
1294         {
1295             ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnHighlightedEntry );
1296             if ( pEntry && pEntry->mbEnabled && pEntry->mpControl && !pEntry->mbHasText )
1297             {
1298                 pForwardControl = pEntry->mpControl;
1299             }
1300         }
1301 
1302     }
1303     if( pForwardControl )
1304         pForwardControl->KeyInput( rKEvent );
1305 
1306 }
1307 
1308 // --------------------------------------------------------------------
1309 static void ImplPaintCheckBackground( Window* i_pWindow, const Rectangle& i_rRect, bool i_bHighlight )
1310 {
1311     sal_Bool bNativeOk = sal_False;
1312     if( i_pWindow->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) )
1313     {
1314         ImplControlValue    aControlValue;
1315         ControlState        nState = CTRL_STATE_PRESSED | CTRL_STATE_ENABLED;
1316 
1317         aControlValue.setTristateVal( BUTTONVALUE_ON );
1318 
1319         bNativeOk = i_pWindow->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON,
1320                                                   i_rRect, nState, aControlValue,
1321                                                   rtl::OUString() );
1322     }
1323 
1324     if( ! bNativeOk )
1325     {
1326         const StyleSettings& rSettings = i_pWindow->GetSettings().GetStyleSettings();
1327         Color aColor( i_bHighlight ? rSettings.GetMenuHighlightTextColor() : rSettings.GetHighlightColor() );
1328         i_pWindow->DrawSelectionBackground( i_rRect, 0, i_bHighlight, sal_True, sal_False, 2, NULL, &aColor );
1329     }
1330 }
1331 
1332 static long ImplGetNativeCheckAndRadioSize( Window* pWin, long& rCheckHeight, long& rRadioHeight, long &rMaxWidth )
1333 {
1334     rMaxWidth = rCheckHeight = rRadioHeight = 0;
1335 
1336     ImplControlValue aVal;
1337     Rectangle aNativeBounds;
1338     Rectangle aNativeContent;
1339     Point tmp( 0, 0 );
1340     Rectangle aCtrlRegion( tmp, Size( 100, 15 ) );
1341     if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_CHECK_MARK ) )
1342     {
1343         if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
1344                                           ControlPart(PART_MENU_ITEM_CHECK_MARK),
1345                                           aCtrlRegion,
1346                                           ControlState(CTRL_STATE_ENABLED),
1347                                           aVal,
1348                                           OUString(),
1349                                           aNativeBounds,
1350                                           aNativeContent )
1351         )
1352         {
1353             rCheckHeight = aNativeBounds.GetHeight();
1354             rMaxWidth = aNativeContent.GetWidth();
1355         }
1356     }
1357     if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_RADIO_MARK ) )
1358     {
1359         if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
1360                                           ControlPart(PART_MENU_ITEM_RADIO_MARK),
1361                                           aCtrlRegion,
1362                                           ControlState(CTRL_STATE_ENABLED),
1363                                           aVal,
1364                                           OUString(),
1365                                           aNativeBounds,
1366                                           aNativeContent )
1367         )
1368         {
1369             rRadioHeight = aNativeBounds.GetHeight();
1370             rMaxWidth = Max (rMaxWidth, aNativeContent.GetWidth());
1371         }
1372     }
1373     return (rCheckHeight > rRadioHeight) ? rCheckHeight : rRadioHeight;
1374 }
1375 
1376 void ToolbarMenu::implPaint( ToolbarMenuEntry* pThisOnly, bool bHighlighted )
1377 {
1378     sal_uInt16 nBorder = 0; long nStartY = 0; // from Menu implementations, needed when we support native menu background & scrollable menu
1379 
1380     long nFontHeight = GetTextHeight();
1381 //    long nExtra = nFontHeight/4;
1382 
1383     long nCheckHeight = 0, nRadioHeight = 0, nMaxCheckWidth = 0;
1384     ImplGetNativeCheckAndRadioSize( this, nCheckHeight, nRadioHeight, nMaxCheckWidth );
1385 
1386     DecorationView aDecoView( this );
1387     const StyleSettings& rSettings = GetSettings().GetStyleSettings();
1388     const bool bUseImages = rSettings.GetUseImagesInMenus();
1389 
1390     int nOuterSpace = 0; // ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
1391     Point aTopLeft( nOuterSpace, nOuterSpace ), aTmpPos;
1392 
1393     Size aOutSz( GetOutputSizePixel() );
1394     const int nEntryCount = mpImpl->maEntryVector.size();
1395     int nEntry;
1396     for( nEntry = 0; nEntry < nEntryCount; nEntry++ )
1397     {
1398         ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry];
1399 
1400         Point aPos( aTopLeft );
1401         aPos.Y() += nBorder;
1402         aPos.Y() += nStartY;
1403 
1404 
1405         if( (pEntry == 0) && !pThisOnly )
1406         {
1407             // Separator
1408             aTmpPos.Y() = aPos.Y() + ((SEPARATOR_HEIGHT-2)/2);
1409             aTmpPos.X() = aPos.X() + 2 + nOuterSpace;
1410             SetLineColor( rSettings.GetShadowColor() );
1411             DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) );
1412             aTmpPos.Y()++;
1413             SetLineColor( rSettings.GetLightColor() );
1414             DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) );
1415             SetLineColor();
1416         }
1417         else if( !pThisOnly || ( pEntry == pThisOnly ) )
1418         {
1419             const bool bTitle = pEntry->mnEntryId == TITLE_ID;
1420 
1421             if ( pThisOnly && bHighlighted )
1422                 SetTextColor( rSettings.GetMenuHighlightTextColor() );
1423 
1424             if( aPos.Y() >= 0 )
1425             {
1426                 long nTextOffsetY = ((pEntry->maSize.Height()-nFontHeight)/2);
1427 
1428                 sal_uInt16  nTextStyle   = 0;
1429                 sal_uInt16  nSymbolStyle = 0;
1430                 sal_uInt16  nImageStyle  = 0;
1431 
1432                 if( !pEntry->mbEnabled )
1433                 {
1434                     nTextStyle   |= TEXT_DRAW_DISABLE;
1435                     nSymbolStyle |= SYMBOL_DRAW_DISABLE;
1436                     nImageStyle  |= IMAGE_DRAW_DISABLE;
1437                 }
1438 
1439                 Rectangle aOuterCheckRect( Point( aPos.X()+mpImpl->mnCheckPos, aPos.Y() ), Size( pEntry->maSize.Height(), pEntry->maSize.Height() ) );
1440                 aOuterCheckRect.Left()      += 1;
1441                 aOuterCheckRect.Right()     -= 1;
1442                 aOuterCheckRect.Top()       += 1;
1443                 aOuterCheckRect.Bottom()    -= 1;
1444 
1445                 if( bTitle )
1446                 {
1447                     // fill the background
1448                     Rectangle aRect( aTopLeft, Size( aOutSz.Width(), pEntry->maSize.Height() ) );
1449                     SetFillColor(rSettings.GetDialogColor());
1450                     SetLineColor();
1451                     DrawRect(aRect);
1452                     SetLineColor( rSettings.GetLightColor() );
1453                     DrawLine( aRect.TopLeft(), aRect.TopRight() );
1454                     SetLineColor( rSettings.GetShadowColor() );
1455                     DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
1456                 }
1457 
1458                 // CheckMark
1459                 if ( pEntry->HasCheck() )
1460                 {
1461                     // draw selection transparent marker if checked
1462                     // onto that either a checkmark or the item image
1463                     // will be painted
1464                     // however do not do this if native checks will be painted since
1465                     // the selection color too often does not fit the theme's check and/or radio
1466 
1467                     if( !pEntry->mbHasImage )
1468                     {
1469                         if( this->IsNativeControlSupported( CTRL_MENU_POPUP,
1470                                                              (pEntry->mnBits & MIB_RADIOCHECK)
1471                                                              ? PART_MENU_ITEM_CHECK_MARK
1472                                                              : PART_MENU_ITEM_RADIO_MARK ) )
1473                         {
1474                             ControlPart nPart = ((pEntry->mnBits & MIB_RADIOCHECK)
1475                                                  ? PART_MENU_ITEM_RADIO_MARK
1476                                                  : PART_MENU_ITEM_CHECK_MARK);
1477 
1478                             ControlState nState = 0;
1479 
1480                             if ( pEntry->mbChecked )
1481                                 nState |= CTRL_STATE_PRESSED;
1482 
1483                             if ( pEntry->mbEnabled )
1484                                 nState |= CTRL_STATE_ENABLED;
1485 
1486                             if ( bHighlighted )
1487                                 nState |= CTRL_STATE_SELECTED;
1488 
1489                             long nCtrlHeight = (pEntry->mnBits & MIB_RADIOCHECK) ? nCheckHeight : nRadioHeight;
1490                             aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - nCtrlHeight)/2;
1491                             aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - nCtrlHeight)/2;
1492 
1493                             Rectangle aCheckRect( aTmpPos, Size( nCtrlHeight, nCtrlHeight ) );
1494                             DrawNativeControl( CTRL_MENU_POPUP, nPart, aCheckRect, nState, ImplControlValue(), OUString() );
1495                         }
1496                         else if ( pEntry->mbChecked ) // by default do nothing for unchecked items
1497                         {
1498                             ImplPaintCheckBackground( this, aOuterCheckRect, pThisOnly && bHighlighted );
1499 
1500                             SymbolType eSymbol;
1501                             Size aSymbolSize;
1502                             if ( pEntry->mnBits & MIB_RADIOCHECK )
1503                             {
1504                                 eSymbol = SYMBOL_RADIOCHECKMARK;
1505                                 aSymbolSize = Size( nFontHeight/2, nFontHeight/2 );
1506                             }
1507                             else
1508                             {
1509                                 eSymbol = SYMBOL_CHECKMARK;
1510                                 aSymbolSize = Size( (nFontHeight*25)/40, nFontHeight/2 );
1511                             }
1512                             aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - aSymbolSize.Width())/2;
1513                             aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - aSymbolSize.Height())/2;
1514                             Rectangle aRect( aTmpPos, aSymbolSize );
1515                             aDecoView.DrawSymbol( aRect, eSymbol, GetTextColor(), nSymbolStyle );
1516                         }
1517                     }
1518                 }
1519 
1520                 // Image:
1521                 if( pEntry->mbHasImage && bUseImages )
1522                 {
1523                     // Don't render an image for a check thing
1524                      /* if((nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES) || !pEntry->HasCheck() )*/
1525                     {
1526                         if( pEntry->mbChecked )
1527                             ImplPaintCheckBackground( this, aOuterCheckRect, pThisOnly && bHighlighted );
1528                         aTmpPos = aOuterCheckRect.TopLeft();
1529                         aTmpPos.X() += (aOuterCheckRect.GetWidth()-pEntry->maImage.GetSizePixel().Width())/2;
1530                         aTmpPos.Y() += (aOuterCheckRect.GetHeight()-pEntry->maImage.GetSizePixel().Height())/2;
1531                         DrawImage( aTmpPos, pEntry->maImage, nImageStyle );
1532                     }
1533                 }
1534 
1535                 // Text:
1536                 if( pEntry->mbHasText )
1537                 {
1538                     aTmpPos.X() = aPos.X() + (bTitle ? 4 : mpImpl->mnTextPos);
1539                     aTmpPos.Y() = aPos.Y();
1540                     aTmpPos.Y() += nTextOffsetY;
1541                     sal_uInt16 nStyle = nTextStyle|TEXT_DRAW_MNEMONIC;
1542 
1543                     DrawCtrlText( aTmpPos, pEntry->maText, 0, pEntry->maText.Len(), nStyle, NULL, NULL ); // pVector, pDisplayText );
1544                 }
1545 
1546 /*
1547                 // Accel
1548                 if ( !bLayout && !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
1549                 {
1550                     XubString aAccText = pData->aAccelKey.GetName();
1551                     aTmpPos.X() = aOutSz.Width() - this->GetTextWidth( aAccText );
1552                     aTmpPos.X() -= 4*nExtra;
1553 
1554                     aTmpPos.X() -= nOuterSpace;
1555                     aTmpPos.Y() = aPos.Y();
1556                     aTmpPos.Y() += nTextOffsetY;
1557                     this->DrawCtrlText( aTmpPos, aAccText, 0, aAccText.Len(), nTextStyle );
1558                 }
1559 */
1560 
1561 /*
1562                 // SubMenu?
1563                 if ( !bLayout && !bIsMenuBar && pData->pSubMenu )
1564                 {
1565                     aTmpPos.X() = aOutSz.Width() - nFontHeight + nExtra - nOuterSpace;
1566                     aTmpPos.Y() = aPos.Y();
1567                     aTmpPos.Y() += nExtra/2;
1568                     aTmpPos.Y() += ( pEntry->maSize.Height() / 2 ) - ( nFontHeight/4 );
1569                     if ( pEntry->mnBits & MIB_POPUPSELECT )
1570                     {
1571                         this->SetTextColor( rSettings.GetMenuTextColor() );
1572                         Point aTmpPos2( aPos );
1573                         aTmpPos2.X() = aOutSz.Width() - nFontHeight - nFontHeight/4;
1574                         aDecoView.DrawFrame(
1575                             Rectangle( aTmpPos2, Size( nFontHeight+nFontHeight/4, pEntry->maSize.Height() ) ), FRAME_DRAW_GROUP );
1576                     }
1577                     aDecoView.DrawSymbol(
1578                         Rectangle( aTmpPos, Size( nFontHeight/2, nFontHeight/2 ) ),
1579                         SYMBOL_SPIN_RIGHT, this->GetTextColor(), nSymbolStyle );
1580 //                  if ( pEntry->mnBits & MIB_POPUPSELECT )
1581 //                  {
1582 //                      aTmpPos.Y() += nFontHeight/2 ;
1583 //                      this->SetLineColor( rSettings.GetShadowColor() );
1584 //                      this->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) );
1585 //                      this->SetLineColor( rSettings.GetLightColor() );
1586 //                      aTmpPos.Y()++;
1587 //                      this->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) );
1588 //                      this->SetLineColor();
1589 //                  }
1590                 }
1591 */
1592 
1593                 if ( pThisOnly && bHighlighted )
1594                 {
1595                     // This restores the normal menu or menu bar text
1596                     // color for when it is no longer highlighted.
1597                     SetTextColor( rSettings.GetMenuTextColor() );
1598                  }
1599             }
1600         }
1601 
1602         aTopLeft.Y() += pEntry ? pEntry->maSize.Height() : SEPARATOR_HEIGHT;
1603     }
1604 }
1605 
1606 // --------------------------------------------------------------------
1607 
1608 void ToolbarMenu::Paint( const Rectangle& )
1609 {
1610     SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
1611 
1612     implPaint();
1613 
1614     if( mpImpl->mnHighlightedEntry != -1 )
1615         implHighlightEntry( mpImpl->mnHighlightedEntry, true );
1616 }
1617 
1618 // --------------------------------------------------------------------
1619 
1620 void ToolbarMenu::RequestHelp( const HelpEvent& rHEvt )
1621 {
1622     DockingWindow::RequestHelp( rHEvt );
1623 }
1624 
1625 // --------------------------------------------------------------------
1626 
1627 void ToolbarMenu::StateChanged( StateChangedType nType )
1628 {
1629     DockingWindow::StateChanged( nType );
1630 
1631     if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || ( nType == STATE_CHANGE_CONTROLBACKGROUND ) )
1632     {
1633         initWindow();
1634         Invalidate();
1635     }
1636 }
1637 
1638 // --------------------------------------------------------------------
1639 
1640 void ToolbarMenu::DataChanged( const DataChangedEvent& rDCEvt )
1641 {
1642     DockingWindow::DataChanged( rDCEvt );
1643 
1644     if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
1645          (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
1646          ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
1647           (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
1648     {
1649         initWindow();
1650         Invalidate();
1651     }
1652 }
1653 
1654 // --------------------------------------------------------------------
1655 
1656 void ToolbarMenu::Command( const CommandEvent& rCEvt )
1657 {
1658     if ( rCEvt.GetCommand() == COMMAND_WHEEL )
1659     {
1660         const CommandWheelData* pData = rCEvt.GetWheelData();
1661         if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
1662         {
1663             implCursorUpDown( pData->GetDelta() > 0L, false );
1664         }
1665     }
1666 }
1667 
1668 // --------------------------------------------------------------------
1669 
1670 Reference< ::com::sun::star::accessibility::XAccessible > ToolbarMenu::CreateAccessible()
1671 {
1672     mpImpl->setAccessible( new ToolbarMenuAcc( *mpImpl ) );
1673     return Reference< XAccessible >( mpImpl->mxAccessible.get() );
1674 }
1675 
1676 // --------------------------------------------------------------------
1677 
1678 // todo: move to new base class that will replace SfxPopupWindo
1679 void ToolbarMenu::AddStatusListener( const rtl::OUString& rCommandURL )
1680 {
1681     initStatusListener();
1682     mpImpl->mxStatusListener->addStatusListener( rCommandURL );
1683 }
1684 
1685 // --------------------------------------------------------------------
1686 
1687 void ToolbarMenu::RemoveStatusListener( const rtl::OUString& rCommandURL )
1688 {
1689     mpImpl->mxStatusListener->removeStatusListener( rCommandURL );
1690 }
1691 // --------------------------------------------------------------------
1692 
1693 
1694 void ToolbarMenu::UpdateStatus( const rtl::OUString& rCommandURL )
1695 {
1696     mpImpl->mxStatusListener->updateStatus( rCommandURL );
1697 }
1698 
1699 // --------------------------------------------------------------------
1700 
1701 // XStatusListener (subclasses must override this one to get the status updates
1702 void SAL_CALL ToolbarMenu::statusChanged( const ::com::sun::star::frame::FeatureStateEvent& /*Event*/ ) throw ( ::com::sun::star::uno::RuntimeException )
1703 {
1704 }
1705 
1706 // --------------------------------------------------------------------
1707 
1708 class ToolbarMenuStatusListener : public svt::FrameStatusListener
1709 {
1710 public:
1711     ToolbarMenuStatusListener( const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& xServiceManager,
1712                                const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame,
1713                                ToolbarMenu& rToolbarMenu );
1714 
1715     virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException);
1716     virtual void SAL_CALL statusChanged( const ::com::sun::star::frame::FeatureStateEvent& Event ) throw ( ::com::sun::star::uno::RuntimeException );
1717 
1718     ToolbarMenu* mpMenu;
1719 };
1720 
1721 // --------------------------------------------------------------------
1722 
1723 ToolbarMenuStatusListener::ToolbarMenuStatusListener(
1724     const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& xServiceManager,
1725     const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame,
1726     ToolbarMenu& rToolbarMenu )
1727 : svt::FrameStatusListener( xServiceManager, xFrame )
1728 , mpMenu( &rToolbarMenu )
1729 {
1730 }
1731 
1732 // --------------------------------------------------------------------
1733 
1734 void SAL_CALL ToolbarMenuStatusListener::dispose() throw (::com::sun::star::uno::RuntimeException)
1735 {
1736     mpMenu = 0;
1737     svt::FrameStatusListener::dispose();
1738 }
1739 
1740 // --------------------------------------------------------------------
1741 
1742 void SAL_CALL ToolbarMenuStatusListener::statusChanged( const ::com::sun::star::frame::FeatureStateEvent& Event ) throw ( ::com::sun::star::uno::RuntimeException )
1743 {
1744     if( mpMenu )
1745         mpMenu->statusChanged( Event );
1746 }
1747 
1748 // --------------------------------------------------------------------
1749 
1750 void ToolbarMenu::initStatusListener()
1751 {
1752     if( !mpImpl->mxStatusListener.is() )
1753         mpImpl->mxStatusListener.set( new ToolbarMenuStatusListener( mpImpl->mxServiceManager, mpImpl->mxFrame, *this ) );
1754 }
1755 
1756 // --------------------------------------------------------------------
1757 
1758 bool ToolbarMenu::IsInPopupMode()
1759 {
1760     return GetDockingManager()->IsInPopupMode(this);
1761 }
1762 
1763 // --------------------------------------------------------------------
1764 
1765 void ToolbarMenu::EndPopupMode()
1766 {
1767     GetDockingManager()->EndPopupMode(this);
1768 }
1769 
1770 // --------------------------------------------------------------------
1771 
1772 const Size& ToolbarMenu::getMenuSize() const
1773 {
1774     return mpImpl->maSize;
1775 }
1776 
1777 // --------------------------------------------------------------------
1778 
1779 void ToolbarMenu::SetSelectHdl( const Link& rLink )
1780 {
1781     mpImpl->maSelectHdl = rLink;
1782 }
1783 
1784 // --------------------------------------------------------------------
1785 
1786 const Link& ToolbarMenu::GetSelectHdl() const
1787 {
1788     return mpImpl->maSelectHdl;
1789 }
1790 
1791 // --------------------------------------------------------------------
1792 
1793 Reference< XFrame > ToolbarMenu::GetFrame() const
1794 {
1795     return mpImpl->mxFrame;
1796 }
1797 
1798 // --------------------------------------------------------------------
1799 
1800 
1801 // --------------------------------------------------------------------
1802 
1803 }
1804 
1805 
1806