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 .
21 #include <vcl/builder.hxx>
22 #include <vcl/commandevent.hxx>
23 #include <vcl/event.hxx>
24 #include <vcl/field.hxx>
25 #include <vcl/status.hxx>
26 #include <vcl/menu.hxx>
27 #include <vcl/image.hxx>
28 #include <vcl/settings.hxx>
29 #include <vcl/svapp.hxx>
30 #include <svl/stritem.hxx>
31 #include <svl/ptitem.hxx>
32 #include <svl/itempool.hxx>
33 #include <sfx2/app.hxx>
34 #include <sfx2/module.hxx>
35 #include <sfx2/dispatch.hxx>
36 #include <sfx2/objsh.hxx>
37 #include <svl/intitem.hxx>
38 #include <sal/log.hxx>
40 #include <svx/pszctrl.hxx>
42 #define PAINT_OFFSET 5
44 #include <editeng/sizeitem.hxx>
45 #include <svx/dlgutil.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( long nVal
)
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
= MetricField::ConvertValue( nVal
* 100, 0L, 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
);
97 class FunctionPopup_Impl
99 VclBuilder m_aBuilder
;
100 VclPtr
<PopupMenu
> m_xMenu
;
101 sal_uInt32
const m_nSelected
;
102 static sal_uInt16
id_to_function(const OString
& rIdent
);
103 sal_uInt16
function_to_id(sal_uInt16 nFunc
) const;
105 explicit FunctionPopup_Impl( sal_uInt32 nCheckEncoded
);
106 sal_uInt16
Execute(vcl::Window
* pWindow
, const Point
& rPopupPos
) { return m_xMenu
->Execute(pWindow
, rPopupPos
); }
107 sal_uInt32
GetSelected() const;
110 sal_uInt16
FunctionPopup_Impl::id_to_function(const OString
& rIdent
)
114 else if (rIdent
== "counta")
115 return PSZ_FUNC_COUNT2
;
116 else if (rIdent
== "count")
117 return PSZ_FUNC_COUNT
;
118 else if (rIdent
== "max")
120 else if (rIdent
== "min")
122 else if (rIdent
== "sum")
124 else if (rIdent
== "selection")
125 return PSZ_FUNC_SELECTION_COUNT
;
126 else if (rIdent
== "none")
127 return PSZ_FUNC_NONE
;
131 sal_uInt16
FunctionPopup_Impl::function_to_id(sal_uInt16 nFunc
) const
136 return m_xMenu
->GetItemId("avg");
137 case PSZ_FUNC_COUNT2
:
138 return m_xMenu
->GetItemId("counta");
140 return m_xMenu
->GetItemId("count");
142 return m_xMenu
->GetItemId("max");
144 return m_xMenu
->GetItemId("min");
146 return m_xMenu
->GetItemId("sum");
147 case PSZ_FUNC_SELECTION_COUNT
:
148 return m_xMenu
->GetItemId("selection");
150 return m_xMenu
->GetItemId("none");
155 FunctionPopup_Impl::FunctionPopup_Impl(sal_uInt32 nCheckEncoded
)
156 : m_aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "svx/ui/functionmenu.ui", "")
157 , m_xMenu(m_aBuilder
.get_menu("menu"))
158 , m_nSelected(nCheckEncoded
)
160 for ( sal_uInt16 nCheck
= 1; nCheck
< 32; ++nCheck
)
161 if ( nCheckEncoded
& (1 << nCheck
) )
162 m_xMenu
->CheckItem(function_to_id(nCheck
));
165 sal_uInt32
FunctionPopup_Impl::GetSelected() const
167 sal_uInt32 nSelected
= m_nSelected
;
168 sal_uInt16 nCurItemId
= id_to_function(m_xMenu
->GetCurItemIdent());
169 if ( nCurItemId
== PSZ_FUNC_NONE
)
170 nSelected
= ( 1 << PSZ_FUNC_NONE
);
173 nSelected
&= (~( 1 << PSZ_FUNC_NONE
)); // Clear the "None" bit
174 nSelected
^= ( 1 << nCurItemId
); // Toggle the bit corresponding to nCurItemId
176 nSelected
= ( 1 << PSZ_FUNC_NONE
);
181 struct SvxPosSizeStatusBarControl_Impl
185 This implementation-structure of the class SvxPosSizeStatusBarControl
186 is done for the un-linking of the changes of the exported interface such as
187 the toning down of symbols that are visible externally.
189 One instance exists for each SvxPosSizeStatusBarControl-instance
194 Point aPos
; // valid when a position is shown
195 Size aSize
; // valid when a size is shown
196 OUString aStr
; // valid when a text is shown
197 bool bPos
; // show position ?
198 bool bSize
; // set size ?
199 bool bTable
; // set table index ?
200 bool bHasMenu
; // set StarCalc popup menu ?
201 sal_uInt32 nFunctionSet
; // the selected StarCalc functions encoded in 32 bits
202 Image aPosImage
; // Image to show the position
203 Image aSizeImage
; // Image to show the size
209 Create an instance of the implementation class,
210 load the images for the position and size
213 #define STR_POSITION ".uno:Position"
214 #define STR_TABLECELL ".uno:StateTableCell"
215 #define STR_FUNC ".uno:StatusBarFunc"
217 SvxPosSizeStatusBarControl::SvxPosSizeStatusBarControl( sal_uInt16 _nSlotId
,
220 SfxStatusBarControl( _nSlotId
, _nId
, rStb
),
221 pImpl( new SvxPosSizeStatusBarControl_Impl
)
224 pImpl
->bSize
= false;
225 pImpl
->bTable
= false;
226 pImpl
->bHasMenu
= false;
227 pImpl
->nFunctionSet
= 0;
228 pImpl
->aPosImage
= Image(StockImage::Yes
, RID_SVXBMP_POSITION
);
229 pImpl
->aSizeImage
= Image(StockImage::Yes
, RID_SVXBMP_SIZE
);
231 addStatusListener( STR_POSITION
); // SID_ATTR_POSITION
232 addStatusListener( STR_TABLECELL
); // SID_TABLE_CELL
233 addStatusListener( STR_FUNC
); // SID_PSZ_FUNCTION
234 ImplUpdateItemText();
240 remove the pointer to the implementation class, so that the timer is stopped
244 SvxPosSizeStatusBarControl::~SvxPosSizeStatusBarControl()
251 SID_PSZ_FUNCTION activates the popup menu for Calc:
254 Depending on the type of the item, a special setting is enabled, the others disabled.
256 NULL/Void SfxPointItem SvxSizeItem SfxStringItem
257 ------------------------------------------------------------------------
258 Position sal_False FALSE
259 Size FALSE TRUE FALSE
260 Text sal_False sal_False TRUE
264 void SvxPosSizeStatusBarControl::StateChanged( sal_uInt16 nSID
, SfxItemState eState
,
265 const SfxPoolItem
* pState
)
267 // Because the combi-controller, always sets the current Id as HelpId
268 // first clean the cached HelpText
269 GetStatusBar().SetHelpText( GetId(), "" );
273 case SID_ATTR_POSITION
: GetStatusBar().SetHelpId( GetId(), STR_POSITION
); break;
274 case SID_TABLE_CELL
: GetStatusBar().SetHelpId( GetId(), STR_TABLECELL
); break;
275 case SID_PSZ_FUNCTION
: GetStatusBar().SetHelpId( GetId(), STR_FUNC
); break;
279 if ( nSID
== SID_PSZ_FUNCTION
)
281 if ( eState
== SfxItemState::DEFAULT
)
283 pImpl
->bHasMenu
= true;
284 if ( auto pUInt32Item
= dynamic_cast< const SfxUInt32Item
* >(pState
) )
285 pImpl
->nFunctionSet
= pUInt32Item
->GetValue();
288 pImpl
->bHasMenu
= false;
290 else if ( SfxItemState::DEFAULT
!= eState
)
292 // don't switch to empty display before an empty state was
293 // notified for all display types
295 if ( nSID
== SID_TABLE_CELL
)
296 pImpl
->bTable
= false;
297 else if ( nSID
== SID_ATTR_POSITION
)
299 else if ( nSID
== GetSlotId() ) // controller is registered for SID_ATTR_SIZE
300 pImpl
->bSize
= false;
303 SAL_WARN( "svx.stbcrtls","unknown slot id");
306 else if ( auto pPointItem
= dynamic_cast<const SfxPointItem
*>( pState
) )
309 pImpl
->aPos
= pPointItem
->GetValue();
311 pImpl
->bTable
= false;
313 else if ( auto pSizeItem
= dynamic_cast<const SvxSizeItem
*>( pState
) )
316 pImpl
->aSize
= pSizeItem
->GetSize();
318 pImpl
->bTable
= false;
320 else if ( auto pStringItem
= dynamic_cast<const SfxStringItem
*>( pState
) )
322 // show string (table cel or different)
323 pImpl
->aStr
= pStringItem
->GetValue();
324 pImpl
->bTable
= true;
326 pImpl
->bSize
= false;
330 SAL_WARN( "svx.stbcrtls", "invalid item type" );
332 pImpl
->bSize
= false;
333 pImpl
->bTable
= false;
336 GetStatusBar().SetItemData( GetId(), nullptr );
338 ImplUpdateItemText();
344 execute popup menu, when the status enables this
347 void SvxPosSizeStatusBarControl::Command( const CommandEvent
& rCEvt
)
349 if ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
&& pImpl
->bHasMenu
)
351 sal_uInt32 nSelect
= pImpl
->nFunctionSet
;
353 nSelect
= ( 1 << PSZ_FUNC_NONE
);
354 FunctionPopup_Impl
aMenu(nSelect
);
355 if (aMenu
.Execute(&GetStatusBar(), rCEvt
.GetMousePosPixel()))
357 nSelect
= aMenu
.GetSelected();
360 if (nSelect
== (1 << PSZ_FUNC_NONE
))
364 SfxUInt32Item
aItem( SID_PSZ_FUNCTION
, nSelect
);
366 css::uno::Sequence
< css::beans::PropertyValue
> aArgs( 1 );
367 aArgs
[0].Name
= "StatusBarFunc";
368 aItem
.QueryValue( a
);
371 execute( ".uno:StatusBarFunc", aArgs
);
376 SfxStatusBarControl::Command( rCEvt
);
382 Depending on the type to be shown, the value us shown. First the
383 rectangle is repainted (removed).
386 void SvxPosSizeStatusBarControl::Paint( const UserDrawEvent
& rUsrEvt
)
388 vcl::RenderContext
* pDev
= rUsrEvt
.GetRenderContext();
390 const tools::Rectangle
& rRect
= rUsrEvt
.GetRect();
391 StatusBar
& rBar
= GetStatusBar();
392 Point aItemPos
= rBar
.GetItemTextPos( GetId() );
393 Color aOldLineColor
= pDev
->GetLineColor();
394 Color aOldFillColor
= pDev
->GetFillColor();
395 pDev
->SetLineColor();
396 pDev
->SetFillColor( pDev
->GetBackground().GetColor() );
398 if ( pImpl
->bPos
|| pImpl
->bSize
)
400 // count the position for showing the size
402 rRect
.Left() + rRect
.GetWidth() / 2 + PAINT_OFFSET
;
404 Point aPnt
= rRect
.TopLeft();
405 aPnt
.setY( aItemPos
.Y() );
406 aPnt
.AdjustX(PAINT_OFFSET
);
407 pDev
->DrawImage( aPnt
, pImpl
->aPosImage
);
408 aPnt
.AdjustX(pImpl
->aPosImage
.GetSizePixel().Width() );
409 aPnt
.AdjustX(PAINT_OFFSET
);
410 OUString aStr
= GetMetricStr_Impl( pImpl
->aPos
.X()) + " / " +
411 GetMetricStr_Impl( pImpl
->aPos
.Y());
412 tools::Rectangle
aRect(aPnt
, Point(nSizePosX
, rRect
.Bottom()));
413 pDev
->DrawRect(aRect
);
414 vcl::Region
aOrigRegion(pDev
->GetClipRegion());
415 pDev
->SetClipRegion(vcl::Region(aRect
));
416 pDev
->DrawText(aPnt
, aStr
);
417 pDev
->SetClipRegion(aOrigRegion
);
419 // draw the size, when available
420 aPnt
.setX( nSizePosX
);
424 pDev
->DrawImage( aPnt
, pImpl
->aSizeImage
);
425 aPnt
.AdjustX(pImpl
->aSizeImage
.GetSizePixel().Width() );
426 Point aDrwPnt
= aPnt
;
427 aPnt
.AdjustX(PAINT_OFFSET
);
428 aStr
= GetMetricStr_Impl( pImpl
->aSize
.Width() ) + " x " +
429 GetMetricStr_Impl( pImpl
->aSize
.Height() );
430 aRect
= tools::Rectangle(aDrwPnt
, rRect
.BottomRight());
431 pDev
->DrawRect(aRect
);
432 aOrigRegion
= pDev
->GetClipRegion();
433 pDev
->SetClipRegion(vcl::Region(aRect
));
434 pDev
->DrawText(aPnt
, aStr
);
435 pDev
->SetClipRegion(aOrigRegion
);
438 pDev
->DrawRect( tools::Rectangle( aPnt
, rRect
.BottomRight() ) );
440 else if ( pImpl
->bTable
)
442 pDev
->DrawRect( rRect
);
443 pDev
->DrawText( Point(
444 rRect
.Left() + rRect
.GetWidth() / 2 - pDev
->GetTextWidth( pImpl
->aStr
) / 2,
445 aItemPos
.Y() ), pImpl
->aStr
);
449 // Empty display if neither size nor table position are available.
450 // Date/Time are no longer used (#65302#).
451 pDev
->DrawRect( rRect
);
454 pDev
->SetLineColor( aOldLineColor
);
455 pDev
->SetFillColor( aOldFillColor
);
458 void SvxPosSizeStatusBarControl::ImplUpdateItemText()
460 // set only strings as text at the statusBar, so that the Help-Tips
461 // can work with the text, when it is too long for the statusBar
463 int nCharsWidth
= -1;
464 if ( pImpl
->bPos
|| pImpl
->bSize
)
466 aText
= GetMetricStr_Impl( pImpl
->aPos
.X()) + " / " +
467 GetMetricStr_Impl( pImpl
->aPos
.Y());
468 // widest X/Y string looks like "-999,99"
469 nCharsWidth
= 1 + 6 + 3 + 6; // icon + x + slash + y
472 aText
+= " " + GetMetricStr_Impl( pImpl
->aSize
.Width() ) + " x " +
473 GetMetricStr_Impl( pImpl
->aSize
.Height() );
474 nCharsWidth
+= 1 + 1 + 4 + 3 + 4; // icon + space + w + x + h
477 else if ( pImpl
->bTable
)
480 GetStatusBar().SetItemText( GetId(), aText
, nCharsWidth
);
482 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */