xref: /core/vcl/source/window/toolbox2.cxx (revision d4f07d4c)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 #include <utility>
22 #include <vcl/uitest/logger.hxx>
23 #include <sal/log.hxx>
24 
25 #include <comphelper/base64.hxx>
26 #include <comphelper/processfactory.hxx>
27 #include <boost/property_tree/ptree.hpp>
28 
29 #include <vcl/cvtgrf.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/idle.hxx>
32 #include <vcl/bitmap.hxx>
33 #include <vcl/toolkit/floatwin.hxx>
34 #include <vcl/toolbox.hxx>
35 #include <vcl/mnemonic.hxx>
36 #include <vcl/menu.hxx>
37 #include <vcl/settings.hxx>
38 #include <vcl/IconThemeInfo.hxx>
39 #include <vcl/commandinfoprovider.hxx>
40 
41 #include <svdata.hxx>
42 #include <brdwin.hxx>
43 #include <toolbox.h>
44 
45 #include <unotools/confignode.hxx>
46 #include <tools/json_writer.hxx>
47 
48 #include <vcl/uitest/uiobject.hxx>
49 
50 #include "impldockingwrapper.hxx"
51 
52 using namespace vcl;
53 
54 #define TB_SEP_SIZE     8  // Separator size
55 
56 
ImplToolBoxPrivateData()57 ImplToolBoxPrivateData::ImplToolBoxPrivateData()
58 {
59     meButtonSize = ToolBoxButtonSize::DontCare;
60     mpMenu = VclPtr<PopupMenu>::Create();
61 
62     maMenuType = ToolBoxMenuType::NONE;
63     maMenubuttonItem.maItemSize = Size( TB_MENUBUTTON_SIZE+TB_MENUBUTTON_OFFSET, TB_MENUBUTTON_SIZE+TB_MENUBUTTON_OFFSET );
64     maMenubuttonItem.meState = TRISTATE_FALSE;
65     mnMenuButtonWidth = TB_MENUBUTTON_SIZE;
66 
67     mbIsLocked = false;
68     mbNativeButtons = false;
69     mbIsPaintLocked = false;
70     mbAssumeDocked = false;
71     mbAssumePopupMode = false;
72     mbAssumeFloating = false;
73     mbKeyInputDisabled = false;
74     mbMenubuttonSelected = false;
75     mbMenubuttonWasLastSelected = false;
76     mbWillUsePopupMode = false;
77     mbDropDownByKeyboard = false;
78 }
79 
~ImplToolBoxPrivateData()80 ImplToolBoxPrivateData::~ImplToolBoxPrivateData()
81 {
82     m_pLayoutData.reset();
83     mpMenu.disposeAndClear();
84 }
85 
init(ToolBoxItemId nItemId,ToolBoxItemBits nItemBits,bool bEmptyBtn)86 void ImplToolItem::init(ToolBoxItemId nItemId, ToolBoxItemBits nItemBits,
87                         bool bEmptyBtn)
88 {
89     mnId            = nItemId;
90     mpWindow        = nullptr;
91     mbNonInteractiveWindow = false;
92     mpUserData      = nullptr;
93     meType          = ToolBoxItemType::BUTTON;
94     mnBits          = nItemBits;
95     meState         = TRISTATE_FALSE;
96     mbEnabled       = true;
97     mbVisible       = true;
98     mbEmptyBtn      = bEmptyBtn;
99     mbShowWindow    = false;
100     mbBreak         = false;
101     mnSepSize       = TB_SEP_SIZE;
102     mnDropDownArrowWidth = TB_DROPDOWNARROWWIDTH;
103     mnImageAngle    = 0_deg10;
104     mbMirrorMode    = false;
105     mbVisibleText   = false;
106     mbExpand        = false;
107 }
108 
ImplToolItem()109 ImplToolItem::ImplToolItem()
110 {
111     init(ToolBoxItemId(0), ToolBoxItemBits::NONE, true);
112 }
113 
ImplToolItem(ToolBoxItemId nItemId,Image aImage,ToolBoxItemBits nItemBits)114 ImplToolItem::ImplToolItem( ToolBoxItemId nItemId, Image aImage,
115                             ToolBoxItemBits nItemBits ) :
116     maImage(std::move( aImage ))
117 {
118     init(nItemId, nItemBits, false);
119 }
120 
ImplToolItem(ToolBoxItemId nItemId,OUString aText,OUString aCommand,ToolBoxItemBits nItemBits)121 ImplToolItem::ImplToolItem( ToolBoxItemId nItemId, OUString aText,
122                             OUString aCommand, ToolBoxItemBits nItemBits ) :
123     maText(std::move( aText )),
124     maCommandStr(std::move( aCommand ))
125 {
126     init(nItemId, nItemBits, false);
127 }
128 
ImplToolItem(ToolBoxItemId nItemId,Image aImage,OUString aText,ToolBoxItemBits nItemBits)129 ImplToolItem::ImplToolItem( ToolBoxItemId nItemId, Image aImage,
130                             OUString aText, ToolBoxItemBits nItemBits ) :
131     maImage(std::move( aImage )),
132     maText(std::move( aText ))
133 {
134     init(nItemId, nItemBits, false);
135 }
136 
GetSize(bool bHorz,bool bCheckMaxWidth,tools::Long maxWidth,const Size & rDefaultSize)137 Size ImplToolItem::GetSize( bool bHorz, bool bCheckMaxWidth, tools::Long maxWidth, const Size& rDefaultSize )
138 {
139     Size aSize( rDefaultSize ); // the size of 'standard' toolbox items
140                                 // non-standard items are eg windows or buttons with text
141 
142     if ( (meType == ToolBoxItemType::BUTTON) || (meType == ToolBoxItemType::SPACE) )
143     {
144         aSize = maItemSize;
145 
146         if ( mpWindow && bHorz )
147         {
148             // get size of item window and check if it fits
149             // no windows in vertical toolbars (the default is mbShowWindow=false)
150             Size aWinSize = mpWindow->GetSizePixel();
151 
152             if (mpWindow->GetStyle() & WB_NOLABEL)
153                 // Window wants no label? Then don't check width, it'll be just
154                 // clipped.
155                 bCheckMaxWidth = false;
156 
157             if ( !bCheckMaxWidth || (aWinSize.Width() <= maxWidth) )
158             {
159                 aSize.setWidth( aWinSize.Width() );
160                 aSize.setHeight( aWinSize.Height() );
161                 mbShowWindow = true;
162             }
163             else
164             {
165                 if ( mbEmptyBtn )
166                 {
167                     aSize.setWidth( 0 );
168                     aSize.setHeight( 0 );
169                 }
170             }
171         }
172     }
173     else if ( meType == ToolBoxItemType::SEPARATOR )
174     {
175         if ( bHorz )
176         {
177             aSize.setWidth( mnSepSize );
178             aSize.setHeight( rDefaultSize.Height() );
179         }
180         else
181         {
182             aSize.setWidth( rDefaultSize.Width() );
183             aSize.setHeight( mnSepSize );
184         }
185     }
186     else if ( meType == ToolBoxItemType::BREAK )
187     {
188         aSize.setWidth( 0 );
189         aSize.setHeight( 0 );
190     }
191 
192     return aSize;
193 }
194 
DetermineButtonDrawStyle(ButtonType eButtonType,bool & rbImage,bool & rbText) const195 void ImplToolItem::DetermineButtonDrawStyle( ButtonType eButtonType, bool& rbImage, bool& rbText ) const
196 {
197     if ( meType != ToolBoxItemType::BUTTON )
198     {
199         // no button -> draw nothing
200         rbImage = rbText = false;
201         return;
202     }
203 
204     bool bHasImage;
205     bool bHasText;
206 
207     // check for image and/or text
208     bHasImage = !!maImage;
209     bHasText = !maText.isEmpty();
210 
211     // prefer images if symbolonly buttons are drawn
212     // prefer texts if textonly buttons are drawn
213 
214     if ( eButtonType == ButtonType::SYMBOLONLY )         // drawing icons only
215     {
216         if( bHasImage || !bHasText )
217         {
218             rbImage = true;
219             rbText  = false;
220         }
221         else
222         {
223             rbImage = false;
224             rbText  = true;
225         }
226     }
227     else if ( eButtonType == ButtonType::TEXT )      // drawing text only
228     {
229         if( bHasText || !bHasImage )
230         {
231             rbImage = false;
232             rbText  = true;
233         }
234         else
235         {
236             rbImage = true;
237             rbText  = false;
238         }
239     }
240     else                                        // drawing icons and text both
241     {
242         rbImage = true;
243         rbText  = true;
244     }
245 }
246 
GetDropDownRect(bool bHorz) const247 tools::Rectangle ImplToolItem::GetDropDownRect( bool bHorz ) const
248 {
249     tools::Rectangle aRect;
250     if( (mnBits & ToolBoxItemBits::DROPDOWN) && !maRect.IsEmpty() )
251     {
252         aRect = maRect;
253         if( mbVisibleText && !bHorz )
254             // item will be rotated -> place dropdown to the bottom
255             aRect.SetTop( aRect.Bottom() - mnDropDownArrowWidth );
256         else
257             // place dropdown to the right
258             aRect.SetLeft( aRect.Right() - mnDropDownArrowWidth );
259     }
260     return aRect;
261 }
262 
IsClipped() const263 bool ImplToolItem::IsClipped() const
264 {
265     return ( meType == ToolBoxItemType::BUTTON && mbVisible && maRect.IsEmpty() );
266 }
267 
IsItemHidden() const268 bool ImplToolItem::IsItemHidden() const
269 {
270     return ( meType == ToolBoxItemType::BUTTON && !mbVisible );
271 }
272 
ImplInvalidate(bool bNewCalc,bool bFullPaint)273 void ToolBox::ImplInvalidate( bool bNewCalc, bool bFullPaint )
274 {
275     ImplUpdateInputEnable();
276 
277     if ( bNewCalc )
278         mbCalc = true;
279 
280     if ( bFullPaint )
281     {
282         mbFormat = true;
283 
284         // do we need to redraw?
285         if ( IsReallyVisible() && IsUpdateMode() )
286         {
287             Invalidate( tools::Rectangle( mnLeftBorder, mnTopBorder,
288                                    mnDX-mnRightBorder-1, mnDY-mnBottomBorder-1 ) );
289             mpIdle->Stop();
290         }
291     }
292     else
293     {
294         if ( !mbFormat )
295         {
296             mbFormat = true;
297 
298             // do we need to redraw?
299             if ( IsReallyVisible() && IsUpdateMode() )
300                 mpIdle->Start();
301         }
302     }
303 
304     // request new layout by layoutmanager
305     CallEventListeners( VclEventId::ToolboxFormatChanged );
306 }
307 
ImplUpdateItem(ImplToolItems::size_type nIndex)308 void ToolBox::ImplUpdateItem( ImplToolItems::size_type nIndex )
309 {
310     // do we need to redraw?
311     if ( !(IsReallyVisible() && IsUpdateMode()) )
312         return;
313 
314     if ( nIndex == ITEM_NOTFOUND )
315     {
316         // #i52217# no immediate draw as this might lead to paint problems
317         Invalidate( tools::Rectangle( mnLeftBorder, mnTopBorder, mnDX-mnRightBorder-1, mnDY-mnBottomBorder-1 ) );
318     }
319     else
320     {
321         if ( !mbFormat )
322         {
323             // #i52217# no immediate draw as this might lead to paint problems
324             Invalidate( mpData->m_aItems[nIndex].maRect );
325         }
326         else
327             maPaintRect.Union( mpData->m_aItems[nIndex].maRect );
328     }
329 }
330 
Click()331 void ToolBox::Click()
332 {
333     CallEventListeners( VclEventId::ToolboxClick );
334     maClickHdl.Call( this );
335     UITestLogger::getInstance().logAction( this, VclEventId::ToolboxClick);
336 }
337 
DoubleClick()338 void ToolBox::DoubleClick()
339 {
340     CallEventListeners( VclEventId::ToolboxDoubleClick );
341     maDoubleClickHdl.Call( this );
342 }
343 
Activate()344 void ToolBox::Activate()
345 {
346     mnActivateCount++;
347     CallEventListeners( VclEventId::ToolboxActivate );
348     maActivateHdl.Call( this );
349 }
350 
Deactivate()351 void ToolBox::Deactivate()
352 {
353     mnActivateCount--;
354     CallEventListeners( VclEventId::ToolboxDeactivate );
355     maDeactivateHdl.Call( this );
356 }
357 
Highlight()358 void ToolBox::Highlight()
359 {
360     CallEventListeners( VclEventId::ToolboxHighlight );
361 }
362 
GetUITestFactory() const363 FactoryFunction ToolBox::GetUITestFactory() const
364 {
365     return ToolBoxUIObject::create;
366 }
367 
Select()368 void ToolBox::Select()
369 {
370     VclPtr<vcl::Window> xWindow = this;
371 
372     CallEventListeners( VclEventId::ToolboxSelect );
373     maSelectHdl.Call( this );
374 
375     if ( xWindow->isDisposed() )
376         return;
377 
378     // TODO: GetFloatingWindow in DockingWindow is currently inline, change it to check dockingwrapper
379     ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
380     if( pWrapper && pWrapper->GetFloatingWindow() && static_cast<FloatingWindow*>(pWrapper->GetFloatingWindow())->IsInPopupMode() )
381         static_cast<FloatingWindow*>(pWrapper->GetFloatingWindow())->EndPopupMode();
382 }
383 
InsertItem(ToolBoxItemId nItemId,const Image & rImage,ToolBoxItemBits nBits,ImplToolItems::size_type nPos)384 void ToolBox::InsertItem( ToolBoxItemId nItemId, const Image& rImage, ToolBoxItemBits nBits, ImplToolItems::size_type nPos )
385 {
386     SAL_WARN_IF( !nItemId, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
387     SAL_WARN_IF( GetItemPos( nItemId ) != ITEM_NOTFOUND, "vcl",
388                 "ToolBox::InsertItem(): ItemId already exists" );
389 
390     // create item and add to list
391     mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(),
392                              ImplToolItem( nItemId, rImage, nBits ) );
393     mpData->ImplClearLayoutData();
394 
395     ImplInvalidate( true );
396 
397     // Notify
398     ImplToolItems::size_type nNewPos = ( nPos == APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos;
399     CallEventListeners( VclEventId::ToolboxItemAdded, reinterpret_cast< void* >(nNewPos ) );
400 }
401 
InsertItem(ToolBoxItemId nItemId,const Image & rImage,const OUString & rText,ToolBoxItemBits nBits,ImplToolItems::size_type nPos)402 void ToolBox::InsertItem( ToolBoxItemId nItemId, const Image& rImage, const OUString& rText, ToolBoxItemBits nBits,
403                           ImplToolItems::size_type nPos )
404 {
405     SAL_WARN_IF( !nItemId, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
406     SAL_WARN_IF( GetItemPos( nItemId ) != ITEM_NOTFOUND, "vcl",
407                 "ToolBox::InsertItem(): ItemId already exists" );
408 
409     // create item and add to list
410     mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(),
411                              ImplToolItem( nItemId, rImage, MnemonicGenerator::EraseAllMnemonicChars(rText), nBits ) );
412     mpData->ImplClearLayoutData();
413 
414     ImplInvalidate( true );
415 
416     // Notify
417     ImplToolItems::size_type nNewPos = ( nPos == APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos;
418     CallEventListeners( VclEventId::ToolboxItemAdded, reinterpret_cast< void* >( nNewPos ) );
419 }
420 
InsertItem(ToolBoxItemId nItemId,const OUString & rText,const OUString & rCommand,ToolBoxItemBits nBits,ImplToolItems::size_type nPos)421 void ToolBox::InsertItem( ToolBoxItemId nItemId, const OUString& rText, const OUString& rCommand, ToolBoxItemBits nBits,
422                           ImplToolItems::size_type nPos )
423 {
424     SAL_WARN_IF( !nItemId, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
425     SAL_WARN_IF( GetItemPos( nItemId ) != ITEM_NOTFOUND, "vcl",
426                 "ToolBox::InsertItem(): ItemId already exists" );
427 
428     // create item and add to list
429     mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(),
430                              ImplToolItem( nItemId, MnemonicGenerator::EraseAllMnemonicChars(rText), rCommand, nBits ) );
431     mpData->ImplClearLayoutData();
432 
433     ImplInvalidate( true );
434 
435     // Notify
436     ImplToolItems::size_type nNewPos = ( nPos == APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos;
437     CallEventListeners( VclEventId::ToolboxItemAdded, reinterpret_cast< void* >( nNewPos ) );
438 }
439 
InsertItem(const OUString & rCommand,const css::uno::Reference<css::frame::XFrame> & rFrame,ToolBoxItemBits nBits,const Size & rRequestedSize,ImplToolItems::size_type nPos)440 void ToolBox::InsertItem(const OUString& rCommand, const css::uno::Reference<css::frame::XFrame>& rFrame, ToolBoxItemBits nBits,
441                          const Size& rRequestedSize, ImplToolItems::size_type nPos)
442 {
443     OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(rFrame));
444     auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(rCommand, aModuleName);
445     OUString aLabel(vcl::CommandInfoProvider::GetLabelForCommand(aProperties));
446     OUString aTooltip(vcl::CommandInfoProvider::GetTooltipForCommand(rCommand, aProperties, rFrame));
447     Image aImage(CommandInfoProvider::GetImageForCommand(rCommand, rFrame, GetImageSize()));
448 
449     ToolBoxItemId nItemId(GetItemCount() + 1);
450         //TODO: ImplToolItems::size_type -> sal_uInt16!
451     InsertItem(nItemId, aLabel, rCommand, nBits, nPos);
452     SetItemImage(nItemId, aImage);
453     SetQuickHelpText(nItemId, aTooltip);
454 
455     // set the minimal size
456     ImplToolItem* pItem = ImplGetItem( nItemId );
457     if ( pItem )
458         pItem->maMinimalItemSize = rRequestedSize;
459 }
460 
InsertWindow(ToolBoxItemId nItemId,vcl::Window * pWindow,ToolBoxItemBits nBits,ImplToolItems::size_type nPos)461 void ToolBox::InsertWindow( ToolBoxItemId nItemId, vcl::Window* pWindow,
462                             ToolBoxItemBits nBits, ImplToolItems::size_type nPos )
463 {
464     SAL_WARN_IF( !nItemId, "vcl", "ToolBox::InsertWindow(): ItemId == 0" );
465     SAL_WARN_IF( GetItemPos( nItemId ) != ITEM_NOTFOUND, "vcl",
466                 "ToolBox::InsertWindow(): ItemId already exists" );
467 
468     // create item and add to list
469     ImplToolItem aItem;
470     aItem.mnId       = nItemId;
471     aItem.meType     = ToolBoxItemType::BUTTON;
472     aItem.mnBits     = nBits;
473     aItem.mpWindow   = pWindow;
474     mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), aItem );
475     mpData->ImplClearLayoutData();
476 
477     if ( pWindow )
478         pWindow->Hide();
479 
480     ImplInvalidate( true );
481 
482     // Notify
483     ImplToolItems::size_type nNewPos = ( nPos == APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos;
484     CallEventListeners( VclEventId::ToolboxItemAdded, reinterpret_cast< void* >( nNewPos ) );
485 }
486 
InsertSpace()487 void ToolBox::InsertSpace()
488 {
489     // create item and add to list
490     ImplToolItem aItem;
491     aItem.meType     = ToolBoxItemType::SPACE;
492     aItem.mbEnabled  = false;
493     mpData->m_aItems.push_back( aItem );
494     mpData->ImplClearLayoutData();
495 
496     ImplInvalidate();
497 
498     // Notify
499     ImplToolItems::size_type nNewPos = mpData->m_aItems.size() - 1;
500     CallEventListeners( VclEventId::ToolboxItemAdded, reinterpret_cast< void* >( nNewPos ) );
501 }
502 
InsertSeparator(ImplToolItems::size_type nPos,sal_uInt16 nPixSize)503 void ToolBox::InsertSeparator( ImplToolItems::size_type nPos, sal_uInt16 nPixSize )
504 {
505     // create item and add to list
506     ImplToolItem aItem;
507     aItem.meType     = ToolBoxItemType::SEPARATOR;
508     aItem.mbEnabled  = false;
509     if ( nPixSize )
510         aItem.mnSepSize = nPixSize;
511     mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), aItem );
512     mpData->ImplClearLayoutData();
513 
514     ImplInvalidate();
515 
516     // Notify
517     ImplToolItems::size_type nNewPos = ( nPos == APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos;
518     CallEventListeners( VclEventId::ToolboxItemAdded, reinterpret_cast< void* >( nNewPos ) );
519 }
520 
InsertBreak(ImplToolItems::size_type nPos)521 void ToolBox::InsertBreak( ImplToolItems::size_type nPos )
522 {
523     // create item and add to list
524     ImplToolItem aItem;
525     aItem.meType     = ToolBoxItemType::BREAK;
526     aItem.mbEnabled  = false;
527     mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), aItem );
528     mpData->ImplClearLayoutData();
529 
530     ImplInvalidate();
531 
532     // Notify
533     ImplToolItems::size_type nNewPos = ( nPos == APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos;
534     CallEventListeners( VclEventId::ToolboxItemAdded, reinterpret_cast< void* >( nNewPos ) );
535 }
536 
RemoveItem(ImplToolItems::size_type nPos)537 void ToolBox::RemoveItem( ImplToolItems::size_type nPos )
538 {
539     if( nPos >= mpData->m_aItems.size() )
540         return;
541 
542     bool bMustCalc;
543     bMustCalc = mpData->m_aItems[nPos].meType == ToolBoxItemType::BUTTON;
544 
545     if ( mpData->m_aItems[nPos].mpWindow )
546         mpData->m_aItems[nPos].mpWindow->Hide();
547 
548     // add the removed item to PaintRect
549     maPaintRect.Union( mpData->m_aItems[nPos].maRect );
550 
551     // ensure not to delete in the Select-Handler
552     if ( mpData->m_aItems[nPos].mnId == mnCurItemId )
553         mnCurItemId = ToolBoxItemId(0);
554     if ( mpData->m_aItems[nPos].mnId == mnHighItemId )
555         mnHighItemId = ToolBoxItemId(0);
556 
557     ImplInvalidate( bMustCalc );
558 
559     mpData->m_aItems.erase( mpData->m_aItems.begin()+nPos );
560     mpData->ImplClearLayoutData();
561 
562     // Notify
563     CallEventListeners( VclEventId::ToolboxItemRemoved, reinterpret_cast< void* >( nPos ) );
564 }
565 
CopyItem(const ToolBox & rToolBox,ToolBoxItemId nItemId)566 void ToolBox::CopyItem( const ToolBox& rToolBox, ToolBoxItemId nItemId )
567 {
568     SAL_WARN_IF( GetItemPos( nItemId ) != ITEM_NOTFOUND, "vcl",
569                 "ToolBox::CopyItem(): ItemId already exists" );
570 
571     ImplToolItems::size_type nPos = rToolBox.GetItemPos( nItemId );
572 
573     // found item
574     if ( nPos == ITEM_NOTFOUND )
575         return;
576 
577     // push ToolBox item onto the list
578     ImplToolItem aNewItem = rToolBox.mpData->m_aItems[nPos];
579     // reset state
580     aNewItem.mpWindow      = nullptr;
581     aNewItem.mbShowWindow = false;
582 
583     mpData->m_aItems.push_back( aNewItem );
584     mpData->ImplClearLayoutData();
585     // redraw ToolBox
586     ImplInvalidate();
587 
588     // Notify
589     ImplToolItems::size_type nNewPos2 = mpData->m_aItems.size() - 1;
590     CallEventListeners( VclEventId::ToolboxItemAdded, reinterpret_cast< void* >( nNewPos2 ) );
591 }
592 
Clear()593 void ToolBox::Clear()
594 {
595     mpData->m_aItems.clear();
596     mpData->ImplClearLayoutData();
597 
598     // ensure not to delete in the Select-Handler
599     mnCurItemId = ToolBoxItemId(0);
600     mnHighItemId = ToolBoxItemId(0);
601 
602     ImplInvalidate( true, true );
603 
604     // Notify
605     CallEventListeners( VclEventId::ToolboxAllItemsChanged );
606 }
607 
SetButtonType(ButtonType eNewType)608 void ToolBox::SetButtonType( ButtonType eNewType )
609 {
610     if ( meButtonType != eNewType )
611     {
612         meButtonType = eNewType;
613 
614         // better redraw everything, as otherwise there might be problems
615         // with regions that were copied with CopyBits
616         ImplInvalidate( true );
617     }
618 }
619 
SetToolboxButtonSize(ToolBoxButtonSize eSize)620 void ToolBox::SetToolboxButtonSize( ToolBoxButtonSize eSize )
621 {
622     if( mpData->meButtonSize != eSize )
623     {
624         mpData->meButtonSize = eSize;
625         mbCalc = true;
626         mbFormat = true;
627     }
628 }
629 
GetToolboxButtonSize() const630 ToolBoxButtonSize ToolBox::GetToolboxButtonSize() const
631 {
632     return mpData->meButtonSize;
633 }
634 
GetImageSize() const635 ImageType ToolBox::GetImageSize() const
636 {
637     ImageType eImageType = ImageType::Size16;
638     if (mpData->meButtonSize == ToolBoxButtonSize::Large)
639         eImageType = ImageType::Size26;
640     else if (mpData->meButtonSize == ToolBoxButtonSize::Size32)
641         eImageType = ImageType::Size32;
642 
643     return eImageType;
644 }
645 
GetDefaultImageSize(ToolBoxButtonSize eToolBoxButtonSize)646 /*static*/ Size ToolBox::GetDefaultImageSize(ToolBoxButtonSize eToolBoxButtonSize)
647 {
648     OutputDevice *pDefault = Application::GetDefaultDevice();
649     float fScaleFactor = pDefault ? pDefault->GetDPIScaleFactor() : 1.0;
650 
651     Size aUnscaledSize(16, 16);
652 
653     if (eToolBoxButtonSize == ToolBoxButtonSize::Large)
654     {
655         OUString iconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme();
656         aUnscaledSize = vcl::IconThemeInfo::SizeByThemeName(iconTheme);
657     }
658     else if (eToolBoxButtonSize == ToolBoxButtonSize::Size32)
659     {
660         aUnscaledSize = Size(32, 32);
661     }
662     return Size(aUnscaledSize.Width()  * fScaleFactor,
663                 aUnscaledSize.Height() * fScaleFactor);
664 }
665 
GetDefaultImageSize() const666 Size ToolBox::GetDefaultImageSize() const
667 {
668     return GetDefaultImageSize(GetToolboxButtonSize());
669 }
670 
SetAlign(WindowAlign eNewAlign)671 void ToolBox::SetAlign( WindowAlign eNewAlign )
672 {
673     if ( meAlign == eNewAlign )
674         return;
675 
676     meAlign = eNewAlign;
677 
678     if ( ImplIsFloatingMode() )
679         return;
680 
681     // set horizontal/vertical alignment
682     if ( (eNewAlign == WindowAlign::Left) || (eNewAlign == WindowAlign::Right) )
683         mbHorz = false;
684     else
685         mbHorz = true;
686 
687     // Update the background according to Persona if necessary
688     ImplInitSettings( false, false, true );
689 
690     // redraw everything, as the border has changed
691     mbCalc = true;
692     mbFormat = true;
693     if ( IsReallyVisible() && IsUpdateMode() )
694         Invalidate();
695 }
696 
SetLineCount(ImplToolItems::size_type nNewLines)697 void ToolBox::SetLineCount( ImplToolItems::size_type nNewLines )
698 {
699     if ( !nNewLines )
700         nNewLines = 1;
701 
702     if ( mnLines != nNewLines )
703     {
704         mnLines = nNewLines;
705 
706         // better redraw everything, as otherwise there might be problems
707         // with regions that were copied with CopyBits
708         Invalidate();
709     }
710 }
711 
GetItemCount() const712 ToolBox::ImplToolItems::size_type ToolBox::GetItemCount() const
713 {
714     return mpData ? mpData->m_aItems.size() : 0;
715 }
716 
GetItemType(ImplToolItems::size_type nPos) const717 ToolBoxItemType ToolBox::GetItemType( ImplToolItems::size_type nPos ) const
718 {
719     return (nPos < mpData->m_aItems.size()) ? mpData->m_aItems[nPos].meType : ToolBoxItemType::DONTKNOW;
720 }
721 
GetItemPos(ToolBoxItemId nItemId) const722 ToolBox::ImplToolItems::size_type ToolBox::GetItemPos( ToolBoxItemId nItemId ) const
723 {
724     if (mpData)
725     {
726         ImplToolItems::size_type nCount = mpData->m_aItems.size();
727         for( ImplToolItems::size_type nPos = 0; nPos < nCount; nPos++ )
728             if( mpData->m_aItems[nPos].mnId == nItemId )
729                 return nPos;
730     }
731     return ITEM_NOTFOUND;
732 }
733 
GetItemPos(const Point & rPos) const734 ToolBox::ImplToolItems::size_type ToolBox::GetItemPos( const Point& rPos ) const
735 {
736     // search the item position on the given point
737     auto it = std::find_if(mpData->m_aItems.begin(), mpData->m_aItems.end(),
738         [&rPos](const ImplToolItem& rItem) { return rItem.maRect.Contains( rPos ); });
739 
740     if( it != mpData->m_aItems.end() )
741         return std::distance(mpData->m_aItems.begin(), it);
742 
743     return ITEM_NOTFOUND;
744 }
745 
GetItemId(ImplToolItems::size_type nPos) const746 ToolBoxItemId ToolBox::GetItemId( ImplToolItems::size_type nPos ) const
747 {
748     return (nPos < mpData->m_aItems.size()) ? mpData->m_aItems[nPos].mnId : ToolBoxItemId(0);
749 }
750 
GetItemId(const Point & rPos) const751 ToolBoxItemId ToolBox::GetItemId( const Point& rPos ) const
752 {
753     // find item that was clicked
754     auto it = std::find_if(mpData->m_aItems.begin(), mpData->m_aItems.end(),
755         [&rPos](const ImplToolItem& rItem) { return rItem.maRect.Contains( rPos ); });
756 
757     if( (it != mpData->m_aItems.end()) && (it->meType == ToolBoxItemType::BUTTON) )
758         return it->mnId;
759 
760     return ToolBoxItemId(0);
761 }
762 
GetItemContentSize(ToolBoxItemId nItemId)763 Size ToolBox::GetItemContentSize( ToolBoxItemId nItemId )
764 {
765     if ( mbCalc || mbFormat )
766         ImplFormat();
767 
768     ImplToolItems::size_type nPos = GetItemPos( nItemId );
769     if ( nPos < mpData->m_aItems.size() )
770         return mpData->m_aItems[nPos].maContentSize;
771     else
772         return Size();
773 }
774 
GetItemId(const OUString & rCommand) const775 ToolBoxItemId ToolBox::GetItemId(const OUString &rCommand) const
776 {
777     if (!mpData)
778         return ToolBoxItemId(0);
779 
780     auto it = std::find_if(mpData->m_aItems.begin(), mpData->m_aItems.end(),
781         [&rCommand](const ImplToolItem& rItem) { return rItem.maCommandStr == rCommand; });
782     if (it != mpData->m_aItems.end())
783         return it->mnId;
784 
785     return ToolBoxItemId(0);
786 }
787 
ImplGetPopupPosition(const tools::Rectangle & rRect) const788 Point ToolBox::ImplGetPopupPosition( const tools::Rectangle& rRect ) const
789 {
790     Point aPos;
791     if( !rRect.IsEmpty() )
792     {
793         AbsoluteScreenPixelRectangle aScreen = GetDesktopRectPixel();
794 
795         // the popup should be positioned so that it will not cover
796         // the item rect and that it fits the desktop
797         // the preferred direction is always towards the center of
798         // the application window
799 
800         AbsoluteScreenPixelPoint devPos; // the position in device coordinates for screen comparison
801         switch( meAlign )
802         {
803             case WindowAlign::Top:
804                 aPos = rRect.BottomLeft();
805                 aPos.AdjustY( 1 );
806                 devPos = OutputToAbsoluteScreenPixel( aPos );
807                 if( devPos.Y() >= aScreen.Bottom() )
808                     aPos.setY( rRect.Top() );
809                 break;
810             case WindowAlign::Bottom:
811                 aPos = rRect.TopLeft();
812                 aPos.AdjustY( -1 );
813                 devPos = OutputToAbsoluteScreenPixel( aPos );
814                 if( devPos.Y() <= aScreen.Top() )
815                     aPos.setY( rRect.Bottom() );
816                 break;
817             case WindowAlign::Left:
818                 aPos = rRect.TopRight();
819                 aPos.AdjustX( 1 );
820                 devPos = OutputToAbsoluteScreenPixel( aPos );
821                 if( devPos.X() >= aScreen.Right() )
822                     aPos.setX( rRect.Left() );
823                 break;
824             case WindowAlign::Right:
825                 aPos = rRect.TopLeft();
826                 aPos.AdjustX( -1 );
827                 devPos = OutputToAbsoluteScreenPixel( aPos );
828                 if( devPos.X() <= aScreen.Left() )
829                     aPos.setX( rRect.Right() );
830                 break;
831             default:
832                 break;
833         }
834     }
835     return aPos;
836 }
837 
GetItemRect(ToolBoxItemId nItemId)838 tools::Rectangle ToolBox::GetItemRect( ToolBoxItemId nItemId )
839 {
840     if ( mbCalc || mbFormat )
841         ImplFormat();
842 
843     ImplToolItems::size_type nPos = GetItemPos( nItemId );
844     return GetItemPosRect( nPos );
845 }
846 
GetItemPosRect(ImplToolItems::size_type nPos)847 tools::Rectangle ToolBox::GetItemPosRect( ImplToolItems::size_type nPos )
848 {
849     if ( mbCalc || mbFormat )
850         ImplFormat();
851 
852     if ( nPos < mpData->m_aItems.size() )
853         return mpData->m_aItems[nPos].maRect;
854     else
855         return tools::Rectangle();
856 }
857 
GetOverflowRect() const858 tools::Rectangle const & ToolBox::GetOverflowRect() const
859 {
860     return mpData->maMenubuttonItem.maRect;
861 }
862 
ImplHasExternalMenubutton() const863 bool ToolBox::ImplHasExternalMenubutton() const
864 {
865     // check if the borderwindow (i.e. the decoration) provides the menu button
866     bool bRet = false;
867     if( ImplIsFloatingMode() )
868     {
869         // custom menu is placed in the decoration
870         ImplBorderWindow *pBorderWin = dynamic_cast<ImplBorderWindow*>( GetWindow( GetWindowType::Border ) );
871         if( pBorderWin && !pBorderWin->GetMenuRect().IsEmpty() )
872             bRet = true;
873     }
874     return bRet;
875 }
876 
SetItemBits(ToolBoxItemId nItemId,ToolBoxItemBits nBits)877 void ToolBox::SetItemBits( ToolBoxItemId nItemId, ToolBoxItemBits nBits )
878 {
879     ImplToolItems::size_type nPos = GetItemPos( nItemId );
880 
881     if ( nPos < GetItemCount() )
882     {
883         ToolBoxItemBits nOldBits = mpData->m_aItems[nPos].mnBits;
884         mpData->m_aItems[nPos].mnBits = nBits;
885         nBits &= ToolBoxItemBits::LEFT | ToolBoxItemBits::AUTOSIZE | ToolBoxItemBits::DROPDOWN;
886         nOldBits &= ToolBoxItemBits::LEFT | ToolBoxItemBits::AUTOSIZE | ToolBoxItemBits::DROPDOWN;
887         // trigger reformat when the item width has changed (dropdown arrow)
888         bool bFormat = ToolBoxItemBits(nBits & ToolBoxItemBits::DROPDOWN) != ToolBoxItemBits(nOldBits & ToolBoxItemBits::DROPDOWN);
889         if ( nBits != nOldBits )
890             ImplInvalidate( true, bFormat );
891     }
892 }
893 
SetItemWindowNonInteractive(ToolBoxItemId nItemId,bool bNonInteractive)894 void ToolBox::SetItemWindowNonInteractive(ToolBoxItemId nItemId, bool bNonInteractive)
895 {
896     ImplToolItems::size_type nPos = GetItemPos( nItemId );
897 
898     if ( nPos < GetItemCount() )
899     {
900         mpData->m_aItems[nPos].mbNonInteractiveWindow = bNonInteractive;
901     }
902 }
903 
GetItemBits(ToolBoxItemId nItemId) const904 ToolBoxItemBits ToolBox::GetItemBits( ToolBoxItemId nItemId ) const
905 {
906     ImplToolItem* pItem = ImplGetItem( nItemId );
907 
908     if ( pItem )
909         return pItem->mnBits;
910     else
911         return ToolBoxItemBits::NONE;
912 }
913 
SetItemExpand(ToolBoxItemId nItemId,bool bExpand)914 void ToolBox::SetItemExpand( ToolBoxItemId nItemId, bool bExpand )
915 {
916     ImplToolItem* pItem = ImplGetItem( nItemId );
917     if (!pItem)
918         return;
919 
920     if (pItem->mbExpand != bExpand)
921     {
922         pItem->mbExpand = bExpand;
923         ImplInvalidate(true, true);
924     }
925 }
926 
SetItemData(ToolBoxItemId nItemId,void * pNewData)927 void ToolBox::SetItemData( ToolBoxItemId nItemId, void* pNewData )
928 {
929     ImplToolItems::size_type nPos = GetItemPos( nItemId );
930 
931     if ( nPos < mpData->m_aItems.size() )
932     {
933         mpData->m_aItems[nPos].mpUserData = pNewData;
934         ImplUpdateItem( nPos );
935     }
936 }
937 
GetItemData(ToolBoxItemId nItemId) const938 void* ToolBox::GetItemData( ToolBoxItemId nItemId ) const
939 {
940     ImplToolItem* pItem = ImplGetItem( nItemId );
941 
942     if ( pItem )
943         return pItem->mpUserData;
944     else
945         return nullptr;
946 }
947 
ImplMirrorImage(const Image & rImage)948 static Image ImplMirrorImage( const Image& rImage )
949 {
950     BitmapEx    aMirrBitmapEx( rImage.GetBitmapEx() );
951 
952     aMirrBitmapEx.Mirror( BmpMirrorFlags::Horizontal );
953 
954     return Image( aMirrBitmapEx );
955 }
956 
ImplRotImage(const Image & rImage,Degree10 nAngle10)957 static Image ImplRotImage( const Image& rImage, Degree10 nAngle10 )
958 {
959     BitmapEx    aRotBitmapEx( rImage.GetBitmapEx() );
960 
961     aRotBitmapEx.Rotate( nAngle10, COL_WHITE );
962 
963     return Image( aRotBitmapEx );
964 }
965 
SetItemImage(ToolBoxItemId nItemId,const Image & rImage)966 void ToolBox::SetItemImage( ToolBoxItemId nItemId, const Image& rImage )
967 {
968     ImplToolItems::size_type nPos = GetItemPos( nItemId );
969 
970     if ( nPos == ITEM_NOTFOUND )
971         return;
972 
973     ImplToolItem* pItem = &mpData->m_aItems[nPos];
974     Size aOldSize = pItem->maImage.GetSizePixel();
975 
976     pItem->maImage = pItem->mbMirrorMode ? ImplMirrorImage(rImage) : rImage;
977     if (pItem->mnImageAngle != 0_deg10)
978         pItem->maImage = ImplRotImage(pItem->maImage, pItem->mnImageAngle);
979 
980     // only once all is calculated, do extra work
981     if (!mbCalc)
982     {
983         if (aOldSize != pItem->maImage.GetSizePixel())
984             ImplInvalidate( true );
985         else
986             ImplUpdateItem( nPos );
987     }
988 }
989 
SetItemImageAngle(ToolBoxItemId nItemId,Degree10 nAngle10)990 void ToolBox::SetItemImageAngle( ToolBoxItemId nItemId, Degree10 nAngle10 )
991 {
992     ImplToolItems::size_type nPos = GetItemPos( nItemId );
993 
994     if ( nPos == ITEM_NOTFOUND )
995         return;
996 
997     ImplToolItem* pItem = &mpData->m_aItems[nPos];
998     pItem->mnImageAngle = nAngle10;
999 }
1000 
SetItemImageMirrorMode(ToolBoxItemId nItemId,bool bMirror)1001 void ToolBox::SetItemImageMirrorMode( ToolBoxItemId nItemId, bool bMirror )
1002 {
1003     ImplToolItems::size_type nPos = GetItemPos( nItemId );
1004 
1005     if ( nPos == ITEM_NOTFOUND )
1006         return;
1007 
1008     ImplToolItem* pItem = &mpData->m_aItems[nPos];
1009     pItem->mbMirrorMode = bMirror;
1010 }
1011 
GetItemImage(ToolBoxItemId nItemId) const1012 Image ToolBox::GetItemImage(ToolBoxItemId nItemId) const
1013 {
1014     ImplToolItem* pItem = ImplGetItem(nItemId);
1015     return pItem ? pItem->maImage : Image();
1016 }
1017 
SetItemText(ToolBoxItemId nItemId,const OUString & rText)1018 void ToolBox::SetItemText( ToolBoxItemId nItemId, const OUString& rText )
1019 {
1020     ImplToolItems::size_type nPos = GetItemPos( nItemId );
1021 
1022     if ( nPos == ITEM_NOTFOUND )
1023         return;
1024 
1025     ImplToolItem* pItem = &mpData->m_aItems[nPos];
1026     // only once all is calculated, do extra work
1027     if ( !mbCalc &&
1028          ((meButtonType != ButtonType::SYMBOLONLY) || !pItem->maImage) )
1029     {
1030         tools::Long nOldWidth = GetOutDev()->GetCtrlTextWidth( pItem->maText );
1031         pItem->maText = MnemonicGenerator::EraseAllMnemonicChars(rText);
1032         mpData->ImplClearLayoutData();
1033         if ( nOldWidth != GetOutDev()->GetCtrlTextWidth( pItem->maText ) )
1034             ImplInvalidate( true );
1035         else
1036             ImplUpdateItem( nPos );
1037     }
1038     else
1039         pItem->maText = MnemonicGenerator::EraseAllMnemonicChars(rText);
1040 
1041     // Notify
1042     CallEventListeners( VclEventId::ToolboxItemTextChanged, reinterpret_cast< void* >( nPos ) );
1043 }
1044 
GetItemText(ToolBoxItemId nItemId) const1045 const OUString& ToolBox::GetItemText( ToolBoxItemId nItemId ) const
1046 {
1047 
1048     ImplToolItem* pItem = ImplGetItem( nItemId );
1049 
1050     assert( pItem );
1051 
1052     return pItem->maText;
1053 }
1054 
SetItemWindow(ToolBoxItemId nItemId,vcl::Window * pNewWindow)1055 void ToolBox::SetItemWindow( ToolBoxItemId nItemId, vcl::Window* pNewWindow )
1056 {
1057     ImplToolItems::size_type nPos = GetItemPos( nItemId );
1058 
1059     if ( nPos != ITEM_NOTFOUND )
1060     {
1061         ImplToolItem* pItem = &mpData->m_aItems[nPos];
1062         pItem->mpWindow = pNewWindow;
1063         if ( pNewWindow )
1064             pNewWindow->Hide();
1065         ImplInvalidate( true );
1066         CallEventListeners( VclEventId::ToolboxItemWindowChanged, reinterpret_cast< void* >( nPos ) );
1067     }
1068 }
1069 
GetItemWindow(ToolBoxItemId nItemId) const1070 vcl::Window* ToolBox::GetItemWindow( ToolBoxItemId nItemId ) const
1071 {
1072     ImplToolItem* pItem = ImplGetItem( nItemId );
1073 
1074     if ( pItem )
1075         return pItem->mpWindow;
1076     else
1077         return nullptr;
1078 }
1079 
EndSelection()1080 void ToolBox::EndSelection()
1081 {
1082     if ( mbDrag )
1083     {
1084         // reset
1085         mbDrag = false;
1086         if (mnCurPos != ITEM_NOTFOUND)
1087             InvalidateItem(mnCurPos);
1088         EndTracking();
1089         if (IsMouseCaptured())
1090             ReleaseMouse();
1091         Deactivate();
1092     }
1093 
1094     mnCurPos        = ITEM_NOTFOUND;
1095     mnCurItemId     = ToolBoxItemId(0);
1096     mnDownItemId    = ToolBoxItemId(0);
1097     mnMouseModifier = 0;
1098 }
1099 
SetItemDown(ToolBoxItemId nItemId,bool bDown)1100 void ToolBox::SetItemDown( ToolBoxItemId nItemId, bool bDown )
1101 {
1102     ImplToolItems::size_type nPos = GetItemPos( nItemId );
1103 
1104     if ( nPos == ITEM_NOTFOUND )
1105         return;
1106 
1107     if ( bDown )
1108     {
1109         if ( nPos != mnCurPos )
1110         {
1111             mnCurPos = nPos;
1112             InvalidateItem(mnCurPos);
1113             GetOutDev()->Flush();
1114         }
1115     }
1116     else
1117     {
1118         if ( nPos == mnCurPos )
1119         {
1120             InvalidateItem(mnCurPos);
1121             GetOutDev()->Flush();
1122             mnCurPos = ITEM_NOTFOUND;
1123         }
1124     }
1125 
1126     if ( mbDrag )
1127     {
1128         mbDrag = false;
1129         EndTracking();
1130         if (IsMouseCaptured())
1131             ReleaseMouse();
1132         Deactivate();
1133     }
1134 
1135     mnCurItemId     = ToolBoxItemId(0);
1136     mnDownItemId    = ToolBoxItemId(0);
1137     mnMouseModifier = 0;
1138 }
1139 
SetItemState(ToolBoxItemId nItemId,TriState eState)1140 void ToolBox::SetItemState( ToolBoxItemId nItemId, TriState eState )
1141 {
1142     ImplToolItems::size_type nPos = GetItemPos( nItemId );
1143 
1144     if ( nPos == ITEM_NOTFOUND )
1145         return;
1146 
1147     ImplToolItem* pItem = &mpData->m_aItems[nPos];
1148 
1149     // the state has changed
1150     if ( pItem->meState == eState )
1151         return;
1152 
1153     // if RadioCheck, un-check the previous
1154     if ( (eState == TRISTATE_TRUE) && (pItem->mnBits & ToolBoxItemBits::AUTOCHECK) &&
1155          (pItem->mnBits & ToolBoxItemBits::RADIOCHECK) )
1156     {
1157         ImplToolItem*    pGroupItem;
1158         ImplToolItems::size_type nGroupPos;
1159         ImplToolItems::size_type nItemCount = GetItemCount();
1160 
1161         nGroupPos = nPos;
1162         while ( nGroupPos )
1163         {
1164             pGroupItem = &mpData->m_aItems[nGroupPos-1];
1165             if ( pGroupItem->mnBits & ToolBoxItemBits::RADIOCHECK )
1166             {
1167                 if ( pGroupItem->meState != TRISTATE_FALSE )
1168                     SetItemState( pGroupItem->mnId, TRISTATE_FALSE );
1169             }
1170             else
1171                 break;
1172             nGroupPos--;
1173         }
1174 
1175         nGroupPos = nPos+1;
1176         while ( nGroupPos < nItemCount )
1177         {
1178             pGroupItem = &mpData->m_aItems[nGroupPos];
1179             if ( pGroupItem->mnBits & ToolBoxItemBits::RADIOCHECK )
1180             {
1181                 if ( pGroupItem->meState != TRISTATE_FALSE )
1182                     SetItemState( pGroupItem->mnId, TRISTATE_FALSE );
1183             }
1184             else
1185                 break;
1186             nGroupPos++;
1187         }
1188     }
1189 
1190     pItem->meState = eState;
1191     ImplUpdateItem( nPos );
1192 
1193     // Call accessible listener to notify state_changed event
1194     CallEventListeners( VclEventId::ToolboxItemUpdated, reinterpret_cast< void* >(nPos) );
1195 }
1196 
GetItemState(ToolBoxItemId nItemId) const1197 TriState ToolBox::GetItemState( ToolBoxItemId nItemId ) const
1198 {
1199     ImplToolItem* pItem = ImplGetItem( nItemId );
1200 
1201     if ( pItem )
1202         return pItem->meState;
1203     else
1204         return TRISTATE_FALSE;
1205 }
1206 
EnableItem(ToolBoxItemId nItemId,bool bEnable)1207 void ToolBox::EnableItem( ToolBoxItemId nItemId, bool bEnable )
1208 {
1209     ImplToolItems::size_type nPos = GetItemPos( nItemId );
1210 
1211     if ( nPos == ITEM_NOTFOUND )
1212         return;
1213 
1214     ImplToolItem* pItem = &mpData->m_aItems[nPos];
1215     if ( pItem->mbEnabled == bEnable )
1216         return;
1217 
1218     pItem->mbEnabled = bEnable;
1219 
1220     // if existing, also redraw the window
1221     if ( pItem->mpWindow )
1222         pItem->mpWindow->Enable( pItem->mbEnabled );
1223 
1224     // update item
1225     ImplUpdateItem( nPos );
1226 
1227     ImplUpdateInputEnable();
1228 
1229     CallEventListeners( bEnable ? VclEventId::ToolboxItemEnabled : VclEventId::ToolboxItemDisabled, reinterpret_cast< void* >( nPos ) );
1230 }
1231 
IsItemEnabled(ToolBoxItemId nItemId) const1232 bool ToolBox::IsItemEnabled( ToolBoxItemId nItemId ) const
1233 {
1234     ImplToolItem* pItem = ImplGetItem( nItemId );
1235 
1236     if ( pItem )
1237         return pItem->mbEnabled;
1238     else
1239         return false;
1240 }
1241 
ShowItem(ToolBoxItemId nItemId,bool bVisible)1242 void ToolBox::ShowItem( ToolBoxItemId nItemId, bool bVisible )
1243 {
1244     ImplToolItems::size_type nPos = GetItemPos( nItemId );
1245     mpData->ImplClearLayoutData();
1246 
1247     if ( nPos != ITEM_NOTFOUND )
1248     {
1249         ImplToolItem* pItem = &mpData->m_aItems[nPos];
1250         if ( pItem->mbVisible != bVisible )
1251         {
1252             pItem->mbVisible = bVisible;
1253             ImplInvalidate();
1254         }
1255     }
1256 }
1257 
IsItemClipped(ToolBoxItemId nItemId) const1258 bool ToolBox::IsItemClipped( ToolBoxItemId nItemId ) const
1259 {
1260     ImplToolItem* pItem = ImplGetItem( nItemId );
1261 
1262     if ( pItem )
1263         return pItem->IsClipped();
1264     else
1265         return false;
1266 }
1267 
IsItemVisible(ToolBoxItemId nItemId) const1268 bool ToolBox::IsItemVisible( ToolBoxItemId nItemId ) const
1269 {
1270     ImplToolItem* pItem = ImplGetItem( nItemId );
1271 
1272     if ( pItem )
1273         return pItem->mbVisible;
1274     else
1275         return false;
1276 }
1277 
IsItemReallyVisible(ToolBoxItemId nItemId) const1278 bool ToolBox::IsItemReallyVisible( ToolBoxItemId nItemId ) const
1279 {
1280     // is the item on the visible area of the toolbox?
1281     bool bRet = false;
1282     tools::Rectangle aRect( mnLeftBorder, mnTopBorder, mnDX-mnRightBorder, mnDY-mnBottomBorder );
1283     ImplToolItem* pItem = ImplGetItem( nItemId );
1284 
1285     if ( pItem && pItem->mbVisible &&
1286          !pItem->maRect.IsEmpty() && aRect.Overlaps( pItem->maRect ) )
1287     {
1288         bRet = true;
1289     }
1290 
1291     return bRet;
1292 }
1293 
SetItemCommand(ToolBoxItemId nItemId,const OUString & rCommand)1294 void ToolBox::SetItemCommand(ToolBoxItemId nItemId, const OUString& rCommand)
1295 {
1296     ImplToolItem* pItem = ImplGetItem( nItemId );
1297 
1298     if (pItem)
1299         pItem->maCommandStr = rCommand;
1300 }
1301 
GetItemCommand(ToolBoxItemId nItemId) const1302 OUString ToolBox::GetItemCommand( ToolBoxItemId nItemId ) const
1303 {
1304     ImplToolItem* pItem = ImplGetItem( nItemId );
1305 
1306     if (pItem)
1307         return pItem->maCommandStr;
1308 
1309     return OUString();
1310 }
1311 
SetQuickHelpText(ToolBoxItemId nItemId,const OUString & rText)1312 void ToolBox::SetQuickHelpText( ToolBoxItemId nItemId, const OUString& rText )
1313 {
1314     ImplToolItem* pItem = ImplGetItem( nItemId );
1315 
1316     if ( pItem )
1317         pItem->maQuickHelpText = rText;
1318 }
1319 
GetQuickHelpText(ToolBoxItemId nItemId) const1320 OUString ToolBox::GetQuickHelpText( ToolBoxItemId nItemId ) const
1321 {
1322     ImplToolItem* pItem = ImplGetItem( nItemId );
1323 
1324     if ( pItem )
1325         return pItem->maQuickHelpText;
1326     else
1327         return OUString();
1328 }
1329 
SetHelpText(ToolBoxItemId nItemId,const OUString & rText)1330 void ToolBox::SetHelpText( ToolBoxItemId nItemId, const OUString& rText )
1331 {
1332     ImplToolItem* pItem = ImplGetItem( nItemId );
1333 
1334     if ( pItem )
1335         pItem->maHelpText = rText;
1336 }
1337 
GetHelpText(ToolBoxItemId nItemId) const1338 const OUString& ToolBox::GetHelpText( ToolBoxItemId nItemId ) const
1339 {
1340     return ImplGetHelpText( nItemId );
1341 }
1342 
SetAccessibleName(ToolBoxItemId nItemId,const OUString & rText)1343 void ToolBox::SetAccessibleName(ToolBoxItemId nItemId, const OUString& rText)
1344 {
1345     ImplToolItem* pItem = ImplGetItem(nItemId);
1346 
1347     if (pItem)
1348         pItem->maAccessibleName = rText;
1349 }
1350 
GetAccessibleName(ToolBoxItemId nItemId) const1351 OUString ToolBox::GetAccessibleName(ToolBoxItemId nItemId) const
1352 {
1353     ImplToolItem* pItem = ImplGetItem(nItemId);
1354     if (pItem)
1355         return pItem->maAccessibleName;
1356 
1357     return OUString();
1358 }
1359 
SetHelpId(ToolBoxItemId nItemId,const OUString & rHelpId)1360 void ToolBox::SetHelpId( ToolBoxItemId nItemId, const OUString& rHelpId )
1361 {
1362     ImplToolItem* pItem = ImplGetItem( nItemId );
1363 
1364     if ( pItem )
1365         pItem->maHelpId = rHelpId;
1366 }
1367 
1368 // disable key input if all items are disabled
ImplUpdateInputEnable()1369 void ToolBox::ImplUpdateInputEnable()
1370 {
1371     mpData->mbKeyInputDisabled = std::none_of(mpData->m_aItems.begin(), mpData->m_aItems.end(),
1372         [](const ImplToolItem& rItem) {
1373             // at least one useful entry
1374             return rItem.mbEnabled;
1375         });
1376 }
1377 
ImplFillLayoutData()1378 void ToolBox::ImplFillLayoutData()
1379 {
1380     mpData->m_pLayoutData.emplace();
1381 
1382     ImplToolItems::size_type nCount = mpData->m_aItems.size();
1383     for( ImplToolItems::size_type i = 0; i < nCount; i++ )
1384     {
1385         ImplToolItem* pItem = &mpData->m_aItems[i];
1386 
1387         // only draw, if the rectangle is within PaintRectangle
1388         if (!pItem->maRect.IsEmpty())
1389             InvalidateItem(i);
1390     }
1391 }
1392 
GetDisplayText() const1393 OUString ToolBox::GetDisplayText() const
1394 {
1395     if( ! mpData->m_pLayoutData )
1396         const_cast<ToolBox *>(this)->ImplFillLayoutData();
1397     return mpData->m_pLayoutData ? mpData->m_pLayoutData->m_aDisplayText : OUString();
1398 }
1399 
GetCharacterBounds(ToolBoxItemId nItemID,tools::Long nIndex)1400 tools::Rectangle ToolBox::GetCharacterBounds( ToolBoxItemId nItemID, tools::Long nIndex )
1401 {
1402     tools::Long nItemIndex = -1;
1403     if( ! mpData->m_pLayoutData )
1404         ImplFillLayoutData();
1405     if( mpData->m_pLayoutData )
1406     {
1407         for( size_t i = 0; i < mpData->m_pLayoutData->m_aLineItemIds.size(); i++ )
1408         {
1409             if( mpData->m_pLayoutData->m_aLineItemIds[i] == nItemID )
1410             {
1411                 nItemIndex = mpData->m_pLayoutData->m_aLineIndices[i];
1412                 break;
1413             }
1414         }
1415     }
1416     return (mpData->m_pLayoutData && nItemIndex != -1) ? mpData->m_pLayoutData->GetCharacterBounds( nItemIndex+nIndex ) : tools::Rectangle();
1417 }
1418 
GetIndexForPoint(const Point & rPoint,ToolBoxItemId & rItemID)1419 tools::Long ToolBox::GetIndexForPoint( const Point& rPoint, ToolBoxItemId& rItemID )
1420 {
1421     tools::Long nIndex = -1;
1422     rItemID = ToolBoxItemId(0);
1423     if( ! mpData->m_pLayoutData )
1424         ImplFillLayoutData();
1425     if( mpData->m_pLayoutData )
1426     {
1427         nIndex = mpData->m_pLayoutData->GetIndexForPoint( rPoint );
1428         for( size_t i = 0; i < mpData->m_pLayoutData->m_aLineIndices.size(); i++ )
1429         {
1430             if( mpData->m_pLayoutData->m_aLineIndices[i] <= nIndex &&
1431                 (i == mpData->m_pLayoutData->m_aLineIndices.size()-1 || mpData->m_pLayoutData->m_aLineIndices[i+1] > nIndex) )
1432             {
1433                 rItemID = mpData->m_pLayoutData->m_aLineItemIds[i];
1434                 break;
1435             }
1436         }
1437     }
1438     return nIndex;
1439 }
1440 
SetDropdownClickHdl(const Link<ToolBox *,void> & rLink)1441 void ToolBox::SetDropdownClickHdl( const Link<ToolBox *, void>& rLink )
1442 {
1443     if (mpData != nullptr) {
1444         mpData->maDropdownClickHdl = rLink;
1445     }
1446 }
1447 
SetMenuType(ToolBoxMenuType aType)1448 void ToolBox::SetMenuType( ToolBoxMenuType aType )
1449 {
1450     if( aType == mpData->maMenuType )
1451         return;
1452 
1453     mpData->maMenuType = aType;
1454     if( IsFloatingMode() )
1455     {
1456         // the menu button may have to be moved into the decoration which changes the layout
1457         ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
1458         if( pWrapper )
1459             pWrapper->ShowMenuTitleButton( bool( aType & ToolBoxMenuType::Customize) );
1460 
1461         mbFormat = true;
1462         ImplFormat();
1463         ImplSetMinMaxFloatSize();
1464     }
1465     else
1466     {
1467         // trigger redraw of menu button
1468         if( !mpData->maMenubuttonItem.maRect.IsEmpty() )
1469             Invalidate(mpData->maMenubuttonItem.maRect);
1470     }
1471 }
1472 
GetMenuType() const1473 ToolBoxMenuType ToolBox::GetMenuType() const
1474 {
1475     return mpData->maMenuType;
1476 }
1477 
IsMenuEnabled() const1478 bool ToolBox::IsMenuEnabled() const
1479 {
1480     return mpData->maMenuType != ToolBoxMenuType::NONE;
1481 }
1482 
GetMenu() const1483 PopupMenu* ToolBox::GetMenu() const
1484 {
1485     return mpData == nullptr ? nullptr : mpData->mpMenu;
1486 }
1487 
SetMenuExecuteHdl(const Link<ToolBox *,void> & rLink)1488 void ToolBox::SetMenuExecuteHdl( const Link<ToolBox *, void>& rLink )
1489 {
1490     mpData->maMenuButtonHdl = rLink;
1491 }
1492 
ImplHasClippedItems()1493 bool ToolBox::ImplHasClippedItems()
1494 {
1495     // are any items currently clipped ?
1496     ImplFormat();
1497     return std::any_of(mpData->m_aItems.begin(), mpData->m_aItems.end(),
1498         [](const ImplToolItem& rItem) { return rItem.IsClipped(); });
1499 }
1500 
1501 namespace
1502 {
ConvertBitsFromToolBoxToMenu(ToolBoxItemBits nToolItemBits)1503     MenuItemBits ConvertBitsFromToolBoxToMenu(ToolBoxItemBits nToolItemBits)
1504     {
1505         MenuItemBits nMenuItemBits = MenuItemBits::NONE;
1506         if ((nToolItemBits & ToolBoxItemBits::CHECKABLE) ||
1507             (nToolItemBits & ToolBoxItemBits::DROPDOWN))
1508         {
1509             nMenuItemBits |= MenuItemBits::CHECKABLE;
1510         }
1511         return nMenuItemBits;
1512     }
1513 }
1514 
UpdateCustomMenu()1515 void ToolBox::UpdateCustomMenu()
1516 {
1517     // fill clipped items into menu
1518     PopupMenu *pMenu = GetMenu();
1519     pMenu->Clear();
1520 
1521     // add menu items: first the overflow items, then hidden items, both in the
1522     // order they would usually appear in the toolbar. Separators that would be
1523     // in the toolbar are ignored as they would introduce too much clutter,
1524     // instead we have a single separator to help distinguish between overflow
1525     // and hidden items.
1526     if ( mpData->m_aItems.empty() )
1527         return;
1528 
1529     // nStartPos will hold the number of clipped items appended from first loop
1530     for ( const auto& rItem : mpData->m_aItems )
1531     {
1532         if( rItem.IsClipped() )
1533         {
1534             sal_uInt16 id = sal_uInt16(rItem.mnId) + TOOLBOX_MENUITEM_START;
1535             MenuItemBits nMenuItemBits = ConvertBitsFromToolBoxToMenu(rItem.mnBits);
1536             pMenu->InsertItem( id, rItem.maText, rItem.maImage, nMenuItemBits);
1537             pMenu->SetItemCommand( id, rItem.maCommandStr );
1538             pMenu->EnableItem( id, rItem.mbEnabled );
1539             pMenu->CheckItem ( id, rItem.meState == TRISTATE_TRUE );
1540         }
1541     }
1542 
1543     // add a separator below the inserted clipped-items
1544     pMenu->InsertSeparator();
1545 
1546     // now append the items that are explicitly disabled
1547     for ( const auto& rItem : mpData->m_aItems )
1548     {
1549         if( rItem.IsItemHidden() )
1550         {
1551             sal_uInt16 id = sal_uInt16(rItem.mnId) + TOOLBOX_MENUITEM_START;
1552             MenuItemBits nMenuItemBits = ConvertBitsFromToolBoxToMenu(rItem.mnBits);
1553             pMenu->InsertItem( id, rItem.maText, rItem.maImage, nMenuItemBits );
1554             pMenu->SetItemCommand( id, rItem.maCommandStr );
1555             pMenu->EnableItem( id, rItem.mbEnabled );
1556             pMenu->CheckItem( id, rItem.meState == TRISTATE_TRUE );
1557         }
1558     }
1559 }
1560 
IMPL_LINK(ToolBox,ImplCustomMenuListener,VclMenuEvent &,rEvent,void)1561 IMPL_LINK( ToolBox, ImplCustomMenuListener, VclMenuEvent&, rEvent, void )
1562 {
1563     if( rEvent.GetMenu() == GetMenu() && rEvent.GetId() == VclEventId::MenuSelect )
1564     {
1565         sal_uInt16 id = GetMenu()->GetItemId( rEvent.GetItemPos() );
1566         if( id >= TOOLBOX_MENUITEM_START )
1567             TriggerItem( ToolBoxItemId(id - TOOLBOX_MENUITEM_START) );
1568     }
1569 }
1570 
ExecuteCustomMenu(const tools::Rectangle & rRect)1571 void ToolBox::ExecuteCustomMenu( const tools::Rectangle& rRect )
1572 {
1573     if ( !IsMenuEnabled() || ImplIsInPopupMode() )
1574         return;
1575 
1576     UpdateCustomMenu();
1577 
1578     if( GetMenuType() & ToolBoxMenuType::Customize )
1579         // call button handler to allow for menu customization
1580         mpData->maMenuButtonHdl.Call( this );
1581 
1582     GetMenu()->AddEventListener( LINK( this, ToolBox, ImplCustomMenuListener ) );
1583 
1584     // make sure all disabled entries will be shown
1585     GetMenu()->SetMenuFlags(
1586         GetMenu()->GetMenuFlags() | MenuFlags::AlwaysShowDisabledEntries );
1587 
1588     // toolbox might be destroyed during execute
1589     bool bBorderDel = false;
1590 
1591     VclPtr<vcl::Window> pWin = this;
1592     tools::Rectangle aMenuRect = rRect;
1593     VclPtr<ImplBorderWindow> pBorderWin;
1594     if( aMenuRect.IsEmpty() && IsFloatingMode() )
1595     {
1596         // custom menu is placed in the decoration
1597         pBorderWin = dynamic_cast<ImplBorderWindow*>( GetWindow( GetWindowType::Border ) );
1598         if( pBorderWin && !pBorderWin->GetMenuRect().IsEmpty() )
1599         {
1600             pWin = pBorderWin;
1601             aMenuRect = pBorderWin->GetMenuRect();
1602             bBorderDel = true;
1603         }
1604     }
1605 
1606     sal_uInt16 uId = GetMenu()->Execute( pWin, tools::Rectangle( ImplGetPopupPosition( aMenuRect ), Size() ),
1607                             PopupMenuFlags::ExecuteDown | PopupMenuFlags::NoMouseUpClose );
1608 
1609     if ( pWin->isDisposed() )
1610         return;
1611 
1612     if( GetMenu() )
1613         GetMenu()->RemoveEventListener( LINK( this, ToolBox, ImplCustomMenuListener ) );
1614     if( bBorderDel )
1615     {
1616         if( pBorderWin->isDisposed() )
1617             return;
1618     }
1619 
1620     pWin->Invalidate( aMenuRect );
1621 
1622     if( uId )
1623         GrabFocusToDocument();
1624 }
1625 
1626 // checks override first, useful during calculation of sizes
ImplIsFloatingMode() const1627 bool ToolBox::ImplIsFloatingMode() const
1628 {
1629     SAL_WARN_IF( mpData->mbAssumeDocked && mpData->mbAssumeFloating, "vcl",
1630         "cannot assume docked and floating" );
1631 
1632     if( mpData->mbAssumeDocked )
1633         return false;
1634     else if( mpData->mbAssumeFloating )
1635         return true;
1636     else
1637         return IsFloatingMode();
1638 }
1639 
1640 // checks override first, useful during calculation of sizes
ImplIsInPopupMode() const1641 bool ToolBox::ImplIsInPopupMode() const
1642 {
1643     if( mpData->mbAssumePopupMode )
1644         return true;
1645     else
1646     {
1647         ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
1648         return ( pWrapper && pWrapper->GetFloatingWindow() && static_cast<FloatingWindow*>(pWrapper->GetFloatingWindow())->IsInPopupMode() );
1649     }
1650 }
1651 
Lock(bool bLock)1652 void ToolBox::Lock( bool bLock )
1653 {
1654     ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
1655     if( !pWrapper )
1656         return;
1657     if( mpData->mbIsLocked != bLock )
1658     {
1659         mpData->mbIsLocked = bLock;
1660         if( !ImplIsFloatingMode() )
1661         {
1662             mbCalc = true;
1663             mbFormat = true;
1664             SetSizePixel( CalcWindowSizePixel(1) );
1665             Invalidate();
1666         }
1667     }
1668 }
1669 
AlwaysLocked()1670 bool ToolBox::AlwaysLocked()
1671 {
1672     // read config item to determine toolbox behaviour, used for subtoolbars
1673 
1674     static int nAlwaysLocked = -1;
1675 
1676     if( nAlwaysLocked == -1 )
1677     {
1678         nAlwaysLocked = 0; // ask configuration only once
1679 
1680         utl::OConfigurationNode aNode = utl::OConfigurationTreeRoot::tryCreateWithComponentContext(
1681             comphelper::getProcessComponentContext(),
1682             u"/org.openoffice.Office.UI.GlobalSettings/Toolbars"_ustr );    // note: case sensitive !
1683         if ( aNode.isValid() )
1684         {
1685             // feature enabled ?
1686             bool bStatesEnabled = bool();
1687             css::uno::Any aValue = aNode.getNodeValue( u"StatesEnabled"_ustr );
1688             if( aValue >>= bStatesEnabled )
1689             {
1690                 if( bStatesEnabled )
1691                 {
1692                     // now read the locking state
1693                     utl::OConfigurationNode aNode2 = utl::OConfigurationTreeRoot::tryCreateWithComponentContext(
1694                         comphelper::getProcessComponentContext(),
1695                         u"/org.openoffice.Office.UI.GlobalSettings/Toolbars/States"_ustr );    // note: case sensitive !
1696 
1697                     bool bLocked = bool();
1698                     css::uno::Any aValue2 = aNode2.getNodeValue( u"Locked"_ustr );
1699                     if( aValue2 >>= bLocked )
1700                         nAlwaysLocked = bLocked ? 1 : 0;
1701                 }
1702             }
1703         }
1704     }
1705 
1706     return nAlwaysLocked == 1;
1707 }
1708 
WillUsePopupMode() const1709 bool ToolBox::WillUsePopupMode() const
1710 {
1711     return mpData->mbWillUsePopupMode;
1712 }
1713 
WillUsePopupMode(bool b)1714 void ToolBox::WillUsePopupMode( bool b )
1715 {
1716     mpData->mbWillUsePopupMode = b;
1717 }
1718 
DumpAsPropertyTree(tools::JsonWriter & rJsonWriter)1719 void ToolBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
1720 {
1721     DockingWindow::DumpAsPropertyTree(rJsonWriter);
1722 
1723     auto childrenNode = rJsonWriter.startArray("children");
1724     for (ToolBox::ImplToolItems::size_type i = 0; i < GetItemCount(); ++i)
1725     {
1726         auto childNode = rJsonWriter.startStruct();
1727         ToolBoxItemId nId = GetItemId(i);
1728 
1729         vcl::Window* pWindow = GetItemWindow(nId);
1730         if (pWindow)
1731         {
1732             pWindow->DumpAsPropertyTree(rJsonWriter);
1733         }
1734         else
1735         {
1736             OUString sCommand = GetItemCommand(nId);
1737             rJsonWriter.put("type", "toolitem");
1738             rJsonWriter.put("text", GetItemText(nId));
1739             rJsonWriter.put("command", sCommand);
1740             if (IsItemChecked(nId))
1741                 rJsonWriter.put("selected", true);
1742             if (!IsItemVisible(nId))
1743                 rJsonWriter.put("visible", false);
1744             if (GetItemBits(nId) & ToolBoxItemBits::DROPDOWN)
1745                 rJsonWriter.put("dropdown", true);
1746             if (!IsItemEnabled(nId))
1747                 rJsonWriter.put("enabled", false);
1748 
1749             Image aImage = GetItemImage(nId);
1750             if (!sCommand.startsWith(".uno:") && !!aImage)
1751             {
1752                 SvMemoryStream aOStm(6535, 6535);
1753                 if(GraphicConverter::Export(aOStm, aImage.GetBitmapEx(), ConvertDataFormat::PNG) == ERRCODE_NONE)
1754                 {
1755                     css::uno::Sequence<sal_Int8> aSeq( static_cast<sal_Int8 const *>(aOStm.GetData()), aOStm.Tell());
1756                     OStringBuffer aBuffer("data:image/png;base64,");
1757                     ::comphelper::Base64::encode(aBuffer, aSeq);
1758                     rJsonWriter.put("image", aBuffer);
1759                 }
1760             }
1761         }
1762     }
1763 }
1764 
1765 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1766