/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; namespace { /// Helper for sorting properties struct ScSolverOptionsEntry { sal_Int32 nPosition; OUString aDescription; ScSolverOptionsEntry() : nPosition(0) {} bool operator< (const ScSolverOptionsEntry& rOther) const { return (ScGlobal::GetCollator().compareString( aDescription, rOther.aDescription ) < 0); } }; } ScSolverOptionsDialog::ScSolverOptionsDialog(weld::Window* pParent, const uno::Sequence& rImplNames, const uno::Sequence& rDescriptions, OUString aEngine, const uno::Sequence& rProperties ) : GenericDialogController(pParent, "modules/scalc/ui/solveroptionsdialog.ui", "SolverOptionsDialog") , maImplNames(rImplNames) , maEngine(std::move(aEngine)) , maProperties(rProperties) , m_xLbEngine(m_xBuilder->weld_combo_box("engine")) , m_xLbSettings(m_xBuilder->weld_tree_view("settings")) , m_xBtnEdit(m_xBuilder->weld_button("edit")) { m_xLbSettings->set_size_request(m_xLbSettings->get_approximate_digit_width() * 32, m_xLbSettings->get_height_rows(12)); m_xLbSettings->enable_toggle_buttons(weld::ColumnToggleType::Check); m_xLbEngine->connect_changed( LINK( this, ScSolverOptionsDialog, EngineSelectHdl ) ); m_xBtnEdit->connect_clicked( LINK( this, ScSolverOptionsDialog, ButtonHdl ) ); m_xLbSettings->connect_changed( LINK( this, ScSolverOptionsDialog, SettingsSelHdl ) ); m_xLbSettings->connect_row_activated( LINK( this, ScSolverOptionsDialog, SettingsDoubleClickHdl ) ); sal_Int32 nSelect = -1; sal_Int32 nImplCount = maImplNames.getLength(); for (sal_Int32 nImpl=0; nImplappend_text(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.clear(); maProperties.realloc(0); // don't use options from different engine } if ( nSelect >= 0 ) // select in list box m_xLbEngine->set_active(nSelect); if ( !maProperties.hasElements() ) ReadFromComponent(); // fill maProperties from component (using maEngine) FillListBox(); // using maProperties } ScSolverOptionsDialog::~ScSolverOptionsDialog() { if (m_xIntDialog) m_xIntDialog->response(RET_CANCEL); assert(!m_xIntDialog); if (m_xValDialog) m_xValDialog->response(RET_CANCEL); assert(!m_xValDialog); } const uno::Sequence& ScSolverOptionsDialog::GetProperties() { // update maProperties from list box content // order of entries in list box and maProperties is the same sal_Int32 nEntryCount = maProperties.getLength(); if (nEntryCount == m_xLbSettings->n_children()) { auto maPropertiesRange = asNonConstRange(maProperties); for (sal_Int32 nEntryPos=0; nEntryPos(m_xLbSettings->get_id(nEntryPos))) { if (pStringItem->IsDouble()) rValue <<= pStringItem->GetDoubleValue(); else rValue <<= pStringItem->GetIntValue(); } else rValue <<= m_xLbSettings->get_toggle(nEntryPos) == TRISTATE_TRUE; } } else { OSL_FAIL( "wrong count" ); } return maProperties; } void ScSolverOptionsDialog::FillListBox() { // get property descriptions, sort by them uno::Reference xDesc( ScSolverUtil::GetSolver( maEngine ), uno::UNO_QUERY ); sal_Int32 nCount = maProperties.getLength(); std::vector aDescriptions( nCount ); for (sal_Int32 nPos=0; nPosgetPropertyDescription( aPropName ); if ( aVisName.isEmpty() ) 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 aNewSeq; aNewSeq.realloc( nCount ); std::transform(aDescriptions.begin(), aDescriptions.end(), aNewSeq.getArray(), [this](const ScSolverOptionsEntry& rDescr) -> beans::PropertyValue { return maProperties[ rDescr.nPosition ]; }); maProperties = aNewSeq; // fill the list box m_xLbSettings->freeze(); m_xLbSettings->clear(); for (sal_Int32 nPos=0; nPosappend(); if ( eClass == uno::TypeClass_BOOLEAN ) { // check box entry m_xLbSettings->set_toggle(nPos, ScUnoHelpFunctions::GetBoolFromAny(aValue) ? TRISTATE_TRUE : TRISTATE_FALSE); m_xLbSettings->set_text(nPos, aVisName, 0); } else { // value entry m_xLbSettings->set_text(nPos, aVisName, 0); m_aOptions.emplace_back(new ScSolverOptionsString(aVisName)); if (eClass == uno::TypeClass_DOUBLE) { double fDoubleValue = 0.0; if (aValue >>= fDoubleValue) m_aOptions.back()->SetDoubleValue(fDoubleValue); OUString sTxt = aVisName + ": " + rtl::math::doubleToUString(fDoubleValue, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, ScGlobal::getLocaleData().getNumDecimalSep()[0], true ); m_xLbSettings->set_text(nPos, sTxt, 0); } else { sal_Int32 nIntValue = 0; if (aValue >>= nIntValue) m_aOptions.back()->SetIntValue(nIntValue); OUString sTxt = aVisName + ": " + OUString::number(nIntValue); m_xLbSettings->set_text(nPos, sTxt, 0); } m_xLbSettings->set_id(nPos, weld::toId(m_aOptions.back().get())); } } m_xLbSettings->thaw(); } void ScSolverOptionsDialog::ReadFromComponent() { maProperties = ScSolverUtil::GetDefaults( maEngine ); } void ScSolverOptionsDialog::EditOption() { int nEntry = m_xLbSettings->get_selected_index(); if (nEntry == -1) return; ScSolverOptionsString* pStringItem = weld::fromId(m_xLbSettings->get_id(nEntry)); if (!pStringItem) return; if (pStringItem->IsDouble()) { m_xValDialog = std::make_shared(m_xDialog.get()); m_xValDialog->SetOptionName(pStringItem->GetText()); if (maProperties[nEntry].Name == "DECR") m_xValDialog->SetMax(1.0); else if (maProperties[nEntry].Name == "DEFactorMax") m_xValDialog->SetMax(1.2); else if (maProperties[nEntry].Name == "DEFactorMin") m_xValDialog->SetMax(1.2); else if (maProperties[nEntry].Name == "PSCL") m_xValDialog->SetMax(0.005); m_xValDialog->SetValue(pStringItem->GetDoubleValue()); weld::DialogController::runAsync(m_xValDialog, [nEntry, pStringItem, this](sal_Int32 nResult){ if (nResult == RET_OK) { pStringItem->SetDoubleValue(m_xValDialog->GetValue()); OUString sTxt(pStringItem->GetText() + ": " + rtl::math::doubleToUString(pStringItem->GetDoubleValue(), rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, ScGlobal::getLocaleData().getNumDecimalSep()[0], true )); m_xLbSettings->set_text(nEntry, sTxt, 0); } m_xValDialog.reset(); }); } else { m_xIntDialog = std::make_shared(m_xDialog.get()); m_xIntDialog->SetOptionName( pStringItem->GetText() ); if (maProperties[nEntry].Name == "EpsilonLevel") m_xIntDialog->SetMax(3); else if (maProperties[nEntry].Name == "Algorithm") m_xIntDialog->SetMax(1); m_xIntDialog->SetValue( pStringItem->GetIntValue() ); weld::DialogController::runAsync(m_xIntDialog, [nEntry, pStringItem, this](sal_Int32 nResult){ if (nResult == RET_OK) { pStringItem->SetIntValue(m_xIntDialog->GetValue()); OUString sTxt( pStringItem->GetText() + ": " + OUString::number(pStringItem->GetIntValue())); m_xLbSettings->set_text(nEntry, sTxt, 0); } m_xIntDialog.reset(); }); } } IMPL_LINK( ScSolverOptionsDialog, ButtonHdl, weld::Button&, rBtn, void ) { if (&rBtn == m_xBtnEdit.get()) EditOption(); } IMPL_LINK_NOARG(ScSolverOptionsDialog, SettingsDoubleClickHdl, weld::TreeView&, bool) { EditOption(); return true; } IMPL_LINK_NOARG(ScSolverOptionsDialog, EngineSelectHdl, weld::ComboBox&, void) { const sal_Int32 nSelectPos = m_xLbEngine->get_active(); if ( nSelectPos < maImplNames.getLength() ) { OUString aNewEngine( maImplNames[nSelectPos] ); if ( aNewEngine != maEngine ) { maEngine = aNewEngine; ReadFromComponent(); // fill maProperties from component (using maEngine) FillListBox(); // using maProperties } } } IMPL_LINK_NOARG(ScSolverOptionsDialog, SettingsSelHdl, weld::TreeView&, void) { bool bCheckbox = false; int nEntry = m_xLbSettings->get_selected_index(); if (nEntry != -1) { ScSolverOptionsString* pStringItem = weld::fromId(m_xLbSettings->get_id(nEntry)); if (!pStringItem) bCheckbox = true; } m_xBtnEdit->set_sensitive(!bCheckbox); } ScSolverIntegerDialog::ScSolverIntegerDialog(weld::Window * pParent) : GenericDialogController(pParent, "modules/scalc/ui/integerdialog.ui", "IntegerDialog") , m_xFrame(m_xBuilder->weld_frame("frame")) , m_xNfValue(m_xBuilder->weld_spin_button("value")) { } ScSolverIntegerDialog::~ScSolverIntegerDialog() { } void ScSolverIntegerDialog::SetOptionName( const OUString& rName ) { m_xFrame->set_label(rName); } void ScSolverIntegerDialog::SetValue( sal_Int32 nValue ) { m_xNfValue->set_value( nValue ); } void ScSolverIntegerDialog::SetMax( sal_Int32 nMax ) { m_xNfValue->set_range(0, nMax); } sal_Int32 ScSolverIntegerDialog::GetValue() const { return m_xNfValue->get_value(); } ScSolverValueDialog::ScSolverValueDialog(weld::Window* pParent) : GenericDialogController(pParent, "modules/scalc/ui/doubledialog.ui", "DoubleDialog") , m_xFrame(m_xBuilder->weld_frame("frame")) , m_xEdValue(m_xBuilder->weld_entry("value")) , m_fMaxValue(std::numeric_limits::quiet_NaN()) { } ScSolverValueDialog::~ScSolverValueDialog() { } void ScSolverValueDialog::SetOptionName( const OUString& rName ) { m_xFrame->set_label(rName); } void ScSolverValueDialog::SetValue( double fValue ) { m_xEdValue->set_text( rtl::math::doubleToUString( fValue, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, ScGlobal::getLocaleData().getNumDecimalSep()[0], true ) ); } void ScSolverValueDialog::SetMax(double fMax) { m_fMaxValue = fMax; } double ScSolverValueDialog::GetValue() const { OUString aInput = m_xEdValue->get_text(); rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok; sal_Int32 nParseEnd = 0; double fValue = ScGlobal::getLocaleData().stringToDouble( aInput, true, &eStatus, &nParseEnd); /* TODO: shouldn't there be some error checking? */ if (!std::isnan(m_fMaxValue) && fValue > m_fMaxValue) fValue = m_fMaxValue; return fValue; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */