1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27 //------------------------------------------------------------------
28
29 #include "solveroptions.hxx"
30 #include "solveroptions.hrc"
31 #include "scresid.hxx"
32 #include "global.hxx"
33 #include "miscuno.hxx"
34 #include "solverutil.hxx"
35
36 #include <rtl/math.hxx>
37 #include <vcl/msgbox.hxx>
38 #include <unotools/collatorwrapper.hxx>
39 #include <unotools/localedatawrapper.hxx>
40
41 #include <algorithm>
42
43 #include <com/sun/star/sheet/Solver.hpp>
44 #include <com/sun/star/sheet/XSolverDescription.hpp>
45 #include <com/sun/star/beans/PropertyValue.hpp>
46 #include <com/sun/star/beans/XPropertySet.hpp>
47
48 using namespace com::sun::star;
49
50 //==================================================================
51
52 /// Helper for sorting properties
53 struct ScSolverOptionsEntry
54 {
55 sal_Int32 nPosition;
56 rtl::OUString aDescription;
57
ScSolverOptionsEntryScSolverOptionsEntry58 ScSolverOptionsEntry() : nPosition(0) {}
59
operator <ScSolverOptionsEntry60 bool operator< (const ScSolverOptionsEntry& rOther) const
61 {
62 return ( ScGlobal::GetCollator()->compareString( aDescription, rOther.aDescription ) == COMPARE_LESS );
63 }
64 };
65
66 //------------------------------------------------------------------
67
68 class ScSolverOptionsString : public SvLBoxString
69 {
70 bool mbIsDouble;
71 double mfDoubleValue;
72 sal_Int32 mnIntValue;
73
74 public:
ScSolverOptionsString(SvLBoxEntry * pEntry,sal_uInt16 nFlags,const String & rStr)75 ScSolverOptionsString( SvLBoxEntry* pEntry, sal_uInt16 nFlags, const String& rStr ) :
76 SvLBoxString( pEntry, nFlags, rStr ),
77 mbIsDouble( false ),
78 mfDoubleValue( 0.0 ),
79 mnIntValue( 0 ) {}
80
IsDouble() const81 bool IsDouble() const { return mbIsDouble; }
GetDoubleValue() const82 double GetDoubleValue() const { return mfDoubleValue; }
GetIntValue() const83 sal_Int32 GetIntValue() const { return mnIntValue; }
84
SetDoubleValue(double fNew)85 void SetDoubleValue( double fNew ) { mbIsDouble = true; mfDoubleValue = fNew; }
SetIntValue(sal_Int32 nNew)86 void SetIntValue( sal_Int32 nNew ) { mbIsDouble = false; mnIntValue = nNew; }
87 // MT: Commented out SV_ITEM_ID_EXTENDRLBOXSTRING and GetExtendText() in svlbitem.hxx - needed?
88 // virtual USHORT IsA() {return SV_ITEM_ID_EXTENDRLBOXSTRING;}
89 // virtual XubString GetExtendText() const;
90 virtual void Paint( const Point& rPos, SvLBox& rDev, sal_uInt16 nFlags, SvLBoxEntry* pEntry );
91 };
92
93 // MT: Commented out SV_ITEM_ID_EXTENDRLBOXSTRING and GetExtendText() in svlbitem.hxx - needed?
94 /*
95 XubString ScSolverOptionsString::GetExtendText() const
96 {
97 String aNormalStr( GetText() );
98 aNormalStr.Append( (sal_Unicode) ':' );
99 String sTxt( ' ' );
100 if ( mbIsDouble )
101 sTxt += (String)rtl::math::doubleToUString( mfDoubleValue,
102 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
103 ScGlobal::GetpLocaleData()->getNumDecimalSep().GetChar(0), true );
104 else
105 sTxt += String::CreateFromInt32( mnIntValue );
106 aNormalStr.Append(sTxt);
107 return aNormalStr;
108 }
109 */
110
Paint(const Point & rPos,SvLBox & rDev,sal_uInt16,SvLBoxEntry *)111 void ScSolverOptionsString::Paint( const Point& rPos, SvLBox& rDev, sal_uInt16, SvLBoxEntry* /* pEntry */ )
112 {
113 //! move position? (SvxLinguTabPage: aPos.X() += 20)
114 String aNormalStr( GetText() );
115 aNormalStr.Append( (sal_Unicode) ':' );
116 rDev.DrawText( rPos, aNormalStr );
117
118 Point aNewPos( rPos );
119 aNewPos.X() += rDev.GetTextWidth( aNormalStr );
120 Font aOldFont( rDev.GetFont() );
121 Font aFont( aOldFont );
122 aFont.SetWeight( WEIGHT_BOLD );
123
124 String sTxt( ' ' );
125 if ( mbIsDouble )
126 sTxt += (String)rtl::math::doubleToUString( mfDoubleValue,
127 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
128 ScGlobal::GetpLocaleData()->getNumDecimalSep().GetChar(0), true );
129 else
130 sTxt += String::CreateFromInt32( mnIntValue );
131 rDev.SetFont( aFont );
132 rDev.DrawText( aNewPos, sTxt );
133
134 rDev.SetFont( aOldFont );
135 }
136
137 //------------------------------------------------------------------
138
ScSolverOptionsDialog(Window * pParent,const uno::Sequence<rtl::OUString> & rImplNames,const uno::Sequence<rtl::OUString> & rDescriptions,const String & rEngine,const uno::Sequence<beans::PropertyValue> & rProperties)139 ScSolverOptionsDialog::ScSolverOptionsDialog( Window* pParent,
140 const uno::Sequence<rtl::OUString>& rImplNames,
141 const uno::Sequence<rtl::OUString>& rDescriptions,
142 const String& rEngine,
143 const uno::Sequence<beans::PropertyValue>& rProperties )
144 : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVEROPTIONS ) ),
145 maFtEngine ( this, ScResId( FT_ENGINE ) ),
146 maLbEngine ( this, ScResId( LB_ENGINE ) ),
147 maFtSettings ( this, ScResId( FT_SETTINGS ) ),
148 maLbSettings ( this, ScResId( LB_SETTINGS ) ),
149 maBtnEdit ( this, ScResId( BTN_EDIT ) ),
150 maFlButtons ( this, ScResId( FL_BUTTONS ) ),
151 maBtnHelp ( this, ScResId( BTN_HELP ) ),
152 maBtnOk ( this, ScResId( BTN_OK ) ),
153 maBtnCancel ( this, ScResId( BTN_CANCEL ) ),
154 mpCheckButtonData( NULL ),
155 maImplNames( rImplNames ),
156 maDescriptions( rDescriptions ),
157 maEngine( rEngine ),
158 maProperties( rProperties )
159 {
160 maLbEngine.SetSelectHdl( LINK( this, ScSolverOptionsDialog, EngineSelectHdl ) );
161
162 maBtnEdit.SetClickHdl( LINK( this, ScSolverOptionsDialog, ButtonHdl ) );
163
164 maLbSettings.SetStyle( maLbSettings.GetStyle()|WB_CLIPCHILDREN|WB_FORCE_MAKEVISIBLE );
165 maLbSettings.SetHelpId( HID_SC_SOLVEROPTIONS_LB );
166 maLbSettings.SetHighlightRange();
167
168 maLbSettings.SetSelectHdl( LINK( this, ScSolverOptionsDialog, SettingsSelHdl ) );
169 maLbSettings.SetDoubleClickHdl( LINK( this, ScSolverOptionsDialog, SettingsDoubleClickHdl ) );
170
171 sal_Int32 nSelect = -1;
172 sal_Int32 nImplCount = maImplNames.getLength();
173 for (sal_Int32 nImpl=0; nImpl<nImplCount; ++nImpl)
174 {
175 String aImplName( maImplNames[nImpl] );
176 String aDescription( maDescriptions[nImpl] ); // user-visible descriptions in list box
177 maLbEngine.InsertEntry( aDescription );
178 if ( aImplName == maEngine )
179 nSelect = nImpl;
180 }
181 if ( nSelect < 0 ) // no (valid) engine given
182 {
183 if ( nImplCount > 0 )
184 {
185 maEngine = maImplNames[0]; // use first implementation
186 nSelect = 0;
187 }
188 else
189 maEngine.Erase();
190 maProperties.realloc(0); // don't use options from different engine
191 }
192 if ( nSelect >= 0 ) // select in list box
193 maLbEngine.SelectEntryPos( static_cast<sal_uInt16>(nSelect) );
194
195 if ( !maProperties.getLength() )
196 ReadFromComponent(); // fill maProperties from component (using maEngine)
197 FillListBox(); // using maProperties
198
199 FreeResource();
200 }
201
~ScSolverOptionsDialog()202 ScSolverOptionsDialog::~ScSolverOptionsDialog()
203 {
204 delete mpCheckButtonData;
205 }
206
GetEngine() const207 const String& ScSolverOptionsDialog::GetEngine() const
208 {
209 return maEngine; // already updated in selection handler
210 }
211
GetProperties()212 const uno::Sequence<beans::PropertyValue>& ScSolverOptionsDialog::GetProperties()
213 {
214 // update maProperties from list box content
215 // order of entries in list box and maProperties is the same
216 sal_Int32 nEntryCount = maProperties.getLength();
217 SvLBoxTreeList* pModel = maLbSettings.GetModel();
218 if ( nEntryCount == (sal_Int32)pModel->GetEntryCount() )
219 {
220 for (sal_Int32 nEntryPos=0; nEntryPos<nEntryCount; ++nEntryPos)
221 {
222 uno::Any& rValue = maProperties[nEntryPos].Value;
223 SvLBoxEntry* pEntry = pModel->GetEntry(nEntryPos);
224
225 bool bHasData = false;
226 sal_uInt16 nItemCount = pEntry->ItemCount();
227 for (sal_uInt16 nItemPos=0; nItemPos<nItemCount && !bHasData; ++nItemPos)
228 {
229 SvLBoxItem* pItem = pEntry->GetItem( nItemPos );
230 ScSolverOptionsString* pStringItem = dynamic_cast<ScSolverOptionsString*>(pItem);
231 if ( pStringItem )
232 {
233 if ( pStringItem->IsDouble() )
234 rValue <<= pStringItem->GetDoubleValue();
235 else
236 rValue <<= pStringItem->GetIntValue();
237 bHasData = true;
238 }
239 }
240 if ( !bHasData )
241 ScUnoHelpFunctions::SetBoolInAny( rValue,
242 maLbSettings.GetCheckButtonState( pEntry ) == SV_BUTTON_CHECKED );
243 }
244 }
245 else
246 {
247 DBG_ERRORFILE( "wrong count" );
248 }
249
250 return maProperties;
251 }
252
FillListBox()253 void ScSolverOptionsDialog::FillListBox()
254 {
255 // get property descriptions, sort by them
256
257 uno::Reference<sheet::XSolverDescription> xDesc( ScSolverUtil::GetSolver( maEngine ), uno::UNO_QUERY );
258 sal_Int32 nCount = maProperties.getLength();
259 std::vector<ScSolverOptionsEntry> aDescriptions( nCount );
260 for (sal_Int32 nPos=0; nPos<nCount; nPos++)
261 {
262 rtl::OUString aPropName( maProperties[nPos].Name );
263 rtl::OUString aVisName;
264 if ( xDesc.is() )
265 aVisName = xDesc->getPropertyDescription( aPropName );
266 if ( !aVisName.getLength() )
267 aVisName = aPropName;
268 aDescriptions[nPos].nPosition = nPos;
269 aDescriptions[nPos].aDescription = aVisName;
270 }
271 std::sort( aDescriptions.begin(), aDescriptions.end() );
272
273 // also update maProperties to the order of descriptions
274
275 uno::Sequence<beans::PropertyValue> aNewSeq;
276 aNewSeq.realloc( nCount );
277 for (sal_Int32 nPos=0; nPos<nCount; nPos++)
278 aNewSeq[nPos] = maProperties[ aDescriptions[nPos].nPosition ];
279 maProperties = aNewSeq;
280
281 // fill the list box
282
283 maLbSettings.SetUpdateMode(sal_False);
284 maLbSettings.Clear();
285
286 String sEmpty;
287 if (!mpCheckButtonData)
288 mpCheckButtonData = new SvLBoxButtonData( &maLbSettings );
289
290 SvLBoxTreeList* pModel = maLbSettings.GetModel();
291 SvLBoxEntry* pEntry = NULL;
292
293 for (sal_Int32 nPos=0; nPos<nCount; nPos++)
294 {
295 rtl::OUString aVisName = aDescriptions[nPos].aDescription;
296
297 uno::Any aValue = maProperties[nPos].Value;
298 uno::TypeClass eClass = aValue.getValueTypeClass();
299 if ( eClass == uno::TypeClass_BOOLEAN )
300 {
301 // check box entry
302 pEntry = new SvLBoxEntry;
303 SvLBoxButton* pButton = new SvLBoxButton( pEntry, SvLBoxButtonKind_enabledCheckbox, 0, mpCheckButtonData );
304 if ( ScUnoHelpFunctions::GetBoolFromAny( aValue ) )
305 pButton->SetStateChecked();
306 else
307 pButton->SetStateUnchecked();
308 pEntry->AddItem( pButton );
309 pEntry->AddItem( new SvLBoxContextBmp( pEntry, 0, Image(), Image(), 0 ) );
310 pEntry->AddItem( new SvLBoxString( pEntry, 0, aVisName ) );
311 }
312 else
313 {
314 // value entry
315 pEntry = new SvLBoxEntry;
316 pEntry->AddItem( new SvLBoxString( pEntry, 0, sEmpty ) ); // empty column
317 pEntry->AddItem( new SvLBoxContextBmp( pEntry, 0, Image(), Image(), 0 ) );
318 ScSolverOptionsString* pItem = new ScSolverOptionsString( pEntry, 0, aVisName );
319 if ( eClass == uno::TypeClass_DOUBLE )
320 {
321 double fDoubleValue = 0.0;
322 if ( aValue >>= fDoubleValue )
323 pItem->SetDoubleValue( fDoubleValue );
324 }
325 else
326 {
327 sal_Int32 nIntValue = 0;
328 if ( aValue >>= nIntValue )
329 pItem->SetIntValue( nIntValue );
330 }
331 pEntry->AddItem( pItem );
332 }
333 pModel->Insert( pEntry );
334 }
335
336 maLbSettings.SetUpdateMode(sal_True);
337 }
338
ReadFromComponent()339 void ScSolverOptionsDialog::ReadFromComponent()
340 {
341 maProperties = ScSolverUtil::GetDefaults( maEngine );
342 }
343
EditOption()344 void ScSolverOptionsDialog::EditOption()
345 {
346 SvLBoxEntry* pEntry = maLbSettings.GetCurEntry();
347 if (pEntry)
348 {
349 sal_uInt16 nItemCount = pEntry->ItemCount();
350 for (sal_uInt16 nPos=0; nPos<nItemCount; ++nPos)
351 {
352 SvLBoxItem* pItem = pEntry->GetItem( nPos );
353 ScSolverOptionsString* pStringItem = dynamic_cast<ScSolverOptionsString*>(pItem);
354 if ( pStringItem )
355 {
356 if ( pStringItem->IsDouble() )
357 {
358 ScSolverValueDialog aValDialog( this );
359 aValDialog.SetOptionName( pStringItem->GetText() );
360 aValDialog.SetValue( pStringItem->GetDoubleValue() );
361 if ( aValDialog.Execute() == RET_OK )
362 {
363 pStringItem->SetDoubleValue( aValDialog.GetValue() );
364 maLbSettings.InvalidateEntry( pEntry );
365 }
366 }
367 else
368 {
369 ScSolverIntegerDialog aIntDialog( this );
370 aIntDialog.SetOptionName( pStringItem->GetText() );
371 aIntDialog.SetValue( pStringItem->GetIntValue() );
372 if ( aIntDialog.Execute() == RET_OK )
373 {
374 pStringItem->SetIntValue( aIntDialog.GetValue() );
375 maLbSettings.InvalidateEntry( pEntry );
376 }
377 }
378 }
379 }
380 }
381 }
382
IMPL_LINK(ScSolverOptionsDialog,ButtonHdl,PushButton *,pBtn)383 IMPL_LINK( ScSolverOptionsDialog, ButtonHdl, PushButton*, pBtn )
384 {
385 if ( pBtn == &maBtnEdit )
386 EditOption();
387
388 return 0;
389 }
390
IMPL_LINK(ScSolverOptionsDialog,SettingsDoubleClickHdl,SvTreeListBox *,EMPTYARG)391 IMPL_LINK( ScSolverOptionsDialog, SettingsDoubleClickHdl, SvTreeListBox*, EMPTYARG )
392 {
393 EditOption();
394 return 0;
395 }
396
IMPL_LINK(ScSolverOptionsDialog,EngineSelectHdl,ListBox *,EMPTYARG)397 IMPL_LINK( ScSolverOptionsDialog, EngineSelectHdl, ListBox*, EMPTYARG )
398 {
399 sal_uInt16 nSelectPos = maLbEngine.GetSelectEntryPos();
400 if ( nSelectPos < maImplNames.getLength() )
401 {
402 String aNewEngine( maImplNames[nSelectPos] );
403 if ( aNewEngine != maEngine )
404 {
405 maEngine = aNewEngine;
406 ReadFromComponent(); // fill maProperties from component (using maEngine)
407 FillListBox(); // using maProperties
408 }
409 }
410 return 0;
411 }
412
IMPL_LINK(ScSolverOptionsDialog,SettingsSelHdl,SvxCheckListBox *,EMPTYARG)413 IMPL_LINK( ScSolverOptionsDialog, SettingsSelHdl, SvxCheckListBox*, EMPTYARG )
414 {
415 sal_Bool bCheckbox = sal_False;
416
417 SvLBoxEntry* pEntry = maLbSettings.GetCurEntry();
418 if (pEntry)
419 {
420 SvLBoxItem* pItem = pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON);
421 if ( pItem && pItem->IsA() == SV_ITEM_ID_LBOXBUTTON )
422 bCheckbox = sal_True;
423 }
424
425 maBtnEdit.Enable( !bCheckbox );
426
427 return 0;
428 }
429
430 //------------------------------------------------------------------
431
ScSolverIntegerDialog(Window * pParent)432 ScSolverIntegerDialog::ScSolverIntegerDialog( Window * pParent )
433 : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_INTEGER ) ),
434 maFtName ( this, ScResId( FT_OPTIONNAME ) ),
435 maNfValue ( this, ScResId( NF_VALUE ) ),
436 maFlButtons ( this, ScResId( FL_BUTTONS ) ),
437 maBtnOk ( this, ScResId( BTN_OK ) ),
438 maBtnCancel ( this, ScResId( BTN_CANCEL ) )
439 {
440 FreeResource();
441 }
442
~ScSolverIntegerDialog()443 ScSolverIntegerDialog::~ScSolverIntegerDialog()
444 {
445 }
446
SetOptionName(const String & rName)447 void ScSolverIntegerDialog::SetOptionName( const String& rName )
448 {
449 maFtName.SetText( rName );
450 }
451
SetValue(sal_Int32 nValue)452 void ScSolverIntegerDialog::SetValue( sal_Int32 nValue )
453 {
454 maNfValue.SetValue( nValue );
455 }
456
GetValue() const457 sal_Int32 ScSolverIntegerDialog::GetValue() const
458 {
459 sal_Int64 nValue = maNfValue.GetValue();
460 if ( nValue < SAL_MIN_INT32 )
461 return SAL_MIN_INT32;
462 if ( nValue > SAL_MAX_INT32 )
463 return SAL_MAX_INT32;
464 return (sal_Int32) nValue;
465 }
466
467 //------------------------------------------------------------------
468
ScSolverValueDialog(Window * pParent)469 ScSolverValueDialog::ScSolverValueDialog( Window * pParent )
470 : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_DOUBLE ) ),
471 maFtName ( this, ScResId( FT_OPTIONNAME ) ),
472 maEdValue ( this, ScResId( ED_VALUE ) ),
473 maFlButtons ( this, ScResId( FL_BUTTONS ) ),
474 maBtnOk ( this, ScResId( BTN_OK ) ),
475 maBtnCancel ( this, ScResId( BTN_CANCEL ) )
476 {
477 FreeResource();
478 }
479
~ScSolverValueDialog()480 ScSolverValueDialog::~ScSolverValueDialog()
481 {
482 }
483
SetOptionName(const String & rName)484 void ScSolverValueDialog::SetOptionName( const String& rName )
485 {
486 maFtName.SetText( rName );
487 }
488
SetValue(double fValue)489 void ScSolverValueDialog::SetValue( double fValue )
490 {
491 maEdValue.SetText( rtl::math::doubleToUString( fValue,
492 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
493 ScGlobal::GetpLocaleData()->getNumDecimalSep().GetChar(0), true ) );
494 }
495
GetValue() const496 double ScSolverValueDialog::GetValue() const
497 {
498 String aInput = maEdValue.GetText();
499
500 const LocaleDataWrapper* pLocaleData = ScGlobal::GetpLocaleData();
501 rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
502 double fValue = rtl::math::stringToDouble( aInput,
503 pLocaleData->getNumDecimalSep().GetChar(0),
504 pLocaleData->getNumThousandSep().GetChar(0),
505 &eStatus, NULL );
506 return fValue;
507 }
508
509