LibreOffice Module svx (master)  1
pszctrl.cxx
Go to the documentation of this file.
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 
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 <svl/intitem.hxx>
36 #include <sal/log.hxx>
37 
38 #include <svx/pszctrl.hxx>
39 
40 #define PAINT_OFFSET 5
41 
42 #include <editeng/sizeitem.hxx>
43 #include "stbctrls.h"
44 
45 #include <svx/svxids.hrc>
46 #include <bitmaps.hlst>
48 
49 #include <com/sun/star/beans/PropertyValue.hpp>
50 
51 /* [Description]
52 
53  Function used to create a text representation of
54  a metric value
55 
56  nVal is the metric value in the unit eUnit.
57 
58  [cross reference]
59 
60  <SvxPosSizeStatusBarControl::Paint(const UserDrawEvent&)>
61 */
62 
64 {
65  // deliver and set the Metric of the application
66  FieldUnit eOutUnit = SfxModule::GetModuleFieldUnit( getFrameInterface() );
67 
68  OUString sMetric;
70  sal_Int64 nConvVal = vcl::ConvertValue( nVal * 100, 0, 0, FieldUnit::MM_100TH, eOutUnit );
71 
72  if ( nConvVal < 0 && ( nConvVal / 100 == 0 ) )
73  sMetric += "-";
74  sMetric += OUString::number(nConvVal / 100);
75 
76  if( FieldUnit::NONE != eOutUnit )
77  {
78  sMetric += OUStringChar(cSep);
79  sal_Int64 nFract = nConvVal % 100;
80 
81  if ( nFract < 0 )
82  nFract *= -1;
83  if ( nFract < 10 )
84  sMetric += "0";
85  sMetric += OUString::number(nFract);
86  }
87 
88  return sMetric;
89 }
90 
91 
93 
94 namespace {
95 
96 class FunctionPopup_Impl
97 {
98  std::unique_ptr<weld::Builder> m_xBuilder;
99  std::unique_ptr<weld::Menu> m_xMenu;
100  sal_uInt32 m_nSelected;
101  static sal_uInt16 id_to_function(std::string_view rIdent);
102  static OString function_to_id(sal_uInt16 nFunc);
103 public:
104  explicit FunctionPopup_Impl(sal_uInt32 nCheckEncoded);
105  OString Execute(weld::Window* pParent, const tools::Rectangle& rRect)
106  {
107  return m_xMenu->popup_at_rect(pParent, rRect);
108  }
109  sal_uInt32 GetSelected(std::string_view curident) const;
110 };
111 
112 }
113 
114 sal_uInt16 FunctionPopup_Impl::id_to_function(std::string_view rIdent)
115 {
116  if (rIdent == "avg")
117  return PSZ_FUNC_AVG;
118  else if (rIdent == "counta")
119  return PSZ_FUNC_COUNT2;
120  else if (rIdent == "count")
121  return PSZ_FUNC_COUNT;
122  else if (rIdent == "max")
123  return PSZ_FUNC_MAX;
124  else if (rIdent == "min")
125  return PSZ_FUNC_MIN;
126  else if (rIdent == "sum")
127  return PSZ_FUNC_SUM;
128  else if (rIdent == "selection")
130  else if (rIdent == "none")
131  return PSZ_FUNC_NONE;
132  return 0;
133 }
134 
135 OString FunctionPopup_Impl::function_to_id(sal_uInt16 nFunc)
136 {
137  switch (nFunc)
138  {
139  case PSZ_FUNC_AVG:
140  return "avg";
141  case PSZ_FUNC_COUNT2:
142  return "counta";
143  case PSZ_FUNC_COUNT:
144  return "count";
145  case PSZ_FUNC_MAX:
146  return "max";
147  case PSZ_FUNC_MIN:
148  return "min";
149  case PSZ_FUNC_SUM:
150  return "sum";
152  return "selection";
153  case PSZ_FUNC_NONE:
154  return "none";
155  }
156  return OString();
157 }
158 
159 FunctionPopup_Impl::FunctionPopup_Impl(sal_uInt32 nCheckEncoded)
160  : m_xBuilder(Application::CreateBuilder(nullptr, "svx/ui/functionmenu.ui"))
161  , m_xMenu(m_xBuilder->weld_menu("menu"))
162  , m_nSelected(nCheckEncoded)
163 {
164  for ( sal_uInt16 nCheck = 1; nCheck < 32; ++nCheck )
165  if ( nCheckEncoded & (1u << nCheck) )
166  m_xMenu->set_active(function_to_id(nCheck), true);
167 }
168 
169 sal_uInt32 FunctionPopup_Impl::GetSelected(std::string_view curident) const
170 {
171  sal_uInt32 nSelected = m_nSelected;
172  sal_uInt16 nCurItemId = id_to_function(curident);
173  if ( nCurItemId == PSZ_FUNC_NONE )
174  nSelected = ( 1 << PSZ_FUNC_NONE );
175  else
176  {
177  nSelected &= (~( 1u << PSZ_FUNC_NONE )); // Clear the "None" bit
178  nSelected ^= ( 1u << nCurItemId ); // Toggle the bit corresponding to nCurItemId
179  if ( !nSelected )
180  nSelected = ( 1u << PSZ_FUNC_NONE );
181  }
182  return nSelected;
183 }
184 
186 
187 /* [Description]
188 
189  This implementation-structure of the class SvxPosSizeStatusBarControl
190  is done for the un-linking of the changes of the exported interface such as
191  the toning down of symbols that are visible externally.
192 
193  One instance exists for each SvxPosSizeStatusBarControl-instance
194  during its life time
195 */
196 
197 {
198  Point aPos; // valid when a position is shown
199  Size aSize; // valid when a size is shown
200  OUString aStr; // valid when a text is shown
201  bool bPos; // show position ?
202  bool bSize; // set size ?
203  bool bTable; // set table index ?
204  bool bHasMenu; // set StarCalc popup menu ?
205  sal_uInt32 nFunctionSet; // the selected StarCalc functions encoded in 32 bits
206  Image aPosImage; // Image to show the position
207  Image aSizeImage; // Image to show the size
208 };
209 
210 /* [Description]
211 
212  Ctor():
213  Create an instance of the implementation class,
214  load the images for the position and size
215 */
216 
217 #define STR_POSITION ".uno:Position"
218 #define STR_TABLECELL ".uno:StateTableCell"
219 #define STR_FUNC ".uno:StatusBarFunc"
220 
222  sal_uInt16 _nId,
223  StatusBar& rStb ) :
224  SfxStatusBarControl( _nSlotId, _nId, rStb ),
226 {
227  pImpl->bPos = false;
228  pImpl->bSize = false;
229  pImpl->bTable = false;
230  pImpl->bHasMenu = false;
231  pImpl->nFunctionSet = 0;
232  pImpl->aPosImage = Image(StockImage::Yes, RID_SVXBMP_POSITION);
233  pImpl->aSizeImage = Image(StockImage::Yes, RID_SVXBMP_SIZE);
234 
235  addStatusListener( STR_POSITION); // SID_ATTR_POSITION
236  addStatusListener( STR_TABLECELL); // SID_TABLE_CELL
237  addStatusListener( STR_FUNC); // SID_PSZ_FUNCTION
239 }
240 
241 /* [Description]
242 
243  Dtor():
244  remove the pointer to the implementation class, so that the timer is stopped
245 
246 */
247 
249 {
250 }
251 
252 
253 /* [Description]
254 
255  SID_PSZ_FUNCTION activates the popup menu for Calc:
256 
257  Status overview
258  Depending on the type of the item, a special setting is enabled, the others disabled.
259 
260  NULL/Void SfxPointItem SvxSizeItem SfxStringItem
261  ------------------------------------------------------------------------
262  Position sal_False FALSE
263  Size FALSE TRUE FALSE
264  Text sal_False sal_False TRUE
265 
266 */
267 
269  const SfxPoolItem* pState )
270 {
271  // Because the combi-controller, always sets the current Id as HelpId
272  // first clean the cached HelpText
273  GetStatusBar().SetHelpText( GetId(), "" );
274 
275  switch ( nSID )
276  {
277  case SID_ATTR_POSITION : GetStatusBar().SetHelpId( GetId(), STR_POSITION ); break;
278  case SID_TABLE_CELL: GetStatusBar().SetHelpId( GetId(), STR_TABLECELL ); break;
279  case SID_PSZ_FUNCTION: GetStatusBar().SetHelpId( GetId(), STR_FUNC ); break;
280  default: break;
281  }
282 
283  if ( nSID == SID_PSZ_FUNCTION )
284  {
285  if ( eState == SfxItemState::DEFAULT )
286  {
287  pImpl->bHasMenu = true;
288  if ( auto pUInt32Item = dynamic_cast< const SfxUInt32Item* >(pState) )
289  pImpl->nFunctionSet = pUInt32Item->GetValue();
290  }
291  else
292  pImpl->bHasMenu = false;
293  }
294  else if ( SfxItemState::DEFAULT != eState )
295  {
296  // don't switch to empty display before an empty state was
297  // notified for all display types
298 
299  if ( nSID == SID_TABLE_CELL )
300  pImpl->bTable = false;
301  else if ( nSID == SID_ATTR_POSITION )
302  pImpl->bPos = false;
303  else if ( nSID == GetSlotId() ) // controller is registered for SID_ATTR_SIZE
304  pImpl->bSize = false;
305  else
306  {
307  SAL_WARN( "svx.stbcrtls","unknown slot id");
308  }
309  }
310  else if ( auto pPointItem = dynamic_cast<const SfxPointItem*>( pState) )
311  {
312  // show position
313  pImpl->aPos = pPointItem->GetValue();
314  pImpl->bPos = true;
315  pImpl->bTable = false;
316  }
317  else if ( auto pSizeItem = dynamic_cast<const SvxSizeItem*>( pState) )
318  {
319  // show size
320  pImpl->aSize = pSizeItem->GetSize();
321  pImpl->bSize = true;
322  pImpl->bTable = false;
323  }
324  else if ( auto pStringItem = dynamic_cast<const SfxStringItem*>( pState) )
325  {
326  // show string (table cel or different)
327  pImpl->aStr = pStringItem->GetValue();
328  pImpl->bTable = true;
329  pImpl->bPos = false;
330  pImpl->bSize = false;
331  }
332  else
333  {
334  SAL_WARN( "svx.stbcrtls", "invalid item type" );
335  pImpl->bPos = false;
336  pImpl->bSize = false;
337  pImpl->bTable = false;
338  }
339 
340  GetStatusBar().SetItemData( GetId(), nullptr );
341 
343 }
344 
345 
346 /* [Description]
347 
348  execute popup menu, when the status enables this
349 */
350 
352 {
353  if ( rCEvt.GetCommand() == CommandEventId::ContextMenu && pImpl->bHasMenu )
354  {
355  sal_uInt32 nSelect = pImpl->nFunctionSet;
356  if (!nSelect)
357  nSelect = ( 1 << PSZ_FUNC_NONE );
358  tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1,1));
359  weld::Window* pParent = weld::GetPopupParent(GetStatusBar(), aRect);
360  FunctionPopup_Impl aMenu(nSelect);
361  OString sIdent = aMenu.Execute(pParent, aRect);
362  if (!sIdent.isEmpty())
363  {
364  nSelect = aMenu.GetSelected(sIdent);
365  if (nSelect)
366  {
367  if (nSelect == (1 << PSZ_FUNC_NONE))
368  nSelect = 0;
369 
370  css::uno::Any a;
371  SfxUInt32Item aItem( SID_PSZ_FUNCTION, nSelect );
372  aItem.QueryValue( a );
373  css::uno::Sequence< css::beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
374  "StatusBarFunc", a) };
375  execute( ".uno:StatusBarFunc", aArgs );
376  }
377  }
378  }
379  else
381 }
382 
383 
384 /* [Description]
385 
386  Depending on the type to be shown, the value us shown. First the
387  rectangle is repainted (removed).
388 */
389 
391 {
392  vcl::RenderContext* pDev = rUsrEvt.GetRenderContext();
393 
394  const tools::Rectangle& rRect = rUsrEvt.GetRect();
395  StatusBar& rBar = GetStatusBar();
396  Point aItemPos = rBar.GetItemTextPos( GetId() );
397  Color aOldLineColor = pDev->GetLineColor();
398  Color aOldFillColor = pDev->GetFillColor();
399  pDev->SetLineColor();
400  pDev->SetFillColor( pDev->GetBackground().GetColor() );
401 
402  if ( pImpl->bPos || pImpl->bSize )
403  {
404  // count the position for showing the size
405  tools::Long nSizePosX =
406  rRect.Left() + rRect.GetWidth() / 2 + PAINT_OFFSET;
407  // draw position
408  Point aPnt = rRect.TopLeft();
409  aPnt.setY( aItemPos.Y() );
410  aPnt.AdjustX(PAINT_OFFSET );
411  pDev->DrawImage( aPnt, pImpl->aPosImage );
412  aPnt.AdjustX(pImpl->aPosImage.GetSizePixel().Width() );
413  aPnt.AdjustX(PAINT_OFFSET );
414  OUString aStr = GetMetricStr_Impl( pImpl->aPos.X()) + " / " +
415  GetMetricStr_Impl( pImpl->aPos.Y());
416  tools::Rectangle aRect(aPnt, Point(nSizePosX, rRect.Bottom()));
417  pDev->DrawRect(aRect);
418  vcl::Region aOrigRegion(pDev->GetClipRegion());
419  pDev->SetClipRegion(vcl::Region(aRect));
420  pDev->DrawText(aPnt, aStr);
421  pDev->SetClipRegion(aOrigRegion);
422 
423  // draw the size, when available
424  aPnt.setX( nSizePosX );
425 
426  if ( pImpl->bSize )
427  {
428  pDev->DrawImage( aPnt, pImpl->aSizeImage );
429  aPnt.AdjustX(pImpl->aSizeImage.GetSizePixel().Width() );
430  Point aDrwPnt = aPnt;
431  aPnt.AdjustX(PAINT_OFFSET );
432  aStr = GetMetricStr_Impl( pImpl->aSize.Width() ) + " x " +
433  GetMetricStr_Impl( pImpl->aSize.Height() );
434  aRect = tools::Rectangle(aDrwPnt, rRect.BottomRight());
435  pDev->DrawRect(aRect);
436  aOrigRegion = pDev->GetClipRegion();
437  pDev->SetClipRegion(vcl::Region(aRect));
438  pDev->DrawText(aPnt, aStr);
439  pDev->SetClipRegion(aOrigRegion);
440  }
441  else
442  pDev->DrawRect( tools::Rectangle( aPnt, rRect.BottomRight() ) );
443  }
444  else if ( pImpl->bTable )
445  {
446  pDev->DrawRect( rRect );
447  pDev->DrawText( Point(
448  rRect.Left() + rRect.GetWidth() / 2 - pDev->GetTextWidth( pImpl->aStr ) / 2,
449  aItemPos.Y() ), pImpl->aStr );
450  }
451  else
452  {
453  // Empty display if neither size nor table position are available.
454  // Date/Time are no longer used (#65302#).
455  pDev->DrawRect( rRect );
456  }
457 
458  pDev->SetLineColor( aOldLineColor );
459  pDev->SetFillColor( aOldFillColor );
460 }
461 
463 {
464  // set only strings as text at the statusBar, so that the Help-Tips
465  // can work with the text, when it is too long for the statusBar
466  OUString aText;
467  int nCharsWidth = -1;
468  if ( pImpl->bPos || pImpl->bSize )
469  {
470  aText = GetMetricStr_Impl( pImpl->aPos.X()) + " / " +
471  GetMetricStr_Impl( pImpl->aPos.Y());
472  // widest X/Y string looks like "-999,99"
473  nCharsWidth = 1 + 6 + 3 + 6; // icon + x + slash + y
474  if ( pImpl->bSize )
475  {
476  aText += " " + GetMetricStr_Impl( pImpl->aSize.Width() ) + " x " +
477  GetMetricStr_Impl( pImpl->aSize.Height() );
478  nCharsWidth += 1 + 1 + 4 + 3 + 4; // icon + space + w + x + h
479  }
480  }
481  else if ( pImpl->bTable )
482  aText = pImpl->aStr;
483 
484  GetStatusBar().SetItemText( GetId(), aText, nCharsWidth );
485 }
486 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void SetClipRegion()
vcl::Region GetClipRegion() const
const Wallpaper & GetBackground() const
FieldUnit
const LocaleDataWrapper & GetLocaleDataWrapper() const
sal_uInt16 GetSlotId() const
void DrawImage(const Point &rPos, const Image &rImage, DrawImageFlags nStyle=DrawImageFlags::NONE)
const tools::Rectangle & GetRect() const
constexpr tools::Long Left() const
#define PAINT_OFFSET
Definition: pszctrl.cxx:40
long Long
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
static const AllSettings & GetSettings()
#define PSZ_FUNC_COUNT
Definition: stbctrls.h:26
void SetItemText(sal_uInt16 nItemId, const OUString &rText, int nCharsWidth=-1)
virtual ~SvxPosSizeStatusBarControl() override
Definition: pszctrl.cxx:248
virtual void StateChangedAtStatusBarControl(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem *pState) override
Definition: pszctrl.cxx:268
void SetHelpText(sal_uInt16 nItemId, const OUString &rText)
sal_uInt16 sal_Unicode
#define PSZ_FUNC_COUNT2
Definition: stbctrls.h:25
SVX_DLLPRIVATE OUString GetMetricStr_Impl(tools::Long nVal) const
Definition: pszctrl.cxx:63
void SetItemData(sal_uInt16 nItemId, void *pNewData)
constexpr tools::Long GetWidth() const
void DrawRect(const tools::Rectangle &rRect)
Point GetItemTextPos(sal_uInt16 nItemId) const
sal_uInt16 GetId() const
static FieldUnit GetModuleFieldUnit(css::uno::Reference< css::frame::XFrame > const &i_frame)
const OUString & getNumDecimalSep() const
void SetLineColor()
#define PSZ_FUNC_AVG
Definition: stbctrls.h:24
vcl::RenderContext * GetRenderContext() const
#define PSZ_FUNC_MAX
Definition: stbctrls.h:27
tools::Long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::text::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
uno_Any a
virtual bool QueryValue(css::uno::Any &rVal, sal_uInt8 nMemberId=0) const override
#define STR_POSITION
Definition: pszctrl.cxx:217
#define PSZ_FUNC_SELECTION_COUNT
Definition: stbctrls.h:30
weld::Window * GetPopupParent(vcl::Window &rOutWin, tools::Rectangle &rRect)
const Color & GetColor() const
void SetFillColor()
const Color & GetLineColor() const
CommandEventId GetCommand() const
float u
#define PSZ_FUNC_SUM
Definition: stbctrls.h:29
constexpr Point TopLeft() const
#define STR_TABLECELL
Definition: pszctrl.cxx:218
constexpr tools::Long Bottom() const
const Point & GetMousePosPixel() const
SfxItemState
SFX_IMPL_STATUSBAR_CONTROL(SvxPosSizeStatusBarControl, SvxSizeItem)
virtual void Command(const CommandEvent &rCEvt)
StatusBar & GetStatusBar() const
void SetHelpId(sal_uInt16 nItemId, const OString &rHelpId)
#define PSZ_FUNC_NONE
Definition: stbctrls.h:31
constexpr Point BottomRight() const
sal_Int64 ConvertValue(sal_Int64 nValue, sal_Int64 mnBaseValue, sal_uInt16 nDecDigits, FieldUnit eInUnit, FieldUnit eOutUnit)
#define SAL_WARN(area, stream)
virtual void Command(const CommandEvent &rCEvt) override
Definition: pszctrl.cxx:351
SvxPosSizeStatusBarControl(sal_uInt16 nSlotId, sal_uInt16 nId, StatusBar &rStb)
Definition: pszctrl.cxx:221
void DrawText(const Point &rStartPt, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, std::vector< tools::Rectangle > *pVector=nullptr, OUString *pDisplayText=nullptr, const SalLayoutGlyphs *pLayoutCache=nullptr)
aStr
std::unique_ptr< SvxPosSizeStatusBarControl_Impl > pImpl
Definition: pszctrl.hxx:31
#define STR_FUNC
Definition: pszctrl.cxx:219
const Color & GetFillColor() const
virtual void Paint(const UserDrawEvent &rEvt) override
Definition: pszctrl.cxx:390
#define PSZ_FUNC_MIN
Definition: stbctrls.h:28