Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / ui / miscdlgs / solveroptions.cxx
blobbbe675ba623ee350957839d2e06fd0ba7eabd8b2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
22 #include "global.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>
33 #include <algorithm>
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
45 sal_Int32 nPosition;
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
58 bool mbIsDouble;
59 double mfDoubleValue;
60 sal_Int32 mnIntValue;
62 public:
63 explicit ScSolverOptionsString(const OUString& rStr)
64 : SvLBoxString(rStr)
65 , mbIsDouble(false)
66 , mfDoubleValue(0.0)
67 , mnIntValue(0)
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());
87 aNormalStr += ":";
88 rRenderContext.DrawText(rPos, aNormalStr);
90 Point aNewPos(rPos);
91 aNewPos.X() += rRenderContext.GetTextWidth(aNormalStr);
92 vcl::Font aOldFont(rRenderContext.GetFont());
93 vcl::Font aFont(aOldFont);
94 aFont.SetWeight(WEIGHT_BOLD);
96 OUString sTxt(' ');
97 if (mbIsDouble)
98 sTxt += rtl::math::doubleToUString(mfDoubleValue,
99 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
100 ScGlobal::GetpLocaleData()->getNumDecimalSep()[0], true );
101 else
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)
119 , maEngine(rEngine)
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 )
144 nSelect = nImpl;
146 if ( nSelect < 0 ) // no (valid) engine given
148 if ( nImplCount > 0 )
150 maEngine = maImplNames[0]; // use first implementation
151 nSelect = 0;
153 else
154 maEngine.clear();
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()
167 disposeOnce();
170 void ScSolverOptionsDialog::dispose()
172 delete mpCheckButtonData;
173 m_pLbEngine.clear();
174 m_pLbSettings.clear();
175 m_pBtnEdit.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);
198 if ( pStringItem )
200 if ( pStringItem->IsDouble() )
201 rValue <<= pStringItem->GetDoubleValue();
202 else
203 rValue <<= pStringItem->GetIntValue();
204 bHasData = true;
207 if ( !bHasData )
208 rValue <<= ( m_pLbSettings->GetCheckButtonState( pEntry ) == SvButtonState::Checked );
211 else
213 OSL_FAIL( "wrong count" );
216 return maProperties;
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 );
229 OUString aVisName;
230 if ( xDesc.is() )
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;
247 // fill the list box
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 )
266 // check box entry
267 pEntry = new SvTreeListEntry;
268 std::unique_ptr<SvLBoxButton> pButton(new SvLBoxButton(
269 SvLBoxButtonKind::EnabledCheckbox, mpCheckButtonData));
270 if ( ScUnoHelpFunctions::GetBoolFromAny( aValue ) )
271 pButton->SetStateChecked();
272 else
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));
278 else
280 // value entry
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 );
292 else
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();
314 if (pEntry)
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);
321 if ( pStringItem )
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 );
334 else
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)
353 EditOption();
356 IMPL_LINK_NOARG_TYPED(ScSolverOptionsDialog, SettingsDoubleClickHdl, SvTreeListBox*, bool)
358 EditOption();
359 return false;
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();
382 if (pEntry)
384 SvLBoxItem* pItem = pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON);
385 if (pItem && pItem->GetType() == SV_ITEM_ID_LBOXBUTTON)
386 bCheckbox = true;
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()
402 disposeOnce();
405 void ScSolverIntegerDialog::dispose()
407 m_pFrame.clear();
408 m_pNfValue.clear();
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()
442 disposeOnce();
445 void ScSolverValueDialog::dispose()
447 m_pFrame.clear();
448 m_pEdValue.clear();
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],
473 &eStatus );
474 return fValue;
477 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */