1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <comphelper/propertyvalue.hxx>
23 #include <vcl/commandevent.hxx>
24 #include <vcl/event.hxx>
25 #include <vcl/fieldvalues.hxx>
26 #include <vcl/status.hxx>
27 #include <vcl/image.hxx>
28 #include <vcl/settings.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/weld.hxx>
31 #include <vcl/weldutils.hxx>
32 #include <svl/stritem.hxx>
33 #include <svl/ptitem.hxx>
34 #include <sfx2/module.hxx>
35 #include <svx/dialmgr.hxx>
36 #include <svx/statusitem.hxx>
37 #include <svx/strings.hrc>
38 #include <svl/intitem.hxx>
39 #include <sal/log.hxx>
41 #include <svx/pszctrl.hxx>
43 #define PAINT_OFFSET 5
45 #include <editeng/sizeitem.hxx>
48 #include <svx/svxids.hrc>
49 #include <bitmaps.hlst>
50 #include <unotools/localedatawrapper.hxx>
52 #include <com/sun/star/beans/PropertyValue.hpp>
56 Function used to create a text representation of
59 nVal is the metric value in the unit eUnit.
63 <SvxPosSizeStatusBarControl::Paint(const UserDrawEvent&)>
66 OUString
SvxPosSizeStatusBarControl::GetMetricStr_Impl( tools::Long nVal
) const
68 // deliver and set the Metric of the application
69 FieldUnit eOutUnit
= SfxModule::GetModuleFieldUnit( getFrameInterface() );
72 const sal_Unicode cSep
= Application::GetSettings().GetLocaleDataWrapper().getNumDecimalSep()[0];
73 sal_Int64 nConvVal
= vcl::ConvertValue( nVal
* 100, 0, 0, FieldUnit::MM_100TH
, eOutUnit
);
75 if ( nConvVal
< 0 && ( nConvVal
/ 100 == 0 ) )
77 sMetric
+= OUString::number(nConvVal
/ 100);
79 if( FieldUnit::NONE
!= eOutUnit
)
81 sMetric
+= OUStringChar(cSep
);
82 sal_Int64 nFract
= nConvVal
% 100;
88 sMetric
+= OUString::number(nFract
);
95 SFX_IMPL_STATUSBAR_CONTROL(SvxPosSizeStatusBarControl
, SvxSizeItem
);
99 class FunctionPopup_Impl
101 std::unique_ptr
<weld::Builder
> m_xBuilder
;
102 std::unique_ptr
<weld::Menu
> m_xMenu
;
103 sal_uInt32 m_nSelected
;
104 static sal_uInt16
id_to_function(std::u16string_view rIdent
);
105 static OUString
function_to_id(sal_uInt16 nFunc
);
107 explicit FunctionPopup_Impl(sal_uInt32 nCheckEncoded
);
108 OUString
Execute(weld::Window
* pParent
, const tools::Rectangle
& rRect
)
110 return m_xMenu
->popup_at_rect(pParent
, rRect
);
112 sal_uInt32
GetSelected(std::u16string_view curident
) const;
117 sal_uInt16
FunctionPopup_Impl::id_to_function(std::u16string_view rIdent
)
119 if (rIdent
== u
"avg")
121 else if (rIdent
== u
"counta")
122 return PSZ_FUNC_COUNT2
;
123 else if (rIdent
== u
"count")
124 return PSZ_FUNC_COUNT
;
125 else if (rIdent
== u
"max")
127 else if (rIdent
== u
"min")
129 else if (rIdent
== u
"sum")
131 else if (rIdent
== u
"selection")
132 return PSZ_FUNC_SELECTION_COUNT
;
133 else if (rIdent
== u
"none")
134 return PSZ_FUNC_NONE
;
138 OUString
FunctionPopup_Impl::function_to_id(sal_uInt16 nFunc
)
144 case PSZ_FUNC_COUNT2
:
145 return u
"counta"_ustr
;
147 return u
"count"_ustr
;
154 case PSZ_FUNC_SELECTION_COUNT
:
155 return u
"selection"_ustr
;
162 FunctionPopup_Impl::FunctionPopup_Impl(sal_uInt32 nCheckEncoded
)
163 : m_xBuilder(Application::CreateBuilder(nullptr, u
"svx/ui/functionmenu.ui"_ustr
))
164 , m_xMenu(m_xBuilder
->weld_menu(u
"menu"_ustr
))
165 , m_nSelected(nCheckEncoded
)
167 for ( sal_uInt16 nCheck
= 1; nCheck
< 32; ++nCheck
)
168 if ( nCheckEncoded
& (1u << nCheck
) )
169 m_xMenu
->set_active(function_to_id(nCheck
), true);
172 sal_uInt32
FunctionPopup_Impl::GetSelected(std::u16string_view curident
) const
174 sal_uInt32 nSelected
= m_nSelected
;
175 sal_uInt16 nCurItemId
= id_to_function(curident
);
176 if ( nCurItemId
== PSZ_FUNC_NONE
)
177 nSelected
= ( 1 << PSZ_FUNC_NONE
);
180 nSelected
&= (~( 1u << PSZ_FUNC_NONE
)); // Clear the "None" bit
181 nSelected
^= ( 1u << nCurItemId
); // Toggle the bit corresponding to nCurItemId
183 nSelected
= ( 1u << PSZ_FUNC_NONE
);
188 struct SvxPosSizeStatusBarControl_Impl
192 This implementation-structure of the class SvxPosSizeStatusBarControl
193 is done for the un-linking of the changes of the exported interface such as
194 the toning down of symbols that are visible externally.
196 One instance exists for each SvxPosSizeStatusBarControl-instance
201 Point aPos
; // valid when a position is shown
202 Size aSize
; // valid when a size is shown
203 OUString aStr
; // valid when a text is shown
204 bool bPos
; // show position ?
205 bool bSize
; // set size ?
206 bool bTable
; // set table index ?
207 bool bHasMenu
; // set StarCalc popup menu ?
208 sal_uInt32 nFunctionSet
; // the selected StarCalc functions encoded in 32 bits
209 Image aPosImage
; // Image to show the position
210 Image aSizeImage
; // Image to show the size
216 Create an instance of the implementation class,
217 load the images for the position and size
220 #define STR_POSITION ".uno:Position"
221 #define STR_TABLECELL ".uno:StateTableCell"
222 #define STR_FUNC ".uno:StatusBarFunc"
224 SvxPosSizeStatusBarControl::SvxPosSizeStatusBarControl( sal_uInt16 _nSlotId
,
227 SfxStatusBarControl( _nSlotId
, _nId
, rStb
),
228 pImpl( new SvxPosSizeStatusBarControl_Impl
)
231 pImpl
->bSize
= false;
232 pImpl
->bTable
= false;
233 pImpl
->bHasMenu
= false;
234 pImpl
->nFunctionSet
= 0;
235 pImpl
->aPosImage
= Image(StockImage::Yes
, RID_SVXBMP_POSITION
);
236 pImpl
->aSizeImage
= Image(StockImage::Yes
, RID_SVXBMP_SIZE
);
238 addStatusListener( u
"" STR_POSITION
""_ustr
); // SID_ATTR_POSITION
239 addStatusListener( u
"" STR_TABLECELL
""_ustr
); // SID_TABLE_CELL
240 addStatusListener( u
"" STR_FUNC
""_ustr
); // SID_PSZ_FUNCTION
241 ImplUpdateItemText();
247 remove the pointer to the implementation class, so that the timer is stopped
251 SvxPosSizeStatusBarControl::~SvxPosSizeStatusBarControl()
258 SID_PSZ_FUNCTION activates the popup menu for Calc:
261 Depending on the type of the item, a special setting is enabled, the others disabled.
263 NULL/Void SfxPointItem SvxSizeItem SfxStringItem
264 ------------------------------------------------------------------------
265 Position sal_False FALSE
266 Size FALSE TRUE FALSE
267 Text sal_False sal_False TRUE
271 void SvxPosSizeStatusBarControl::StateChangedAtStatusBarControl( sal_uInt16 nSID
, SfxItemState eState
,
272 const SfxPoolItem
* pState
)
274 // Because the combi-controller, always sets the current Id as HelpId
275 // first clean the cached HelpText
276 GetStatusBar().SetHelpText( GetId(), u
""_ustr
);
280 case SID_ATTR_POSITION
: GetStatusBar().SetHelpId( GetId(), u
"" STR_POSITION
""_ustr
); break;
281 case SID_TABLE_CELL
: GetStatusBar().SetHelpId( GetId(), u
"" STR_TABLECELL
""_ustr
); break;
282 case SID_PSZ_FUNCTION
: GetStatusBar().SetHelpId( GetId(), u
"" STR_FUNC
""_ustr
); break;
286 if ( nSID
== SID_PSZ_FUNCTION
)
288 if ( eState
== SfxItemState::DEFAULT
)
290 pImpl
->bHasMenu
= true;
291 if ( auto pUInt32Item
= dynamic_cast< const SfxUInt32Item
* >(pState
) )
292 pImpl
->nFunctionSet
= pUInt32Item
->GetValue();
295 pImpl
->bHasMenu
= false;
297 else if ( SfxItemState::DEFAULT
!= eState
)
299 // don't switch to empty display before an empty state was
300 // notified for all display types
302 if ( nSID
== SID_TABLE_CELL
)
303 pImpl
->bTable
= false;
304 else if ( nSID
== SID_ATTR_POSITION
)
306 else if ( nSID
== GetSlotId() ) // controller is registered for SID_ATTR_SIZE
307 pImpl
->bSize
= false;
310 SAL_WARN( "svx.stbcrtls","unknown slot id");
313 else if ( auto pPointItem
= dynamic_cast<const SfxPointItem
*>( pState
) )
316 pImpl
->aPos
= pPointItem
->GetValue();
318 pImpl
->bTable
= false;
320 else if ( auto pSizeItem
= dynamic_cast<const SvxSizeItem
*>( pState
) )
323 pImpl
->aSize
= pSizeItem
->GetSize();
325 pImpl
->bTable
= false;
327 else if ( auto pStatusItem
= dynamic_cast<const SvxStatusItem
*>( pState
) )
329 // show string (table cell or different)
330 pImpl
->aStr
= pStatusItem
->GetValue();
331 pImpl
->bTable
= true;
333 pImpl
->bSize
= false;
334 if (!pImpl
->aStr
.isEmpty())
337 switch (pStatusItem
->GetCategory())
339 case StatusCategory::TableCell
:
340 sTip
= SvxResId(RID_SVXSTR_TABLECELL_HINT
);
342 case StatusCategory::Section
:
343 sTip
= SvxResId(RID_SVXSTR_SECTION_HINT
);
345 case StatusCategory::TableOfContents
:
346 sTip
= SvxResId(RID_SVXSTR_TOC_HINT
);
348 case StatusCategory::Numbering
:
349 sTip
= SvxResId(RID_SVXSTR_NUMBERING_HINT
);
351 case StatusCategory::ListStyle
:
352 sTip
= SvxResId(RID_SVXSTR_LIST_STYLE_HINT
);
354 case StatusCategory::Formula
:
355 sTip
= SvxResId(RID_SVXSTR_FORMULA_HINT
);
357 case StatusCategory::RowColumn
:
358 sTip
= SvxResId(RID_SVXSTR_ROW_COLUMN_HINT
);
360 case StatusCategory::NONE
:
363 GetStatusBar().SetQuickHelpText(GetId(), sTip
);
366 else if ( auto pStringItem
= dynamic_cast<const SfxStringItem
*>( pState
) )
368 SAL_WARN( "svx.stbcrtls", "this should be a SvxStatusItem not a SfxStringItem" );
369 // show string (table cell or different)
370 pImpl
->aStr
= pStringItem
->GetValue();
371 pImpl
->bTable
= true;
373 pImpl
->bSize
= false;
377 SAL_WARN( "svx.stbcrtls", "invalid item type" );
379 pImpl
->bSize
= false;
380 pImpl
->bTable
= false;
383 GetStatusBar().SetItemData( GetId(), nullptr );
385 ImplUpdateItemText();
391 execute popup menu, when the status enables this
394 void SvxPosSizeStatusBarControl::Command( const CommandEvent
& rCEvt
)
396 if ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
&& pImpl
->bHasMenu
)
398 sal_uInt32 nSelect
= pImpl
->nFunctionSet
;
400 nSelect
= ( 1 << PSZ_FUNC_NONE
);
401 tools::Rectangle
aRect(rCEvt
.GetMousePosPixel(), Size(1,1));
402 weld::Window
* pParent
= weld::GetPopupParent(GetStatusBar(), aRect
);
403 FunctionPopup_Impl
aMenu(nSelect
);
404 OUString sIdent
= aMenu
.Execute(pParent
, aRect
);
405 if (!sIdent
.isEmpty())
407 nSelect
= aMenu
.GetSelected(sIdent
);
410 if (nSelect
== (1 << PSZ_FUNC_NONE
))
414 SfxUInt32Item
aItem( SID_PSZ_FUNCTION
, nSelect
);
415 aItem
.QueryValue( a
);
416 css::uno::Sequence
< css::beans::PropertyValue
> aArgs
{ comphelper::makePropertyValue(
417 u
"StatusBarFunc"_ustr
, a
) };
418 execute( u
".uno:StatusBarFunc"_ustr
, aArgs
);
423 SfxStatusBarControl::Command( rCEvt
);
429 Depending on the type to be shown, the value us shown. First the
430 rectangle is repainted (removed).
433 void SvxPosSizeStatusBarControl::Paint( const UserDrawEvent
& rUsrEvt
)
435 vcl::RenderContext
* pDev
= rUsrEvt
.GetRenderContext();
437 const tools::Rectangle
& rRect
= rUsrEvt
.GetRect();
438 StatusBar
& rBar
= GetStatusBar();
439 Point aItemPos
= rBar
.GetItemTextPos( GetId() );
440 Color aOldLineColor
= pDev
->GetLineColor();
441 Color aOldFillColor
= pDev
->GetFillColor();
442 pDev
->SetLineColor();
443 pDev
->SetFillColor( pDev
->GetBackground().GetColor() );
445 if ( pImpl
->bPos
|| pImpl
->bSize
)
447 // count the position for showing the size
448 tools::Long nSizePosX
=
449 rRect
.Left() + rRect
.GetWidth() / 2 + PAINT_OFFSET
;
451 Point aPnt
= rRect
.TopLeft();
452 aPnt
.AdjustX(PAINT_OFFSET
);
453 // vertically centered
454 const tools::Long nSizePosY
=
455 (rRect
.GetHeight() - pImpl
->aPosImage
.GetSizePixel().Height()) / 2;
456 aPnt
.AdjustY( nSizePosY
);
458 pDev
->DrawImage( aPnt
, pImpl
->aPosImage
);
459 aPnt
.AdjustX(pImpl
->aPosImage
.GetSizePixel().Width() );
460 aPnt
.AdjustX(PAINT_OFFSET
);
461 OUString aStr
= GetMetricStr_Impl( pImpl
->aPos
.X()) + " / " +
462 GetMetricStr_Impl( pImpl
->aPos
.Y());
463 tools::Rectangle
aRect(aPnt
, Point(nSizePosX
, rRect
.Bottom()));
464 pDev
->DrawRect(aRect
);
465 vcl::Region
aOrigRegion(pDev
->GetClipRegion());
466 pDev
->SetClipRegion(vcl::Region(aRect
));
467 pDev
->DrawText(aPnt
, aStr
);
468 pDev
->SetClipRegion(aOrigRegion
);
470 // draw the size, when available
471 aPnt
.setX( nSizePosX
);
475 pDev
->DrawImage( aPnt
, pImpl
->aSizeImage
);
476 aPnt
.AdjustX(pImpl
->aSizeImage
.GetSizePixel().Width() );
477 Point aDrwPnt
= aPnt
;
478 aPnt
.AdjustX(PAINT_OFFSET
);
479 aStr
= GetMetricStr_Impl( pImpl
->aSize
.Width() ) + " x " +
480 GetMetricStr_Impl( pImpl
->aSize
.Height() );
481 aRect
= tools::Rectangle(aDrwPnt
, rRect
.BottomRight());
482 pDev
->DrawRect(aRect
);
483 aOrigRegion
= pDev
->GetClipRegion();
484 pDev
->SetClipRegion(vcl::Region(aRect
));
485 pDev
->DrawText(aPnt
, aStr
);
486 pDev
->SetClipRegion(aOrigRegion
);
489 pDev
->DrawRect( tools::Rectangle( aPnt
, rRect
.BottomRight() ) );
491 else if ( pImpl
->bTable
)
493 pDev
->DrawRect( rRect
);
494 pDev
->DrawText( Point(
495 rRect
.Left() + rRect
.GetWidth() / 2 - pDev
->GetTextWidth( pImpl
->aStr
) / 2,
496 aItemPos
.Y() ), pImpl
->aStr
);
500 // Empty display if neither size nor table position are available.
501 // Date/Time are no longer used (#65302#).
502 pDev
->DrawRect( rRect
);
505 pDev
->SetLineColor( aOldLineColor
);
506 pDev
->SetFillColor( aOldFillColor
);
509 void SvxPosSizeStatusBarControl::ImplUpdateItemText()
511 // set only strings as text at the statusBar, so that the Help-Tips
512 // can work with the text, when it is too long for the statusBar
514 int nCharsWidth
= -1;
515 if ( pImpl
->bPos
|| pImpl
->bSize
)
517 aText
= GetMetricStr_Impl( pImpl
->aPos
.X()) + " / " +
518 GetMetricStr_Impl( pImpl
->aPos
.Y());
519 // widest X/Y string looks like "-999,99"
520 nCharsWidth
= 1 + 6 + 3 + 6; // icon + x + slash + y
523 aText
+= " " + GetMetricStr_Impl( pImpl
->aSize
.Width() ) + " x " +
524 GetMetricStr_Impl( pImpl
->aSize
.Height() );
525 nCharsWidth
+= 1 + 1 + 4 + 3 + 4; // icon + space + w + x + h
528 else if ( pImpl
->bTable
)
531 GetStatusBar().SetItemText( GetId(), aText
, nCharsWidth
);
533 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */