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 "NumberFormatPropertyPanel.hxx"
21 #include <sc.hrc>
22 #include <sfx2/bindings.hxx>
23 #include <sfx2/dispatch.hxx>
24 #include <svl/intitem.hxx>
25 #include <svl/stritem.hxx>
26 #include <svl/itemset.hxx>
27 #include <svx/numfmtsh.hxx>
28 #include <o3tl/string_view.hxx>
29 #include <com/sun/star/lang/IllegalArgumentException.hpp>
30 
31 using namespace css;
32 using namespace css::uno;
33 
34 namespace sc::sidebar {
35 
NumberFormatPropertyPanel(weld::Widget * pParent,const css::uno::Reference<css::frame::XFrame> & rxFrame,SfxBindings * pBindings)36 NumberFormatPropertyPanel::NumberFormatPropertyPanel(
37     weld::Widget* pParent,
38     const css::uno::Reference<css::frame::XFrame>& rxFrame,
39     SfxBindings* pBindings)
40     : PanelLayout(pParent,u"NumberFormatPropertyPanel"_ustr, u"modules/scalc/ui/sidebarnumberformat.ui"_ustr)
41     , mxLbCategory(m_xBuilder->weld_combo_box(u"numberformatcombobox"_ustr))
42     , mxTBCategory(m_xBuilder->weld_toolbar(u"numberformat"_ustr))
43     , mxCategoryDispatch(new ToolbarUnoDispatcher(*mxTBCategory, *m_xBuilder, rxFrame))
44     , mxFtDecimals(m_xBuilder->weld_label(u"decimalplaceslabel"_ustr))
45     , mxEdDecimals(m_xBuilder->weld_spin_button(u"decimalplaces"_ustr))
46     , mxFtDenominator(m_xBuilder->weld_label(u"denominatorplaceslabel"_ustr))
47     , mxEdDenominator(m_xBuilder->weld_spin_button(u"denominatorplaces"_ustr))
48     , mxFtLeadZeroes(m_xBuilder->weld_label(u"leadingzeroeslabel"_ustr))
49     , mxEdLeadZeroes(m_xBuilder->weld_spin_button(u"leadingzeroes"_ustr))
50     , mxBtnNegRed(m_xBuilder->weld_check_button(u"negativenumbersred"_ustr))
51     , mxBtnThousand(m_xBuilder->weld_check_button(u"thousandseparator"_ustr))
52     , mxBtnEngineering(m_xBuilder->weld_check_button(u"engineeringnotation"_ustr))
53     , maNumFormatControl(SID_NUMBER_TYPE_FORMAT, *pBindings, *this)
54     , maFormatControl(SID_NUMBER_FORMAT, *pBindings, *this)
55     , mnCategorySelected(0)
56     , mpBindings(pBindings)
57 {
58     Initialize();
59 }
60 
~NumberFormatPropertyPanel()61 NumberFormatPropertyPanel::~NumberFormatPropertyPanel()
62 {
63     mxLbCategory.reset();
64     mxCategoryDispatch.reset();
65     mxTBCategory.reset();
66     mxFtDecimals.reset();
67     mxEdDecimals.reset();
68     mxFtDenominator.reset();
69     mxEdDenominator.reset();
70     mxFtLeadZeroes.reset();
71     mxEdLeadZeroes.reset();
72     mxBtnNegRed.reset();
73     mxBtnThousand.reset();
74     mxBtnEngineering.reset();
75 
76     maNumFormatControl.dispose();
77     maFormatControl.dispose();
78 }
79 
Initialize()80 void NumberFormatPropertyPanel::Initialize()
81 {
82     mxLbCategory->connect_changed( LINK(this, NumberFormatPropertyPanel, NumFormatSelectHdl) );
83     mxLbCategory->set_active(0);
84 
85     Link<weld::SpinButton&,void> aLink = LINK(this, NumberFormatPropertyPanel, NumFormatValueHdl);
86 
87     mxEdDecimals->connect_value_changed( aLink );
88     mxEdDenominator->connect_value_changed( aLink );
89     mxEdLeadZeroes->connect_value_changed( aLink );
90 
91     mxBtnNegRed->connect_toggled( LINK(this, NumberFormatPropertyPanel, NumFormatValueClickHdl) );
92     mxBtnThousand->connect_toggled( LINK(this, NumberFormatPropertyPanel, NumFormatValueClickHdl) );
93     mxBtnEngineering->connect_toggled( LINK(this, NumberFormatPropertyPanel, NumFormatValueClickHdl) );
94 }
95 
IMPL_LINK(NumberFormatPropertyPanel,NumFormatSelectHdl,weld::ComboBox &,rBox,void)96 IMPL_LINK( NumberFormatPropertyPanel, NumFormatSelectHdl, weld::ComboBox&, rBox, void )
97 {
98     const sal_Int32 nVal = rBox.get_active();
99     if( nVal != mnCategorySelected )
100     {
101         SfxUInt16Item aItem( SID_NUMBER_TYPE_FORMAT,  nVal );
102         GetBindings()->GetDispatcher()->ExecuteList(SID_NUMBER_TYPE_FORMAT,
103                 SfxCallMode::RECORD, { &aItem });
104         mnCategorySelected = nVal;
105     }
106 }
107 
IMPL_LINK_NOARG(NumberFormatPropertyPanel,NumFormatValueClickHdl,weld::Toggleable &,void)108 IMPL_LINK_NOARG( NumberFormatPropertyPanel, NumFormatValueClickHdl, weld::Toggleable&, void )
109 {
110     NumFormatValueHdl(*mxEdDecimals);
111 }
112 
IMPL_LINK_NOARG(NumberFormatPropertyPanel,NumFormatValueHdl,weld::SpinButton &,void)113 IMPL_LINK_NOARG( NumberFormatPropertyPanel, NumFormatValueHdl, weld::SpinButton&, void )
114 {
115     OUString    aFormat;
116     OUString    sBreak = u","_ustr;
117     bool        bThousand   = ( mxBtnThousand->get_visible() && mxBtnThousand->get_sensitive() && mxBtnThousand->get_active() )
118                            || ( mxBtnEngineering->get_visible() && mxBtnEngineering->get_sensitive() && mxBtnEngineering->get_active() );
119     bool        bNegRed     =  mxBtnNegRed->get_sensitive() && mxBtnNegRed->get_active();
120     sal_uInt16  nPrecision  = (mxEdDecimals->get_sensitive() && mxEdDecimals->get_visible())
121                             ? static_cast<sal_uInt16>(mxEdDecimals->get_value())
122                             : (mxEdDenominator->get_sensitive() && mxEdDenominator->get_visible())
123                                 ? static_cast<sal_uInt16>(mxEdDenominator->get_value())
124                                 : sal_uInt16(0);
125     sal_uInt16  nLeadZeroes = (mxEdLeadZeroes->get_sensitive())
126                             ? static_cast<sal_uInt16>(mxEdLeadZeroes->get_value())
127                             : sal_uInt16(0);
128 
129     OUString sThousand = OUString::number(static_cast<sal_Int32>(bThousand));
130     OUString sNegRed = OUString::number(static_cast<sal_Int32>(bNegRed));
131     OUString sPrecision = OUString::number(nPrecision);
132     OUString sLeadZeroes = OUString::number(nLeadZeroes);
133 
134     aFormat += sThousand +
135         sBreak +
136         sNegRed +
137         sBreak +
138         sPrecision +
139         sBreak +
140         sLeadZeroes +
141         sBreak;
142 
143     SfxStringItem aItem( SID_NUMBER_FORMAT,  aFormat );
144     GetBindings()->GetDispatcher()->ExecuteList(SID_NUMBER_FORMAT,
145             SfxCallMode::RECORD, { &aItem });
146 }
147 
Create(weld::Widget * pParent,const css::uno::Reference<css::frame::XFrame> & rxFrame,SfxBindings * pBindings)148 std::unique_ptr<PanelLayout> NumberFormatPropertyPanel::Create (
149     weld::Widget* pParent,
150     const css::uno::Reference<css::frame::XFrame>& rxFrame,
151     SfxBindings* pBindings)
152 {
153     if (pParent == nullptr)
154         throw lang::IllegalArgumentException(u"no parent Window given to NumberFormatPropertyPanel::Create"_ustr, nullptr, 0);
155     if ( ! rxFrame.is())
156         throw lang::IllegalArgumentException(u"no XFrame given to NumberFormatPropertyPanel::Create"_ustr, nullptr, 1);
157     if (pBindings == nullptr)
158         throw lang::IllegalArgumentException(u"no SfxBindings given to NumberFormatPropertyPanel::Create"_ustr, nullptr, 2);
159 
160     return std::make_unique<NumberFormatPropertyPanel>(pParent, rxFrame, pBindings);
161 }
162 
HandleContextChange(const vcl::EnumContext & rContext)163 void NumberFormatPropertyPanel::HandleContextChange(
164     const vcl::EnumContext& rContext)
165 {
166     if(maContext == rContext)
167     {
168         // Nothing to do.
169         return;
170     }
171 
172     maContext = rContext;
173 }
174 
NotifyItemUpdate(sal_uInt16 nSID,SfxItemState eState,const SfxPoolItem * pState)175 void NumberFormatPropertyPanel::NotifyItemUpdate(
176     sal_uInt16 nSID,
177     SfxItemState eState,
178     const SfxPoolItem* pState)
179 {
180     switch(nSID)
181     {
182     case SID_NUMBER_TYPE_FORMAT:
183         {
184             if( eState >= SfxItemState::DEFAULT)
185             {
186                 const SfxUInt16Item* pItem = static_cast<const SfxUInt16Item*>(pState);
187                 sal_uInt16 nVal = pItem->GetValue();
188                 mnCategorySelected = nVal;
189                 mxLbCategory->set_active(nVal);
190                 // There is an offset between category list enum and listbox in side panel
191                 SvxNumberFormatCategory nCategory = static_cast< SvxNumberFormatCategory >( nVal + 1 );
192                 if (nCategory <= CAT_FRACTION &&  // General, Number, Percent, Currency, Time, Scientific, Fraction
193                     nCategory != CAT_DATE )       // not Date
194                 {
195                     // For scientific, Thousand separator is replaced by Engineering notation
196                     bool bIsScientific ( nCategory == CAT_SCIENTIFIC );
197                     // For fraction, Decimal places is replaced by Denominator places
198                     bool bIsFraction ( nCategory == CAT_FRACTION );
199                     // For Time, Decimal places and NegRed available
200                     bool bIsTime ( nCategory == CAT_TIME );
201                     mxBtnThousand->set_visible( !bIsScientific );
202                     mxBtnThousand->set_sensitive( !bIsScientific && !bIsTime );
203                     mxBtnThousand->set_active(false);
204                     mxBtnEngineering->set_visible(bIsScientific);
205                     mxBtnEngineering->set_sensitive(bIsScientific);
206                     mxBtnEngineering->set_active(false);
207                     mxBtnNegRed->set_sensitive(true);
208                     mxFtDenominator->set_visible(bIsFraction);
209                     mxEdDenominator->set_visible(bIsFraction);
210                     mxFtDenominator->set_sensitive(bIsFraction);
211                     mxEdDenominator->set_sensitive(bIsFraction);
212                     mxFtDecimals->set_visible(!bIsFraction);
213                     mxEdDecimals->set_visible(!bIsFraction);
214                     mxFtDecimals->set_sensitive(!bIsFraction);
215                     mxEdDecimals->set_sensitive(!bIsFraction);
216                     mxFtLeadZeroes->set_sensitive( !bIsTime );
217                     mxEdLeadZeroes->set_sensitive( !bIsTime );
218                 }
219                 else
220                     DisableControls();
221             }
222             else
223             {
224                 DisableControls();
225                 mxLbCategory->set_active(-1);
226                 mnCategorySelected = 0;
227             }
228         }
229         break;
230     case SID_NUMBER_FORMAT:
231         {
232             bool          bThousand     =    false;
233             bool          bNegRed       =    false;
234             sal_uInt16        nPrecision    =    0;
235             sal_uInt16        nLeadZeroes   =    0;
236             bool          bNatNum12     =    false;
237             SvxNumberFormatCategory nCategory = static_cast< SvxNumberFormatCategory >( mnCategorySelected + 1 );
238             if( eState >= SfxItemState::DEFAULT)
239             {
240                 const SfxStringItem* pItem = static_cast<const SfxStringItem*>(pState);
241                 const OUString& aCode = pItem->GetValue();
242                 sal_Int32 nIndex = 0;
243                 sal_Int32 aFormat[5] = {0};
244                 for (sal_Int32 & rn : aFormat)
245                 {
246                     rn = o3tl::toInt32(o3tl::getToken(aCode, 0, ',', nIndex));
247                     if (nIndex<0)
248                         break;
249                 }
250                 bThousand   = static_cast<bool>(aFormat[0]);
251                 bNegRed     = static_cast<bool>(aFormat[1]);
252                 nPrecision  = static_cast<sal_uInt16>(aFormat[2]);
253                 nLeadZeroes = static_cast<sal_uInt16>(aFormat[3]);
254                 bNatNum12   = static_cast< bool >( aFormat[4] );
255             }
256             else
257             {
258                 bThousand   =    false;
259                 bNegRed     =    false;
260                 nPrecision  =    0;
261                 nLeadZeroes =    1;
262             }
263             if ( nCategory == CAT_NUMBER ||
264                  nCategory == CAT_PERCENT ||
265                  nCategory == CAT_CURRENCY ||
266                  nCategory == CAT_FRACTION )
267                 mxBtnThousand->set_sensitive( !bNatNum12 );
268             if ( mxBtnThousand->get_visible() )
269                 mxBtnThousand->set_active(bThousand);
270             else if ( mxBtnEngineering->get_visible() )
271                 mxBtnEngineering->set_active(bThousand);
272             mxBtnNegRed->set_active(bNegRed);
273             if ( mxLbCategory->get_active() == 0 )
274                 mxEdDecimals->set_text(u""_ustr); // tdf#44399
275             else if ( mxEdDecimals->get_visible() )
276                 mxEdDecimals->set_value(nPrecision);
277             else if ( mxEdDenominator->get_visible() )
278                 mxEdDenominator->set_value(nPrecision);
279             mxEdLeadZeroes->set_value(nLeadZeroes);
280         }
281         break;
282     default:
283         break;
284     }
285 }
286 
DisableControls()287 void NumberFormatPropertyPanel::DisableControls()
288 {
289     mxBtnEngineering->hide();
290     mxBtnThousand->show();
291     mxBtnThousand->set_sensitive(false);
292     mxBtnNegRed->set_sensitive(false);
293     mxFtDenominator->hide();
294     mxEdDenominator->hide();
295     mxFtDecimals->show();
296     mxEdDecimals->show();
297     mxFtDecimals->set_sensitive(false);
298     mxEdDecimals->set_sensitive(false);
299     mxFtLeadZeroes->set_sensitive(false);
300     mxEdLeadZeroes->set_sensitive(false);
301 }
302 
303 } // end of namespace ::sc::sidebar
304 
305 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
306