blob: c4aab79d26c08d8f143aca03054b15ffd9b02d21 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
//------------------------------------------------------------------
#include "solveroptions.hxx"
#include "solveroptions.hrc"
#include "scresid.hxx"
#include "global.hxx"
#include "miscuno.hxx"
#include "solverutil.hxx"
#include <rtl/math.hxx>
#include <vcl/msgbox.hxx>
#include <unotools/collatorwrapper.hxx>
#include <unotools/localedatawrapper.hxx>
#include <algorithm>
#include <com/sun/star/sheet/Solver.hpp>
#include <com/sun/star/sheet/XSolverDescription.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
using namespace com::sun::star;
//==================================================================
/// Helper for sorting properties
struct ScSolverOptionsEntry
{
sal_Int32 nPosition;
rtl::OUString aDescription;
ScSolverOptionsEntry() : nPosition(0) {}
bool operator< (const ScSolverOptionsEntry& rOther) const
{
return ( ScGlobal::GetCollator()->compareString( aDescription, rOther.aDescription ) == COMPARE_LESS );
}
};
//------------------------------------------------------------------
class ScSolverOptionsString : public SvLBoxString
{
bool mbIsDouble;
double mfDoubleValue;
sal_Int32 mnIntValue;
public:
ScSolverOptionsString( SvLBoxEntry* pEntry, sal_uInt16 nFlags, const String& rStr ) :
SvLBoxString( pEntry, nFlags, rStr ),
mbIsDouble( false ),
mfDoubleValue( 0.0 ),
mnIntValue( 0 ) {}
bool IsDouble() const { return mbIsDouble; }
double GetDoubleValue() const { return mfDoubleValue; }
sal_Int32 GetIntValue() const { return mnIntValue; }
void SetDoubleValue( double fNew ) { mbIsDouble = true; mfDoubleValue = fNew; }
void SetIntValue( sal_Int32 nNew ) { mbIsDouble = false; mnIntValue = nNew; }
// MT: Commented out SV_ITEM_ID_EXTENDRLBOXSTRING and GetExtendText() in svlbitem.hxx - needed?
// virtual USHORT IsA() {return SV_ITEM_ID_EXTENDRLBOXSTRING;}
// virtual XubString GetExtendText() const;
virtual void Paint( const Point& rPos, SvLBox& rDev, sal_uInt16 nFlags, SvLBoxEntry* pEntry );
};
// MT: Commented out SV_ITEM_ID_EXTENDRLBOXSTRING and GetExtendText() in svlbitem.hxx - needed?
/*
XubString ScSolverOptionsString::GetExtendText() const
{
String aNormalStr( GetText() );
aNormalStr.Append( (sal_Unicode) ':' );
String sTxt( ' ' );
if ( mbIsDouble )
sTxt += (String)rtl::math::doubleToUString( mfDoubleValue,
rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
ScGlobal::GetpLocaleData()->getNumDecimalSep().GetChar(0), true );
else
sTxt += String::CreateFromInt32( mnIntValue );
aNormalStr.Append(sTxt);
return aNormalStr;
}
*/
void ScSolverOptionsString::Paint( const Point& rPos, SvLBox& rDev, sal_uInt16, SvLBoxEntry* /* pEntry */ )
{
//! move position? (SvxLinguTabPage: aPos.X() += 20)
String aNormalStr( GetText() );
aNormalStr.Append( (sal_Unicode) ':' );
rDev.DrawText( rPos, aNormalStr );
Point aNewPos( rPos );
aNewPos.X() += rDev.GetTextWidth( aNormalStr );
Font aOldFont( rDev.GetFont() );
Font aFont( aOldFont );
aFont.SetWeight( WEIGHT_BOLD );
String sTxt( ' ' );
if ( mbIsDouble )
sTxt += (String)rtl::math::doubleToUString( mfDoubleValue,
rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
ScGlobal::GetpLocaleData()->getNumDecimalSep().GetChar(0), true );
else
sTxt += String::CreateFromInt32( mnIntValue );
rDev.SetFont( aFont );
rDev.DrawText( aNewPos, sTxt );
rDev.SetFont( aOldFont );
}
//------------------------------------------------------------------
ScSolverOptionsDialog::ScSolverOptionsDialog( Window* pParent,
const uno::Sequence<rtl::OUString>& rImplNames,
const uno::Sequence<rtl::OUString>& rDescriptions,
const String& rEngine,
const uno::Sequence<beans::PropertyValue>& rProperties )
: ModalDialog( pParent, ScResId( RID_SCDLG_SOLVEROPTIONS ) ),
maFtEngine ( this, ScResId( FT_ENGINE ) ),
maLbEngine ( this, ScResId( LB_ENGINE ) ),
maFtSettings ( this, ScResId( FT_SETTINGS ) ),
maLbSettings ( this, ScResId( LB_SETTINGS ) ),
maBtnEdit ( this, ScResId( BTN_EDIT ) ),
maFlButtons ( this, ScResId( FL_BUTTONS ) ),
maBtnHelp ( this, ScResId( BTN_HELP ) ),
maBtnOk ( this, ScResId( BTN_OK ) ),
maBtnCancel ( this, ScResId( BTN_CANCEL ) ),
mpCheckButtonData( NULL ),
maImplNames( rImplNames ),
maDescriptions( rDescriptions ),
maEngine( rEngine ),
maProperties( rProperties )
{
maLbEngine.SetSelectHdl( LINK( this, ScSolverOptionsDialog, EngineSelectHdl ) );
maBtnEdit.SetClickHdl( LINK( this, ScSolverOptionsDialog, ButtonHdl ) );
maLbSettings.SetStyle( maLbSettings.GetStyle()|WB_CLIPCHILDREN|WB_FORCE_MAKEVISIBLE );
maLbSettings.SetHelpId( HID_SC_SOLVEROPTIONS_LB );
maLbSettings.SetHighlightRange();
maLbSettings.SetSelectHdl( LINK( this, ScSolverOptionsDialog, SettingsSelHdl ) );
maLbSettings.SetDoubleClickHdl( LINK( this, ScSolverOptionsDialog, SettingsDoubleClickHdl ) );
sal_Int32 nSelect = -1;
sal_Int32 nImplCount = maImplNames.getLength();
for (sal_Int32 nImpl=0; nImpl<nImplCount; ++nImpl)
{
String aImplName( maImplNames[nImpl] );
String aDescription( maDescriptions[nImpl] ); // user-visible descriptions in list box
maLbEngine.InsertEntry( aDescription );
if ( aImplName == maEngine )
nSelect = nImpl;
}
if ( nSelect < 0 ) // no (valid) engine given
{
if ( nImplCount > 0 )
{
maEngine = maImplNames[0]; // use first implementation
nSelect = 0;
}
else
maEngine.Erase();
maProperties.realloc(0); // don't use options from different engine
}
if ( nSelect >= 0 ) // select in list box
maLbEngine.SelectEntryPos( static_cast<sal_uInt16>(nSelect) );
if ( !maProperties.getLength() )
ReadFromComponent(); // fill maProperties from component (using maEngine)
FillListBox(); // using maProperties
FreeResource();
}
ScSolverOptionsDialog::~ScSolverOptionsDialog()
{
delete mpCheckButtonData;
}
const String& ScSolverOptionsDialog::GetEngine() const
{
return maEngine; // already updated in selection handler
}
const uno::Sequence<beans::PropertyValue>& ScSolverOptionsDialog::GetProperties()
{
// update maProperties from list box content
// order of entries in list box and maProperties is the same
sal_Int32 nEntryCount = maProperties.getLength();
SvLBoxTreeList* pModel = maLbSettings.GetModel();
if ( nEntryCount == (sal_Int32)pModel->GetEntryCount() )
{
for (sal_Int32 nEntryPos=0; nEntryPos<nEntryCount; ++nEntryPos)
{
uno::Any& rValue = maProperties[nEntryPos].Value;
SvLBoxEntry* pEntry = pModel->GetEntry(nEntryPos);
bool bHasData = false;
sal_uInt16 nItemCount = pEntry->ItemCount();
for (sal_uInt16 nItemPos=0; nItemPos<nItemCount && !bHasData; ++nItemPos)
{
SvLBoxItem* pItem = pEntry->GetItem( nItemPos );
ScSolverOptionsString* pStringItem = dynamic_cast<ScSolverOptionsString*>(pItem);
if ( pStringItem )
{
if ( pStringItem->IsDouble() )
rValue <<= pStringItem->GetDoubleValue();
else
rValue <<= pStringItem->GetIntValue();
bHasData = true;
}
}
if ( !bHasData )
ScUnoHelpFunctions::SetBoolInAny( rValue,
maLbSettings.GetCheckButtonState( pEntry ) == SV_BUTTON_CHECKED );
}
}
else
{
DBG_ERRORFILE( "wrong count" );
}
return maProperties;
}
void ScSolverOptionsDialog::FillListBox()
{
// get property descriptions, sort by them
uno::Reference<sheet::XSolverDescription> xDesc( ScSolverUtil::GetSolver( maEngine ), uno::UNO_QUERY );
sal_Int32 nCount = maProperties.getLength();
std::vector<ScSolverOptionsEntry> aDescriptions( nCount );
for (sal_Int32 nPos=0; nPos<nCount; nPos++)
{
rtl::OUString aPropName( maProperties[nPos].Name );
rtl::OUString aVisName;
if ( xDesc.is() )
aVisName = xDesc->getPropertyDescription( aPropName );
if ( !aVisName.getLength() )
aVisName = aPropName;
aDescriptions[nPos].nPosition = nPos;
aDescriptions[nPos].aDescription = aVisName;
}
std::sort( aDescriptions.begin(), aDescriptions.end() );
// also update maProperties to the order of descriptions
uno::Sequence<beans::PropertyValue> aNewSeq;
aNewSeq.realloc( nCount );
for (sal_Int32 nPos=0; nPos<nCount; nPos++)
aNewSeq[nPos] = maProperties[ aDescriptions[nPos].nPosition ];
maProperties = aNewSeq;
// fill the list box
maLbSettings.SetUpdateMode(sal_False);
maLbSettings.Clear();
String sEmpty;
if (!mpCheckButtonData)
mpCheckButtonData = new SvLBoxButtonData( &maLbSettings );
SvLBoxTreeList* pModel = maLbSettings.GetModel();
SvLBoxEntry* pEntry = NULL;
for (sal_Int32 nPos=0; nPos<nCount; nPos++)
{
rtl::OUString aVisName = aDescriptions[nPos].aDescription;
uno::Any aValue = maProperties[nPos].Value;
uno::TypeClass eClass = aValue.getValueTypeClass();
if ( eClass == uno::TypeClass_BOOLEAN )
{
// check box entry
pEntry = new SvLBoxEntry;
SvLBoxButton* pButton = new SvLBoxButton( pEntry, SvLBoxButtonKind_enabledCheckbox, 0, mpCheckButtonData );
if ( ScUnoHelpFunctions::GetBoolFromAny( aValue ) )
pButton->SetStateChecked();
else
pButton->SetStateUnchecked();
pEntry->AddItem( pButton );
pEntry->AddItem( new SvLBoxContextBmp( pEntry, 0, Image(), Image(), 0 ) );
pEntry->AddItem( new SvLBoxString( pEntry, 0, aVisName ) );
}
else
{
// value entry
pEntry = new SvLBoxEntry;
pEntry->AddItem( new SvLBoxString( pEntry, 0, sEmpty ) ); // empty column
pEntry->AddItem( new SvLBoxContextBmp( pEntry, 0, Image(), Image(), 0 ) );
ScSolverOptionsString* pItem = new ScSolverOptionsString( pEntry, 0, aVisName );
if ( eClass == uno::TypeClass_DOUBLE )
{
double fDoubleValue = 0.0;
if ( aValue >>= fDoubleValue )
pItem->SetDoubleValue( fDoubleValue );
}
else
{
sal_Int32 nIntValue = 0;
if ( aValue >>= nIntValue )
pItem->SetIntValue( nIntValue );
}
pEntry->AddItem( pItem );
}
pModel->Insert( pEntry );
}
maLbSettings.SetUpdateMode(sal_True);
}
void ScSolverOptionsDialog::ReadFromComponent()
{
maProperties = ScSolverUtil::GetDefaults( maEngine );
}
void ScSolverOptionsDialog::EditOption()
{
SvLBoxEntry* pEntry = maLbSettings.GetCurEntry();
if (pEntry)
{
sal_uInt16 nItemCount = pEntry->ItemCount();
for (sal_uInt16 nPos=0; nPos<nItemCount; ++nPos)
{
SvLBoxItem* pItem = pEntry->GetItem( nPos );
ScSolverOptionsString* pStringItem = dynamic_cast<ScSolverOptionsString*>(pItem);
if ( pStringItem )
{
if ( pStringItem->IsDouble() )
{
ScSolverValueDialog aValDialog( this );
aValDialog.SetOptionName( pStringItem->GetText() );
aValDialog.SetValue( pStringItem->GetDoubleValue() );
if ( aValDialog.Execute() == RET_OK )
{
pStringItem->SetDoubleValue( aValDialog.GetValue() );
maLbSettings.InvalidateEntry( pEntry );
}
}
else
{
ScSolverIntegerDialog aIntDialog( this );
aIntDialog.SetOptionName( pStringItem->GetText() );
aIntDialog.SetValue( pStringItem->GetIntValue() );
if ( aIntDialog.Execute() == RET_OK )
{
pStringItem->SetIntValue( aIntDialog.GetValue() );
maLbSettings.InvalidateEntry( pEntry );
}
}
}
}
}
}
IMPL_LINK( ScSolverOptionsDialog, ButtonHdl, PushButton*, pBtn )
{
if ( pBtn == &maBtnEdit )
EditOption();
return 0;
}
IMPL_LINK( ScSolverOptionsDialog, SettingsDoubleClickHdl, SvTreeListBox*, EMPTYARG )
{
EditOption();
return 0;
}
IMPL_LINK( ScSolverOptionsDialog, EngineSelectHdl, ListBox*, EMPTYARG )
{
sal_uInt16 nSelectPos = maLbEngine.GetSelectEntryPos();
if ( nSelectPos < maImplNames.getLength() )
{
String aNewEngine( maImplNames[nSelectPos] );
if ( aNewEngine != maEngine )
{
maEngine = aNewEngine;
ReadFromComponent(); // fill maProperties from component (using maEngine)
FillListBox(); // using maProperties
}
}
return 0;
}
IMPL_LINK( ScSolverOptionsDialog, SettingsSelHdl, SvxCheckListBox*, EMPTYARG )
{
sal_Bool bCheckbox = sal_False;
SvLBoxEntry* pEntry = maLbSettings.GetCurEntry();
if (pEntry)
{
SvLBoxItem* pItem = pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON);
if ( pItem && pItem->IsA() == SV_ITEM_ID_LBOXBUTTON )
bCheckbox = sal_True;
}
maBtnEdit.Enable( !bCheckbox );
return 0;
}
//------------------------------------------------------------------
ScSolverIntegerDialog::ScSolverIntegerDialog( Window * pParent )
: ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_INTEGER ) ),
maFtName ( this, ScResId( FT_OPTIONNAME ) ),
maNfValue ( this, ScResId( NF_VALUE ) ),
maFlButtons ( this, ScResId( FL_BUTTONS ) ),
maBtnOk ( this, ScResId( BTN_OK ) ),
maBtnCancel ( this, ScResId( BTN_CANCEL ) )
{
FreeResource();
}
ScSolverIntegerDialog::~ScSolverIntegerDialog()
{
}
void ScSolverIntegerDialog::SetOptionName( const String& rName )
{
maFtName.SetText( rName );
}
void ScSolverIntegerDialog::SetValue( sal_Int32 nValue )
{
maNfValue.SetValue( nValue );
}
sal_Int32 ScSolverIntegerDialog::GetValue() const
{
sal_Int64 nValue = maNfValue.GetValue();
if ( nValue < SAL_MIN_INT32 )
return SAL_MIN_INT32;
if ( nValue > SAL_MAX_INT32 )
return SAL_MAX_INT32;
return (sal_Int32) nValue;
}
//------------------------------------------------------------------
ScSolverValueDialog::ScSolverValueDialog( Window * pParent )
: ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_DOUBLE ) ),
maFtName ( this, ScResId( FT_OPTIONNAME ) ),
maEdValue ( this, ScResId( ED_VALUE ) ),
maFlButtons ( this, ScResId( FL_BUTTONS ) ),
maBtnOk ( this, ScResId( BTN_OK ) ),
maBtnCancel ( this, ScResId( BTN_CANCEL ) )
{
FreeResource();
}
ScSolverValueDialog::~ScSolverValueDialog()
{
}
void ScSolverValueDialog::SetOptionName( const String& rName )
{
maFtName.SetText( rName );
}
void ScSolverValueDialog::SetValue( double fValue )
{
maEdValue.SetText( rtl::math::doubleToUString( fValue,
rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
ScGlobal::GetpLocaleData()->getNumDecimalSep().GetChar(0), true ) );
}
double ScSolverValueDialog::GetValue() const
{
String aInput = maEdValue.GetText();
const LocaleDataWrapper* pLocaleData = ScGlobal::GetpLocaleData();
rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
double fValue = rtl::math::stringToDouble( aInput,
pLocaleData->getNumDecimalSep().GetChar(0),
pLocaleData->getNumThousandSep().GetChar(0),
&eStatus, NULL );
return fValue;
}