summaryrefslogtreecommitdiffstats
path: root/svx/source/stbctrls/pszctrl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svx/source/stbctrls/pszctrl.cxx')
-rw-r--r--svx/source/stbctrls/pszctrl.cxx533
1 files changed, 533 insertions, 0 deletions
diff --git a/svx/source/stbctrls/pszctrl.cxx b/svx/source/stbctrls/pszctrl.cxx
new file mode 100644
index 0000000000..6de9554391
--- /dev/null
+++ b/svx/source/stbctrls/pszctrl.cxx
@@ -0,0 +1,533 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/fieldvalues.hxx>
+#include <vcl/status.hxx>
+#include <vcl/image.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+#include <svl/stritem.hxx>
+#include <svl/ptitem.hxx>
+#include <sfx2/module.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/statusitem.hxx>
+#include <svx/strings.hrc>
+#include <svl/intitem.hxx>
+#include <sal/log.hxx>
+
+#include <svx/pszctrl.hxx>
+
+#define PAINT_OFFSET 5
+
+#include <editeng/sizeitem.hxx>
+#include "stbctrls.h"
+
+#include <svx/svxids.hrc>
+#include <bitmaps.hlst>
+#include <unotools/localedatawrapper.hxx>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+/* [Description]
+
+ Function used to create a text representation of
+ a metric value
+
+ nVal is the metric value in the unit eUnit.
+
+ [cross reference]
+
+ <SvxPosSizeStatusBarControl::Paint(const UserDrawEvent&)>
+*/
+
+OUString SvxPosSizeStatusBarControl::GetMetricStr_Impl( tools::Long nVal ) const
+{
+ // deliver and set the Metric of the application
+ FieldUnit eOutUnit = SfxModule::GetModuleFieldUnit( getFrameInterface() );
+
+ OUString sMetric;
+ const sal_Unicode cSep = Application::GetSettings().GetLocaleDataWrapper().getNumDecimalSep()[0];
+ sal_Int64 nConvVal = vcl::ConvertValue( nVal * 100, 0, 0, FieldUnit::MM_100TH, eOutUnit );
+
+ if ( nConvVal < 0 && ( nConvVal / 100 == 0 ) )
+ sMetric += "-";
+ sMetric += OUString::number(nConvVal / 100);
+
+ if( FieldUnit::NONE != eOutUnit )
+ {
+ sMetric += OUStringChar(cSep);
+ sal_Int64 nFract = nConvVal % 100;
+
+ if ( nFract < 0 )
+ nFract *= -1;
+ if ( nFract < 10 )
+ sMetric += "0";
+ sMetric += OUString::number(nFract);
+ }
+
+ return sMetric;
+}
+
+
+SFX_IMPL_STATUSBAR_CONTROL(SvxPosSizeStatusBarControl, SvxSizeItem);
+
+namespace {
+
+class FunctionPopup_Impl
+{
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Menu> m_xMenu;
+ sal_uInt32 m_nSelected;
+ static sal_uInt16 id_to_function(std::u16string_view rIdent);
+ static OUString function_to_id(sal_uInt16 nFunc);
+public:
+ explicit FunctionPopup_Impl(sal_uInt32 nCheckEncoded);
+ OUString Execute(weld::Window* pParent, const tools::Rectangle& rRect)
+ {
+ return m_xMenu->popup_at_rect(pParent, rRect);
+ }
+ sal_uInt32 GetSelected(std::u16string_view curident) const;
+};
+
+}
+
+sal_uInt16 FunctionPopup_Impl::id_to_function(std::u16string_view rIdent)
+{
+ if (rIdent == u"avg")
+ return PSZ_FUNC_AVG;
+ else if (rIdent == u"counta")
+ return PSZ_FUNC_COUNT2;
+ else if (rIdent == u"count")
+ return PSZ_FUNC_COUNT;
+ else if (rIdent == u"max")
+ return PSZ_FUNC_MAX;
+ else if (rIdent == u"min")
+ return PSZ_FUNC_MIN;
+ else if (rIdent == u"sum")
+ return PSZ_FUNC_SUM;
+ else if (rIdent == u"selection")
+ return PSZ_FUNC_SELECTION_COUNT;
+ else if (rIdent == u"none")
+ return PSZ_FUNC_NONE;
+ return 0;
+}
+
+OUString FunctionPopup_Impl::function_to_id(sal_uInt16 nFunc)
+{
+ switch (nFunc)
+ {
+ case PSZ_FUNC_AVG:
+ return "avg";
+ case PSZ_FUNC_COUNT2:
+ return "counta";
+ case PSZ_FUNC_COUNT:
+ return "count";
+ case PSZ_FUNC_MAX:
+ return "max";
+ case PSZ_FUNC_MIN:
+ return "min";
+ case PSZ_FUNC_SUM:
+ return "sum";
+ case PSZ_FUNC_SELECTION_COUNT:
+ return "selection";
+ case PSZ_FUNC_NONE:
+ return "none";
+ }
+ return {};
+}
+
+FunctionPopup_Impl::FunctionPopup_Impl(sal_uInt32 nCheckEncoded)
+ : m_xBuilder(Application::CreateBuilder(nullptr, "svx/ui/functionmenu.ui"))
+ , m_xMenu(m_xBuilder->weld_menu("menu"))
+ , m_nSelected(nCheckEncoded)
+{
+ for ( sal_uInt16 nCheck = 1; nCheck < 32; ++nCheck )
+ if ( nCheckEncoded & (1u << nCheck) )
+ m_xMenu->set_active(function_to_id(nCheck), true);
+}
+
+sal_uInt32 FunctionPopup_Impl::GetSelected(std::u16string_view curident) const
+{
+ sal_uInt32 nSelected = m_nSelected;
+ sal_uInt16 nCurItemId = id_to_function(curident);
+ if ( nCurItemId == PSZ_FUNC_NONE )
+ nSelected = ( 1 << PSZ_FUNC_NONE );
+ else
+ {
+ nSelected &= (~( 1u << PSZ_FUNC_NONE )); // Clear the "None" bit
+ nSelected ^= ( 1u << nCurItemId ); // Toggle the bit corresponding to nCurItemId
+ if ( !nSelected )
+ nSelected = ( 1u << PSZ_FUNC_NONE );
+ }
+ return nSelected;
+}
+
+struct SvxPosSizeStatusBarControl_Impl
+
+/* [Description]
+
+ This implementation-structure of the class SvxPosSizeStatusBarControl
+ is done for the un-linking of the changes of the exported interface such as
+ the toning down of symbols that are visible externally.
+
+ One instance exists for each SvxPosSizeStatusBarControl-instance
+ during its life time
+*/
+
+{
+ Point aPos; // valid when a position is shown
+ Size aSize; // valid when a size is shown
+ OUString aStr; // valid when a text is shown
+ bool bPos; // show position ?
+ bool bSize; // set size ?
+ bool bTable; // set table index ?
+ bool bHasMenu; // set StarCalc popup menu ?
+ sal_uInt32 nFunctionSet; // the selected StarCalc functions encoded in 32 bits
+ Image aPosImage; // Image to show the position
+ Image aSizeImage; // Image to show the size
+};
+
+/* [Description]
+
+ Ctor():
+ Create an instance of the implementation class,
+ load the images for the position and size
+*/
+
+#define STR_POSITION ".uno:Position"
+#define STR_TABLECELL ".uno:StateTableCell"
+#define STR_FUNC ".uno:StatusBarFunc"
+
+SvxPosSizeStatusBarControl::SvxPosSizeStatusBarControl( sal_uInt16 _nSlotId,
+ sal_uInt16 _nId,
+ StatusBar& rStb ) :
+ SfxStatusBarControl( _nSlotId, _nId, rStb ),
+ pImpl( new SvxPosSizeStatusBarControl_Impl )
+{
+ pImpl->bPos = false;
+ pImpl->bSize = false;
+ pImpl->bTable = false;
+ pImpl->bHasMenu = false;
+ pImpl->nFunctionSet = 0;
+ pImpl->aPosImage = Image(StockImage::Yes, RID_SVXBMP_POSITION);
+ pImpl->aSizeImage = Image(StockImage::Yes, RID_SVXBMP_SIZE);
+
+ addStatusListener( STR_POSITION); // SID_ATTR_POSITION
+ addStatusListener( STR_TABLECELL); // SID_TABLE_CELL
+ addStatusListener( STR_FUNC); // SID_PSZ_FUNCTION
+ ImplUpdateItemText();
+}
+
+/* [Description]
+
+ Dtor():
+ remove the pointer to the implementation class, so that the timer is stopped
+
+*/
+
+SvxPosSizeStatusBarControl::~SvxPosSizeStatusBarControl()
+{
+}
+
+
+/* [Description]
+
+ SID_PSZ_FUNCTION activates the popup menu for Calc:
+
+ Status overview
+ Depending on the type of the item, a special setting is enabled, the others disabled.
+
+ NULL/Void SfxPointItem SvxSizeItem SfxStringItem
+ ------------------------------------------------------------------------
+ Position sal_False FALSE
+ Size FALSE TRUE FALSE
+ Text sal_False sal_False TRUE
+
+*/
+
+void SvxPosSizeStatusBarControl::StateChangedAtStatusBarControl( sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState )
+{
+ // Because the combi-controller, always sets the current Id as HelpId
+ // first clean the cached HelpText
+ GetStatusBar().SetHelpText( GetId(), "" );
+
+ switch ( nSID )
+ {
+ case SID_ATTR_POSITION : GetStatusBar().SetHelpId( GetId(), STR_POSITION ); break;
+ case SID_TABLE_CELL: GetStatusBar().SetHelpId( GetId(), STR_TABLECELL ); break;
+ case SID_PSZ_FUNCTION: GetStatusBar().SetHelpId( GetId(), STR_FUNC ); break;
+ default: break;
+ }
+
+ if ( nSID == SID_PSZ_FUNCTION )
+ {
+ if ( eState == SfxItemState::DEFAULT )
+ {
+ pImpl->bHasMenu = true;
+ if ( auto pUInt32Item = dynamic_cast< const SfxUInt32Item* >(pState) )
+ pImpl->nFunctionSet = pUInt32Item->GetValue();
+ }
+ else
+ pImpl->bHasMenu = false;
+ }
+ else if ( SfxItemState::DEFAULT != eState )
+ {
+ // don't switch to empty display before an empty state was
+ // notified for all display types
+
+ if ( nSID == SID_TABLE_CELL )
+ pImpl->bTable = false;
+ else if ( nSID == SID_ATTR_POSITION )
+ pImpl->bPos = false;
+ else if ( nSID == GetSlotId() ) // controller is registered for SID_ATTR_SIZE
+ pImpl->bSize = false;
+ else
+ {
+ SAL_WARN( "svx.stbcrtls","unknown slot id");
+ }
+ }
+ else if ( auto pPointItem = dynamic_cast<const SfxPointItem*>( pState) )
+ {
+ // show position
+ pImpl->aPos = pPointItem->GetValue();
+ pImpl->bPos = true;
+ pImpl->bTable = false;
+ }
+ else if ( auto pSizeItem = dynamic_cast<const SvxSizeItem*>( pState) )
+ {
+ // show size
+ pImpl->aSize = pSizeItem->GetSize();
+ pImpl->bSize = true;
+ pImpl->bTable = false;
+ }
+ else if ( auto pStatusItem = dynamic_cast<const SvxStatusItem*>( pState) )
+ {
+ // show string (table cell or different)
+ pImpl->aStr = pStatusItem->GetValue();
+ pImpl->bTable = true;
+ pImpl->bPos = false;
+ pImpl->bSize = false;
+ if (!pImpl->aStr.isEmpty())
+ {
+ OUString sTip;
+ switch (pStatusItem->GetCategory())
+ {
+ case StatusCategory::TableCell:
+ sTip = SvxResId(RID_SVXSTR_TABLECELL_HINT);
+ break;
+ case StatusCategory::Section:
+ sTip = SvxResId(RID_SVXSTR_SECTION_HINT);
+ break;
+ case StatusCategory::TableOfContents:
+ sTip = SvxResId(RID_SVXSTR_TOC_HINT);
+ break;
+ case StatusCategory::Numbering:
+ sTip = SvxResId(RID_SVXSTR_NUMBERING_HINT);
+ break;
+ case StatusCategory::ListStyle:
+ sTip = SvxResId(RID_SVXSTR_LIST_STYLE_HINT);
+ break;
+ case StatusCategory::Formula:
+ sTip = SvxResId(RID_SVXSTR_FORMULA_HINT);
+ break;
+ case StatusCategory::RowColumn:
+ sTip = SvxResId(RID_SVXSTR_ROW_COLUMN_HINT);
+ break;
+ case StatusCategory::NONE:
+ break;
+ }
+ GetStatusBar().SetQuickHelpText(GetId(), sTip);
+ }
+ }
+ else if ( auto pStringItem = dynamic_cast<const SfxStringItem*>( pState) )
+ {
+ SAL_WARN( "svx.stbcrtls", "this should be a SvxStatusItem not a SfxStringItem" );
+ // show string (table cell or different)
+ pImpl->aStr = pStringItem->GetValue();
+ pImpl->bTable = true;
+ pImpl->bPos = false;
+ pImpl->bSize = false;
+ }
+ else
+ {
+ SAL_WARN( "svx.stbcrtls", "invalid item type" );
+ pImpl->bPos = false;
+ pImpl->bSize = false;
+ pImpl->bTable = false;
+ }
+
+ GetStatusBar().SetItemData( GetId(), nullptr );
+
+ ImplUpdateItemText();
+}
+
+
+/* [Description]
+
+ execute popup menu, when the status enables this
+*/
+
+void SvxPosSizeStatusBarControl::Command( const CommandEvent& rCEvt )
+{
+ if ( rCEvt.GetCommand() == CommandEventId::ContextMenu && pImpl->bHasMenu )
+ {
+ sal_uInt32 nSelect = pImpl->nFunctionSet;
+ if (!nSelect)
+ nSelect = ( 1 << PSZ_FUNC_NONE );
+ tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1,1));
+ weld::Window* pParent = weld::GetPopupParent(GetStatusBar(), aRect);
+ FunctionPopup_Impl aMenu(nSelect);
+ OUString sIdent = aMenu.Execute(pParent, aRect);
+ if (!sIdent.isEmpty())
+ {
+ nSelect = aMenu.GetSelected(sIdent);
+ if (nSelect)
+ {
+ if (nSelect == (1 << PSZ_FUNC_NONE))
+ nSelect = 0;
+
+ css::uno::Any a;
+ SfxUInt32Item aItem( SID_PSZ_FUNCTION, nSelect );
+ aItem.QueryValue( a );
+ css::uno::Sequence< css::beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
+ "StatusBarFunc", a) };
+ execute( ".uno:StatusBarFunc", aArgs );
+ }
+ }
+ }
+ else
+ SfxStatusBarControl::Command( rCEvt );
+}
+
+
+/* [Description]
+
+ Depending on the type to be shown, the value us shown. First the
+ rectangle is repainted (removed).
+*/
+
+void SvxPosSizeStatusBarControl::Paint( const UserDrawEvent& rUsrEvt )
+{
+ vcl::RenderContext* pDev = rUsrEvt.GetRenderContext();
+
+ const tools::Rectangle& rRect = rUsrEvt.GetRect();
+ StatusBar& rBar = GetStatusBar();
+ Point aItemPos = rBar.GetItemTextPos( GetId() );
+ Color aOldLineColor = pDev->GetLineColor();
+ Color aOldFillColor = pDev->GetFillColor();
+ pDev->SetLineColor();
+ pDev->SetFillColor( pDev->GetBackground().GetColor() );
+
+ if ( pImpl->bPos || pImpl->bSize )
+ {
+ // count the position for showing the size
+ tools::Long nSizePosX =
+ rRect.Left() + rRect.GetWidth() / 2 + PAINT_OFFSET;
+ // draw position
+ Point aPnt = rRect.TopLeft();
+ aPnt.AdjustX(PAINT_OFFSET );
+ // vertically centered
+ const tools::Long nSizePosY =
+ (rRect.GetHeight() - pImpl->aPosImage.GetSizePixel().Height()) / 2;
+ aPnt.AdjustY( nSizePosY );
+
+ pDev->DrawImage( aPnt, pImpl->aPosImage );
+ aPnt.AdjustX(pImpl->aPosImage.GetSizePixel().Width() );
+ aPnt.AdjustX(PAINT_OFFSET );
+ OUString aStr = GetMetricStr_Impl( pImpl->aPos.X()) + " / " +
+ GetMetricStr_Impl( pImpl->aPos.Y());
+ tools::Rectangle aRect(aPnt, Point(nSizePosX, rRect.Bottom()));
+ pDev->DrawRect(aRect);
+ vcl::Region aOrigRegion(pDev->GetClipRegion());
+ pDev->SetClipRegion(vcl::Region(aRect));
+ pDev->DrawText(aPnt, aStr);
+ pDev->SetClipRegion(aOrigRegion);
+
+ // draw the size, when available
+ aPnt.setX( nSizePosX );
+
+ if ( pImpl->bSize )
+ {
+ pDev->DrawImage( aPnt, pImpl->aSizeImage );
+ aPnt.AdjustX(pImpl->aSizeImage.GetSizePixel().Width() );
+ Point aDrwPnt = aPnt;
+ aPnt.AdjustX(PAINT_OFFSET );
+ aStr = GetMetricStr_Impl( pImpl->aSize.Width() ) + " x " +
+ GetMetricStr_Impl( pImpl->aSize.Height() );
+ aRect = tools::Rectangle(aDrwPnt, rRect.BottomRight());
+ pDev->DrawRect(aRect);
+ aOrigRegion = pDev->GetClipRegion();
+ pDev->SetClipRegion(vcl::Region(aRect));
+ pDev->DrawText(aPnt, aStr);
+ pDev->SetClipRegion(aOrigRegion);
+ }
+ else
+ pDev->DrawRect( tools::Rectangle( aPnt, rRect.BottomRight() ) );
+ }
+ else if ( pImpl->bTable )
+ {
+ pDev->DrawRect( rRect );
+ pDev->DrawText( Point(
+ rRect.Left() + rRect.GetWidth() / 2 - pDev->GetTextWidth( pImpl->aStr ) / 2,
+ aItemPos.Y() ), pImpl->aStr );
+ }
+ else
+ {
+ // Empty display if neither size nor table position are available.
+ // Date/Time are no longer used (#65302#).
+ pDev->DrawRect( rRect );
+ }
+
+ pDev->SetLineColor( aOldLineColor );
+ pDev->SetFillColor( aOldFillColor );
+}
+
+void SvxPosSizeStatusBarControl::ImplUpdateItemText()
+{
+ // set only strings as text at the statusBar, so that the Help-Tips
+ // can work with the text, when it is too long for the statusBar
+ OUString aText;
+ int nCharsWidth = -1;
+ if ( pImpl->bPos || pImpl->bSize )
+ {
+ aText = GetMetricStr_Impl( pImpl->aPos.X()) + " / " +
+ GetMetricStr_Impl( pImpl->aPos.Y());
+ // widest X/Y string looks like "-999,99"
+ nCharsWidth = 1 + 6 + 3 + 6; // icon + x + slash + y
+ if ( pImpl->bSize )
+ {
+ aText += " " + GetMetricStr_Impl( pImpl->aSize.Width() ) + " x " +
+ GetMetricStr_Impl( pImpl->aSize.Height() );
+ nCharsWidth += 1 + 1 + 4 + 3 + 4; // icon + space + w + x + h
+ }
+ }
+ else if ( pImpl->bTable )
+ aText = pImpl->aStr;
+
+ GetStatusBar().SetItemText( GetId(), aText, nCharsWidth );
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */