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 "solveroptions.hxx"
21 #include "scresid.hxx"
23 #include "miscuno.hxx"
24 #include "solverutil.hxx"
26 #include <rtl/math.hxx>
27 #include <vcl/msgbox.hxx>
28 #include <unotools/collatorwrapper.hxx>
29 #include <unotools/localedatawrapper.hxx>
30 #include <svtools/treelistentry.hxx>
31 #include <o3tl/make_unique.hxx>
35 #include <com/sun/star/sheet/Solver.hpp>
36 #include <com/sun/star/sheet/XSolverDescription.hpp>
37 #include <com/sun/star/beans/PropertyValue.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
40 using namespace com::sun::star
;
42 /// Helper for sorting properties
43 struct ScSolverOptionsEntry
46 OUString aDescription
;
48 ScSolverOptionsEntry() : nPosition(0) {}
50 bool operator< (const ScSolverOptionsEntry
& rOther
) const
52 return (ScGlobal::GetCollator()->compareString( aDescription
, rOther
.aDescription
) < 0);
56 class ScSolverOptionsString
: public SvLBoxString
63 explicit ScSolverOptionsString(const OUString
& rStr
)
71 bool IsDouble() const { return mbIsDouble
; }
72 double GetDoubleValue() const { return mfDoubleValue
; }
73 sal_Int32
GetIntValue() const { return mnIntValue
; }
75 void SetDoubleValue( double fNew
) { mbIsDouble
= true; mfDoubleValue
= fNew
; }
76 void SetIntValue( sal_Int32 nNew
) { mbIsDouble
= false; mnIntValue
= nNew
; }
78 virtual void Paint(const Point
& rPos
, SvTreeListBox
& rDev
, vcl::RenderContext
& rRenderContext
,
79 const SvViewDataEntry
* pView
, const SvTreeListEntry
& rEntry
) override
;
82 void ScSolverOptionsString::Paint(const Point
& rPos
, SvTreeListBox
& /*rDev*/, vcl::RenderContext
& rRenderContext
,
83 const SvViewDataEntry
* /*pView*/, const SvTreeListEntry
& /*rEntry*/)
85 //! move position? (SvxLinguTabPage: aPos.X() += 20)
86 OUString
aNormalStr(GetText());
88 rRenderContext
.DrawText(rPos
, aNormalStr
);
91 aNewPos
.X() += rRenderContext
.GetTextWidth(aNormalStr
);
92 vcl::Font
aOldFont(rRenderContext
.GetFont());
93 vcl::Font
aFont(aOldFont
);
94 aFont
.SetWeight(WEIGHT_BOLD
);
98 sTxt
+= rtl::math::doubleToUString(mfDoubleValue
,
99 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
100 ScGlobal::GetpLocaleData()->getNumDecimalSep()[0], true );
102 sTxt
+= OUString::number(mnIntValue
);
103 rRenderContext
.SetFont(aFont
);
104 rRenderContext
.DrawText(aNewPos
, sTxt
);
106 rRenderContext
.SetFont(aOldFont
);
109 ScSolverOptionsDialog::ScSolverOptionsDialog( vcl::Window
* pParent
,
110 const uno::Sequence
<OUString
>& rImplNames
,
111 const uno::Sequence
<OUString
>& rDescriptions
,
112 const OUString
& rEngine
,
113 const uno::Sequence
<beans::PropertyValue
>& rProperties
)
114 : ModalDialog(pParent
, "SolverOptionsDialog",
115 "modules/scalc/ui/solveroptionsdialog.ui")
116 , mpCheckButtonData(nullptr)
117 , maImplNames(rImplNames
)
118 , maDescriptions(rDescriptions
)
120 , maProperties(rProperties
)
122 get(m_pLbEngine
, "engine");
123 get(m_pLbSettings
, "settings");
124 get(m_pBtnEdit
, "edit");
126 m_pLbEngine
->SetSelectHdl( LINK( this, ScSolverOptionsDialog
, EngineSelectHdl
) );
128 m_pBtnEdit
->SetClickHdl( LINK( this, ScSolverOptionsDialog
, ButtonHdl
) );
130 m_pLbSettings
->SetStyle( m_pLbSettings
->GetStyle()|WB_CLIPCHILDREN
|WB_FORCE_MAKEVISIBLE
);
131 m_pLbSettings
->SetHighlightRange();
133 m_pLbSettings
->SetSelectHdl( LINK( this, ScSolverOptionsDialog
, SettingsSelHdl
) );
134 m_pLbSettings
->SetDoubleClickHdl( LINK( this, ScSolverOptionsDialog
, SettingsDoubleClickHdl
) );
136 sal_Int32 nSelect
= -1;
137 sal_Int32 nImplCount
= maImplNames
.getLength();
138 for (sal_Int32 nImpl
=0; nImpl
<nImplCount
; ++nImpl
)
140 OUString
aImplName( maImplNames
[nImpl
] );
141 OUString
aDescription( maDescriptions
[nImpl
] ); // user-visible descriptions in list box
142 m_pLbEngine
->InsertEntry( aDescription
);
143 if ( aImplName
== maEngine
)
146 if ( nSelect
< 0 ) // no (valid) engine given
148 if ( nImplCount
> 0 )
150 maEngine
= maImplNames
[0]; // use first implementation
155 maProperties
.realloc(0); // don't use options from different engine
157 if ( nSelect
>= 0 ) // select in list box
158 m_pLbEngine
->SelectEntryPos( static_cast<sal_uInt16
>(nSelect
) );
160 if ( !maProperties
.getLength() )
161 ReadFromComponent(); // fill maProperties from component (using maEngine)
162 FillListBox(); // using maProperties
165 ScSolverOptionsDialog::~ScSolverOptionsDialog()
170 void ScSolverOptionsDialog::dispose()
172 delete mpCheckButtonData
;
174 m_pLbSettings
.clear();
176 ModalDialog::dispose();
179 const uno::Sequence
<beans::PropertyValue
>& ScSolverOptionsDialog::GetProperties()
181 // update maProperties from list box content
182 // order of entries in list box and maProperties is the same
183 sal_Int32 nEntryCount
= maProperties
.getLength();
184 SvTreeList
* pModel
= m_pLbSettings
->GetModel();
185 if ( nEntryCount
== (sal_Int32
)pModel
->GetEntryCount() )
187 for (sal_Int32 nEntryPos
=0; nEntryPos
<nEntryCount
; ++nEntryPos
)
189 uno::Any
& rValue
= maProperties
[nEntryPos
].Value
;
190 SvTreeListEntry
* pEntry
= pModel
->GetEntry(nEntryPos
);
192 bool bHasData
= false;
193 sal_uInt16 nItemCount
= pEntry
->ItemCount();
194 for (sal_uInt16 nItemPos
=0; nItemPos
<nItemCount
&& !bHasData
; ++nItemPos
)
196 SvLBoxItem
& rItem
= pEntry
->GetItem( nItemPos
);
197 ScSolverOptionsString
* pStringItem
= dynamic_cast<ScSolverOptionsString
*>(&rItem
);
200 if ( pStringItem
->IsDouble() )
201 rValue
<<= pStringItem
->GetDoubleValue();
203 rValue
<<= pStringItem
->GetIntValue();
208 rValue
<<= ( m_pLbSettings
->GetCheckButtonState( pEntry
) == SvButtonState::Checked
);
213 OSL_FAIL( "wrong count" );
219 void ScSolverOptionsDialog::FillListBox()
221 // get property descriptions, sort by them
223 uno::Reference
<sheet::XSolverDescription
> xDesc( ScSolverUtil::GetSolver( maEngine
), uno::UNO_QUERY
);
224 sal_Int32 nCount
= maProperties
.getLength();
225 std::vector
<ScSolverOptionsEntry
> aDescriptions( nCount
);
226 for (sal_Int32 nPos
=0; nPos
<nCount
; nPos
++)
228 OUString
aPropName( maProperties
[nPos
].Name
);
231 aVisName
= xDesc
->getPropertyDescription( aPropName
);
232 if ( aVisName
.isEmpty() )
233 aVisName
= aPropName
;
234 aDescriptions
[nPos
].nPosition
= nPos
;
235 aDescriptions
[nPos
].aDescription
= aVisName
;
237 std::sort( aDescriptions
.begin(), aDescriptions
.end() );
239 // also update maProperties to the order of descriptions
241 uno::Sequence
<beans::PropertyValue
> aNewSeq
;
242 aNewSeq
.realloc( nCount
);
243 for (sal_Int32 nPos
=0; nPos
<nCount
; nPos
++)
244 aNewSeq
[nPos
] = maProperties
[ aDescriptions
[nPos
].nPosition
];
245 maProperties
= aNewSeq
;
249 m_pLbSettings
->SetUpdateMode(false);
250 m_pLbSettings
->Clear();
252 if (!mpCheckButtonData
)
253 mpCheckButtonData
= new SvLBoxButtonData(m_pLbSettings
);
255 SvTreeList
* pModel
= m_pLbSettings
->GetModel();
256 SvTreeListEntry
* pEntry
= nullptr;
258 for (sal_Int32 nPos
=0; nPos
<nCount
; nPos
++)
260 OUString aVisName
= aDescriptions
[nPos
].aDescription
;
262 uno::Any aValue
= maProperties
[nPos
].Value
;
263 uno::TypeClass eClass
= aValue
.getValueTypeClass();
264 if ( eClass
== uno::TypeClass_BOOLEAN
)
267 pEntry
= new SvTreeListEntry
;
268 std::unique_ptr
<SvLBoxButton
> pButton(new SvLBoxButton(
269 SvLBoxButtonKind::EnabledCheckbox
, mpCheckButtonData
));
270 if ( ScUnoHelpFunctions::GetBoolFromAny( aValue
) )
271 pButton
->SetStateChecked();
273 pButton
->SetStateUnchecked();
274 pEntry
->AddItem(std::move(pButton
));
275 pEntry
->AddItem(o3tl::make_unique
<SvLBoxContextBmp
>(Image(), Image(), false));
276 pEntry
->AddItem(o3tl::make_unique
<SvLBoxString
>(aVisName
));
281 pEntry
= new SvTreeListEntry
;
282 pEntry
->AddItem(o3tl::make_unique
<SvLBoxString
>("")); // empty column
283 pEntry
->AddItem(o3tl::make_unique
<SvLBoxContextBmp
>(Image(), Image(), false));
284 std::unique_ptr
<ScSolverOptionsString
> pItem(
285 new ScSolverOptionsString(aVisName
));
286 if ( eClass
== uno::TypeClass_DOUBLE
)
288 double fDoubleValue
= 0.0;
289 if ( aValue
>>= fDoubleValue
)
290 pItem
->SetDoubleValue( fDoubleValue
);
294 sal_Int32 nIntValue
= 0;
295 if ( aValue
>>= nIntValue
)
296 pItem
->SetIntValue( nIntValue
);
298 pEntry
->AddItem(std::move(pItem
));
300 pModel
->Insert( pEntry
);
303 m_pLbSettings
->SetUpdateMode(true);
306 void ScSolverOptionsDialog::ReadFromComponent()
308 maProperties
= ScSolverUtil::GetDefaults( maEngine
);
311 void ScSolverOptionsDialog::EditOption()
313 SvTreeListEntry
* pEntry
= m_pLbSettings
->GetCurEntry();
316 sal_uInt16 nItemCount
= pEntry
->ItemCount();
317 for (sal_uInt16 nPos
=0; nPos
<nItemCount
; ++nPos
)
319 SvLBoxItem
& rItem
= pEntry
->GetItem( nPos
);
320 ScSolverOptionsString
* pStringItem
= dynamic_cast<ScSolverOptionsString
*>(&rItem
);
323 if ( pStringItem
->IsDouble() )
325 ScopedVclPtrInstance
< ScSolverValueDialog
> aValDialog( this );
326 aValDialog
->SetOptionName( pStringItem
->GetText() );
327 aValDialog
->SetValue( pStringItem
->GetDoubleValue() );
328 if ( aValDialog
->Execute() == RET_OK
)
330 pStringItem
->SetDoubleValue( aValDialog
->GetValue() );
331 m_pLbSettings
->InvalidateEntry( pEntry
);
336 ScopedVclPtrInstance
< ScSolverIntegerDialog
> aIntDialog( this );
337 aIntDialog
->SetOptionName( pStringItem
->GetText() );
338 aIntDialog
->SetValue( pStringItem
->GetIntValue() );
339 if ( aIntDialog
->Execute() == RET_OK
)
341 pStringItem
->SetIntValue( aIntDialog
->GetValue() );
342 m_pLbSettings
->InvalidateEntry( pEntry
);
350 IMPL_LINK_TYPED( ScSolverOptionsDialog
, ButtonHdl
, Button
*, pBtn
, void )
352 if (pBtn
== m_pBtnEdit
)
356 IMPL_LINK_NOARG_TYPED(ScSolverOptionsDialog
, SettingsDoubleClickHdl
, SvTreeListBox
*, bool)
362 IMPL_LINK_NOARG_TYPED(ScSolverOptionsDialog
, EngineSelectHdl
, ListBox
&, void)
364 const sal_Int32 nSelectPos
= m_pLbEngine
->GetSelectEntryPos();
365 if ( nSelectPos
< maImplNames
.getLength() )
367 OUString
aNewEngine( maImplNames
[nSelectPos
] );
368 if ( aNewEngine
!= maEngine
)
370 maEngine
= aNewEngine
;
371 ReadFromComponent(); // fill maProperties from component (using maEngine)
372 FillListBox(); // using maProperties
377 IMPL_LINK_NOARG_TYPED(ScSolverOptionsDialog
, SettingsSelHdl
, SvTreeListBox
*, void)
379 bool bCheckbox
= false;
381 SvTreeListEntry
* pEntry
= m_pLbSettings
->GetCurEntry();
384 SvLBoxItem
* pItem
= pEntry
->GetFirstItem(SV_ITEM_ID_LBOXBUTTON
);
385 if (pItem
&& pItem
->GetType() == SV_ITEM_ID_LBOXBUTTON
)
389 m_pBtnEdit
->Enable( !bCheckbox
);
392 ScSolverIntegerDialog::ScSolverIntegerDialog(vcl::Window
* pParent
)
393 : ModalDialog( pParent
, "IntegerDialog",
394 "modules/scalc/ui/integerdialog.ui" )
396 get(m_pFrame
, "frame");
397 get(m_pNfValue
, "value");
400 ScSolverIntegerDialog::~ScSolverIntegerDialog()
405 void ScSolverIntegerDialog::dispose()
409 ModalDialog::dispose();
412 void ScSolverIntegerDialog::SetOptionName( const OUString
& rName
)
414 m_pFrame
->set_label(rName
);
417 void ScSolverIntegerDialog::SetValue( sal_Int32 nValue
)
419 m_pNfValue
->SetValue( nValue
);
422 sal_Int32
ScSolverIntegerDialog::GetValue() const
424 sal_Int64 nValue
= m_pNfValue
->GetValue();
425 if ( nValue
< SAL_MIN_INT32
)
426 return SAL_MIN_INT32
;
427 if ( nValue
> SAL_MAX_INT32
)
428 return SAL_MAX_INT32
;
429 return (sal_Int32
) nValue
;
432 ScSolverValueDialog::ScSolverValueDialog( vcl::Window
* pParent
)
433 : ModalDialog( pParent
, "DoubleDialog",
434 "modules/scalc/ui/doubledialog.ui" )
436 get(m_pFrame
, "frame");
437 get(m_pEdValue
, "value");
440 ScSolverValueDialog::~ScSolverValueDialog()
445 void ScSolverValueDialog::dispose()
449 ModalDialog::dispose();
452 void ScSolverValueDialog::SetOptionName( const OUString
& rName
)
454 m_pFrame
->set_label(rName
);
457 void ScSolverValueDialog::SetValue( double fValue
)
459 m_pEdValue
->SetText( rtl::math::doubleToUString( fValue
,
460 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
461 ScGlobal::GetpLocaleData()->getNumDecimalSep()[0], true ) );
464 double ScSolverValueDialog::GetValue() const
466 OUString aInput
= m_pEdValue
->GetText();
468 const LocaleDataWrapper
* pLocaleData
= ScGlobal::GetpLocaleData();
469 rtl_math_ConversionStatus eStatus
= rtl_math_ConversionStatus_Ok
;
470 double fValue
= rtl::math::stringToDouble( aInput
,
471 pLocaleData
->getNumDecimalSep()[0],
472 pLocaleData
->getNumThousandSep()[0],
477 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */