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