diff options
Diffstat (limited to 'sc/source/ui/condformat')
-rw-r--r-- | sc/source/ui/condformat/colorformat.cxx | 303 | ||||
-rw-r--r-- | sc/source/ui/condformat/condformatdlg.cxx | 709 | ||||
-rw-r--r-- | sc/source/ui/condformat/condformatdlgentry.cxx | 1530 | ||||
-rw-r--r-- | sc/source/ui/condformat/condformatdlgitem.cxx | 66 | ||||
-rw-r--r-- | sc/source/ui/condformat/condformathelper.cxx | 229 | ||||
-rw-r--r-- | sc/source/ui/condformat/condformatmgr.cxx | 180 |
6 files changed, 3017 insertions, 0 deletions
diff --git a/sc/source/ui/condformat/colorformat.cxx b/sc/source/ui/condformat/colorformat.cxx new file mode 100644 index 000000000..920fee3c0 --- /dev/null +++ b/sc/source/ui/condformat/colorformat.cxx @@ -0,0 +1,303 @@ +/* -*- 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/. + */ + +#include <colorformat.hxx> +#include <colorscale.hxx> + +#include <document.hxx> + +#include <svl/numformat.hxx> +#include <svx/colorbox.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +namespace { + +void SetType(const ScColorScaleEntry* pEntry, weld::ComboBox& rLstBox) +{ + rLstBox.set_active(pEntry->GetType()); +} + +void GetType(const weld::ComboBox& rLstBox, const weld::Entry& rEd, ScColorScaleEntry* pEntry, SvNumberFormatter* pNumberFormatter, + ScDocument* pDoc, const ScAddress& rPos ) +{ + double nVal = 0; + sal_uInt32 nIndex = 0; + pEntry->SetType(static_cast<ScColorScaleEntryType>(rLstBox.get_active())); + switch (rLstBox.get_active()) + { + case COLORSCALE_AUTO: + case COLORSCALE_MIN: + case COLORSCALE_MAX: + break; + case COLORSCALE_PERCENTILE: + case COLORSCALE_VALUE: + case COLORSCALE_PERCENT: + (void)pNumberFormatter->IsNumberFormat( rEd.get_text(), nIndex, nVal ); + pEntry->SetValue(nVal); + break; + case COLORSCALE_FORMULA: + pEntry->SetFormula(rEd.get_text(), *pDoc, rPos); + break; + } +} + +OUString convertNumberToString(double nVal, const ScDocument* pDoc) +{ + SvNumberFormatter* pNumberFormatter = pDoc->GetFormatTable(); + OUString aText; + pNumberFormatter->GetInputLineString(nVal, 0, aText); + return aText; +} + +void SetValue( const ScDocument* pDoc, const ScColorScaleEntry* pEntry, weld::Entry& rEdit) +{ + if(pEntry->GetType() == COLORSCALE_FORMULA) + rEdit.set_text(pEntry->GetFormula(formula::FormulaGrammar::GRAM_DEFAULT)); + else if(pEntry->GetType() != COLORSCALE_MIN && pEntry->GetType() != COLORSCALE_MAX) + rEdit.set_text(convertNumberToString(pEntry->GetValue(), pDoc)); + else + rEdit.set_sensitive(false); +} + +} + +ScDataBarSettingsDlg::ScDataBarSettingsDlg(weld::Window* pParent, const ScDataBarFormatData& rData, ScDocument* pDoc, const ScAddress& rPos) + : GenericDialogController(pParent, "modules/scalc/ui/databaroptions.ui", "DataBarOptions") + , mpNumberFormatter(pDoc->GetFormatTable()) + , mpDoc(pDoc) + , maPos(rPos) + , mxBtnOk(m_xBuilder->weld_button("ok")) + , mxBtnCancel(m_xBuilder->weld_button("cancel")) + , mxLbPos(new ColorListBox(m_xBuilder->weld_menu_button("positive_colour"), [this]{ return m_xDialog.get(); })) + , mxLbNeg(new ColorListBox(m_xBuilder->weld_menu_button("negative_colour"), [this]{ return m_xDialog.get(); })) + , mxLbAxisCol(new ColorListBox(m_xBuilder->weld_menu_button("axis_colour"), [this]{ return m_xDialog.get(); })) + , mxLbFillType(m_xBuilder->weld_combo_box("fill_type")) + , mxLbTypeMin(m_xBuilder->weld_combo_box("min")) + , mxLbTypeMax(m_xBuilder->weld_combo_box("max")) + , mxLbAxisPos(m_xBuilder->weld_combo_box("axis_pos")) + , mxEdMin(m_xBuilder->weld_entry("min_value")) + , mxEdMax(m_xBuilder->weld_entry("max_value")) + , mxLenMin(m_xBuilder->weld_entry("min_length")) + , mxLenMax(m_xBuilder->weld_entry("max_length")) + , mxCbOnlyBar(m_xBuilder->weld_check_button("only_bar")) + , mxStrSameValueFT(m_xBuilder->weld_label("str_same_value")) +{ + maStrWarnSameValue = mxStrSameValueFT->get_label(); + + Init(); + + mxLbPos->SelectEntry(rData.maPositiveColor); + mxLbFillType->set_active( rData.mbGradient ? 1 : 0 ); + if (rData.mxNegativeColor) + mxLbNeg->SelectEntry(*rData.mxNegativeColor); + + switch (rData.meAxisPosition) + { + case databar::NONE: + mxLbAxisPos->set_active(2); + break; + case databar::AUTOMATIC: + mxLbAxisPos->set_active(0); + break; + case databar::MIDDLE: + mxLbAxisPos->set_active(1); + break; + } + ::SetType(rData.mpLowerLimit.get(), *mxLbTypeMin); + ::SetType(rData.mpUpperLimit.get(), *mxLbTypeMax); + SetValue(mpDoc, rData.mpLowerLimit.get(), *mxEdMin); + SetValue(mpDoc, rData.mpUpperLimit.get(), *mxEdMax); + mxLenMin->set_text(convertNumberToString(rData.mnMinLength, mpDoc)); + mxLenMax->set_text(convertNumberToString(rData.mnMaxLength, mpDoc)); + mxLbAxisCol->SelectEntry(rData.maAxisColor); + mxCbOnlyBar->set_active(rData.mbOnlyBar); + + TypeSelectHdl(*mxLbTypeMin); + PosSelectHdl(*mxLbTypeMin); +} + +ScDataBarSettingsDlg::~ScDataBarSettingsDlg() +{ +} + +void ScDataBarSettingsDlg::Init() +{ + mxLbNeg->SelectEntry(COL_LIGHTRED); + mxLbAxisCol->SelectEntry(COL_BLACK); + mxLbPos->SelectEntry(0x2a6099); + mxBtnOk->connect_clicked( LINK( this, ScDataBarSettingsDlg, OkBtnHdl ) ); + + mxLbTypeMin->connect_changed( LINK( this, ScDataBarSettingsDlg, TypeSelectHdl ) ); + mxLbTypeMax->connect_changed( LINK( this, ScDataBarSettingsDlg, TypeSelectHdl ) ); + mxLbAxisPos->connect_changed( LINK( this, ScDataBarSettingsDlg, PosSelectHdl ) ); + +} + +namespace { + +void GetAxesPosition(ScDataBarFormatData* pData, const weld::ComboBox& rLbox) +{ + switch (rLbox.get_active()) + { + case 0: + pData->meAxisPosition = databar::AUTOMATIC; + break; + case 1: + pData->meAxisPosition = databar::MIDDLE; + break; + case 2: + pData->meAxisPosition = databar::NONE; + break; + } +} + +void SetBarLength(ScDataBarFormatData* pData, const OUString& minStr, const OUString& maxStr, SvNumberFormatter* mpNumberFormatter) +{ + double nMinValue = 0; + sal_uInt32 nIndex = 0; + (void)mpNumberFormatter->IsNumberFormat(minStr, nIndex, nMinValue); + nIndex = 0; + double nMaxValue = 0; + (void)mpNumberFormatter->IsNumberFormat(maxStr, nIndex, nMaxValue); + pData->mnMinLength = nMinValue; + pData->mnMaxLength = nMaxValue; +} + +} + +ScDataBarFormatData* ScDataBarSettingsDlg::GetData() +{ + ScDataBarFormatData* pData = new ScDataBarFormatData(); + pData->maPositiveColor = mxLbPos->GetSelectEntryColor(); + pData->mxNegativeColor = mxLbNeg->GetSelectEntryColor(); + pData->mbGradient = ( mxLbFillType->get_active() == 1 ); + pData->mpUpperLimit.reset(new ScColorScaleEntry()); + pData->mpLowerLimit.reset(new ScColorScaleEntry()); + pData->maAxisColor = mxLbAxisCol->GetSelectEntryColor(); + pData->mbOnlyBar = mxCbOnlyBar->get_active(); + + ::GetType(*mxLbTypeMin, *mxEdMin, pData->mpLowerLimit.get(), mpNumberFormatter, mpDoc, maPos); + ::GetType(*mxLbTypeMax, *mxEdMax, pData->mpUpperLimit.get(), mpNumberFormatter, mpDoc, maPos); + GetAxesPosition(pData, *mxLbAxisPos); + SetBarLength(pData, mxLenMin->get_text(), mxLenMax->get_text(), mpNumberFormatter); + + return pData; +} + +IMPL_LINK_NOARG(ScDataBarSettingsDlg, OkBtnHdl, weld::Button&, void) +{ + //check that min < max + bool bWarn = false; + int nSelectMin = mxLbTypeMin->get_active(); + if( nSelectMin == COLORSCALE_MAX ) + bWarn = true; + int nSelectMax = mxLbTypeMax->get_active(); + if( nSelectMax == COLORSCALE_MIN ) + bWarn = true; + if(!bWarn) // databar length checks + { + OUString aMinString = mxLenMin->get_text(); + OUString aMaxString = mxLenMax->get_text(); + double nMinValue = 0; + sal_uInt32 nIndex = 0; + (void)mpNumberFormatter->IsNumberFormat(aMinString, nIndex, nMinValue); + nIndex = 0; + double nMaxValue = 0; + (void)mpNumberFormatter->IsNumberFormat(aMaxString, nIndex, nMaxValue); + if(rtl::math::approxEqual(nMinValue, nMaxValue) || nMinValue > nMaxValue || nMaxValue > 100 || nMinValue < 0) + bWarn = true; + } + if (!bWarn && mxLbTypeMin->get_active() == mxLbTypeMax->get_active()) + { + + if(nSelectMax != COLORSCALE_FORMULA && nSelectMax != COLORSCALE_AUTO) + { + OUString aMinString = mxEdMin->get_text(); + OUString aMaxString = mxEdMax->get_text(); + double nMinValue = 0; + sal_uInt32 nIndex = 0; + (void)mpNumberFormatter->IsNumberFormat(aMinString, nIndex, nMinValue); + nIndex = 0; + double nMaxValue = 0; + (void)mpNumberFormatter->IsNumberFormat(aMaxString, nIndex, nMaxValue); + if(rtl::math::approxEqual(nMinValue, nMaxValue) || nMinValue > nMaxValue) + bWarn = true; + } + } + + if(bWarn) + { + //show warning message and don't close + std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, + maStrWarnSameValue)); + xWarn->run(); + } + else + { + m_xDialog->response(RET_OK); + } +} + +IMPL_LINK_NOARG(ScDataBarSettingsDlg, TypeSelectHdl, weld::ComboBox&, void) +{ + int nSelectMin = mxLbTypeMin->get_active(); + if( nSelectMin <= COLORSCALE_MAX) + mxEdMin->set_sensitive(false); + else + { + mxEdMin->set_sensitive(true); + if(mxEdMin->get_text().isEmpty()) + { + if(nSelectMin == COLORSCALE_PERCENTILE || nSelectMin == COLORSCALE_PERCENT) + mxEdMin->set_text(OUString::number(50)); + else + mxEdMin->set_text(OUString::number(0)); + } + } + + int nSelectMax = mxLbTypeMax->get_active(); + if (nSelectMax <= COLORSCALE_MAX) + mxEdMax->set_sensitive(false); + else + { + mxEdMax->set_sensitive(true); + if (mxEdMax->get_text().isEmpty()) + { + if(nSelectMax == COLORSCALE_PERCENTILE || nSelectMax == COLORSCALE_PERCENT) + mxEdMax->set_text(OUString::number(50)); + else + mxEdMax->set_text(OUString::number(0)); + } + } +} + +IMPL_LINK_NOARG(ScDataBarSettingsDlg, PosSelectHdl, weld::ComboBox&, void) +{ + int axisPos = mxLbAxisPos->get_active(); + if(axisPos != 2 && axisPos != 1) // disable if axis vertical position is automatic + { + mxLenMin->set_sensitive(false); + mxLenMax->set_sensitive(false); + } + else + { + mxLenMin->set_sensitive(true); + mxLenMax->set_sensitive(true); + if(mxLenMin->get_text().isEmpty()) + { + mxLenMin->set_text(OUString::number(0)); + mxLenMax->set_text(OUString::number(100)); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ + diff --git a/sc/source/ui/condformat/condformatdlg.cxx b/sc/source/ui/condformat/condformatdlg.cxx new file mode 100644 index 000000000..b4759bb39 --- /dev/null +++ b/sc/source/ui/condformat/condformatdlg.cxx @@ -0,0 +1,709 @@ +/* -*- 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/. + */ + +#include <condformatdlg.hxx> + +#include <sfx2/dispatch.hxx> +#include <vcl/svapp.hxx> + +#include <anyrefdg.hxx> +#include <document.hxx> +#include <conditio.hxx> +#include <tabvwsh.hxx> +#include <colorscale.hxx> +#include <reffact.hxx> +#include <docsh.hxx> +#include <docfunc.hxx> +#include <condformatdlgentry.hxx> +#include <condformatdlgitem.hxx> + +ScCondFormatList::ScCondFormatList(ScCondFormatDlg* pDialogParent, + std::unique_ptr<weld::ScrolledWindow> xWindow, + std::unique_ptr<weld::Container> xGrid) + : mxScrollWindow(std::move(xWindow)) + , mxGrid(std::move(xGrid)) + , mbFrozen(false) + , mbNewEntry(false) + , mpDoc(nullptr) + , mpDialogParent(pDialogParent) +{ + mxScrollWindow->set_size_request(mxScrollWindow->get_approximate_digit_width() * 85, + mxScrollWindow->get_text_height() * 23); + mxGrid->set_stack_background(); +} + +weld::Window* ScCondFormatList::GetFrameWeld() +{ + return mpDialogParent->getDialog(); +} + +ScCondFormatList::~ScCondFormatList() +{ + Freeze(); +} + +void ScCondFormatList::init(ScDocument& rDoc, + const ScConditionalFormat* pFormat, const ScRangeList& rRanges, + const ScAddress& rPos, condformat::dialog::ScCondFormatDialogType eType) +{ + mpDoc = &rDoc; + maPos = rPos; + maRanges = rRanges; + + Freeze(); + + if(pFormat) + { + size_t nCount = pFormat->size(); + for (size_t nIndex = 0; nIndex < nCount; ++nIndex) + { + const ScFormatEntry* pEntry = pFormat->GetEntry(nIndex); + switch(pEntry->GetType()) + { + case ScFormatEntry::Type::Condition: + case ScFormatEntry::Type::ExtCondition: + { + const ScCondFormatEntry* pConditionEntry = static_cast<const ScCondFormatEntry*>( pEntry ); + if(pConditionEntry->GetOperation() != ScConditionMode::Direct) + maEntries.emplace_back(new ScConditionFrmtEntry( this, mpDoc, mpDialogParent, maPos, pConditionEntry ) ); + else + maEntries.emplace_back(new ScFormulaFrmtEntry( this, mpDoc, mpDialogParent, maPos, pConditionEntry ) ); + + } + break; + case ScFormatEntry::Type::Colorscale: + { + const ScColorScaleFormat* pColorScale = static_cast<const ScColorScaleFormat*>( pEntry ); + if( pColorScale->size() == 2 ) + maEntries.emplace_back(new ScColorScale2FrmtEntry( this, mpDoc, maPos, pColorScale ) ); + else + maEntries.emplace_back(new ScColorScale3FrmtEntry( this, mpDoc, maPos, pColorScale ) ); + } + break; + case ScFormatEntry::Type::Databar: + maEntries.emplace_back(new ScDataBarFrmtEntry( this, mpDoc, maPos, static_cast<const ScDataBarFormat*>( pEntry ) ) ); + break; + case ScFormatEntry::Type::Iconset: + maEntries.emplace_back(new ScIconSetFrmtEntry( this, mpDoc, maPos, static_cast<const ScIconSetFormat*>( pEntry ) ) ); + break; + case ScFormatEntry::Type::Date: + maEntries.emplace_back(new ScDateFrmtEntry( this, mpDoc, static_cast<const ScCondDateFormatEntry*>( pEntry ) ) ); + break; + } + } + if(nCount) + EntrySelectHdl(*maEntries[0]); + } + else + { + switch(eType) + { + case condformat::dialog::CONDITION: + maEntries.emplace_back(new ScConditionFrmtEntry( this, mpDoc, mpDialogParent, maPos )); + break; + case condformat::dialog::COLORSCALE: + maEntries.emplace_back(new ScColorScale3FrmtEntry( this, mpDoc, maPos )); + break; + case condformat::dialog::DATABAR: + maEntries.emplace_back(new ScDataBarFrmtEntry( this, mpDoc, maPos )); + break; + case condformat::dialog::ICONSET: + maEntries.emplace_back(new ScIconSetFrmtEntry( this, mpDoc, maPos )); + break; + case condformat::dialog::DATE: + maEntries.emplace_back(new ScDateFrmtEntry( this, mpDoc )); + break; + case condformat::dialog::NONE: + break; + } + mbNewEntry = true; + } + Thaw(); + RecalcAll(); + if (!maEntries.empty()) + { + (*maEntries.begin())->SetActive(); + mpDialogParent->OnSelectionChange(0, maEntries.size()); + } + + RecalcAll(); +} + +void ScCondFormatList::SetRange(const ScRangeList& rRange) +{ + maRanges = rRange; +} + +std::unique_ptr<ScConditionalFormat> ScCondFormatList::GetConditionalFormat() const +{ + if(maEntries.empty()) + return nullptr; + + std::unique_ptr<ScConditionalFormat> pFormat(new ScConditionalFormat(0, mpDoc)); + pFormat->SetRange(maRanges); + + for(auto & rEntry: maEntries) + { + // tdf#119178: Sometimes initial apply-to range (the one this dialog + // was opened with) is different from the final apply-to range + // (as edited by the user) + + // If this format entry is new, take top-left corner of the final range + // and use it to create the initial entry (token array therein, if applicable) + if (mbNewEntry) + rEntry->SetPos(maRanges.GetTopLeftCorner()); + // else do nothing: setting new position when editing recompiles formulas + // in entries and nobody wants that + + ScFormatEntry* pEntry = rEntry->GetEntry(); + if(pEntry) + pFormat->AddEntry(pEntry); + } + + return pFormat; +} + +void ScCondFormatList::RecalcAll() +{ + if (mbFrozen) + return; + + int nWheelScroll = SAL_MAX_INT32; + + sal_Int32 nIndex = 1; + for (const auto& item : maEntries) + { + if (!item) + continue; + item->SetIndex(nIndex); + item->set_grid_top_attach(nIndex - 1); + nWheelScroll = std::min(nWheelScroll, item->get_preferred_height()); + ++nIndex; + } + + if (nWheelScroll != SAL_MAX_INT32) + { + // tdf#118482 set a scroll step of the height of a collapsed entry + mxScrollWindow->vadjustment_set_step_increment(nWheelScroll); + } +} + +IMPL_LINK(ScCondFormatList, ColFormatTypeHdl, weld::ComboBox&, rBox, void) +{ + Application::PostUserEvent(LINK(this, ScCondFormatList, AfterColFormatTypeHdl), &rBox); +} + +IMPL_LINK(ScCondFormatList, AfterColFormatTypeHdl, void*, p, void) +{ + weld::ComboBox* pBox = static_cast<weld::ComboBox*>(p); + EntryContainer::iterator itr = std::find_if(maEntries.begin(), maEntries.end(), + [](const std::unique_ptr<ScCondFrmtEntry>& widget) { return widget->IsSelected(); }); + if(itr == maEntries.end()) + return; + + sal_Int32 nPos = pBox->get_active(); + switch(nPos) + { + case 0: + if((*itr)->GetType() == condformat::entry::COLORSCALE2) + return; + + Freeze(); + itr->reset(new ScColorScale2FrmtEntry(this, mpDoc, maPos)); + break; + case 1: + if((*itr)->GetType() == condformat::entry::COLORSCALE3) + return; + + Freeze(); + itr->reset(new ScColorScale3FrmtEntry(this, mpDoc, maPos)); + break; + case 2: + if((*itr)->GetType() == condformat::entry::DATABAR) + return; + + Freeze(); + itr->reset(new ScDataBarFrmtEntry(this, mpDoc, maPos)); + break; + case 3: + if((*itr)->GetType() == condformat::entry::ICONSET) + return; + + Freeze(); + itr->reset(new ScIconSetFrmtEntry(this, mpDoc, maPos)); + break; + default: + break; + } + mpDialogParent->InvalidateRefData(); + (*itr)->SetActive(); + Thaw(); + RecalcAll(); +} + +IMPL_LINK(ScCondFormatList, TypeListHdl, weld::ComboBox&, rBox, void) +{ + //Resolves: fdo#79021 At this point we are still inside the ListBox Select. + //If we call maEntries.replace here then the pBox will be deleted before it + //has finished Select and will crash on accessing its deleted this. So Post + //to do the real work after the Select has completed + Application::PostUserEvent(LINK(this, ScCondFormatList, AfterTypeListHdl), &rBox); +} + +IMPL_LINK(ScCondFormatList, AfterTypeListHdl, void*, p, void) +{ + weld::ComboBox* pBox = static_cast<weld::ComboBox*>(p); + EntryContainer::iterator itr = std::find_if(maEntries.begin(), maEntries.end(), + [](const std::unique_ptr<ScCondFrmtEntry>& widget) { return widget->IsSelected(); }); + if(itr == maEntries.end()) + return; + + sal_Int32 nPos = pBox->get_active(); + switch(nPos) + { + case 0: + switch((*itr)->GetType()) + { + case condformat::entry::FORMULA: + case condformat::entry::CONDITION: + case condformat::entry::DATE: + break; + case condformat::entry::COLORSCALE2: + case condformat::entry::COLORSCALE3: + case condformat::entry::DATABAR: + case condformat::entry::ICONSET: + return; + } + Freeze(); + itr->reset(new ScColorScale3FrmtEntry(this, mpDoc, maPos)); + mpDialogParent->InvalidateRefData(); + (*itr)->SetActive(); + break; + case 1: + if((*itr)->GetType() == condformat::entry::CONDITION) + return; + + Freeze(); + itr->reset(new ScConditionFrmtEntry(this, mpDoc, mpDialogParent, maPos)); + mpDialogParent->InvalidateRefData(); + (*itr)->SetActive(); + break; + case 2: + if((*itr)->GetType() == condformat::entry::FORMULA) + return; + + Freeze(); + itr->reset(new ScFormulaFrmtEntry(this, mpDoc, mpDialogParent, maPos)); + mpDialogParent->InvalidateRefData(); + (*itr)->SetActive(); + break; + case 3: + if((*itr)->GetType() == condformat::entry::DATE) + return; + + Freeze(); + itr->reset(new ScDateFrmtEntry( this, mpDoc )); + mpDialogParent->InvalidateRefData(); + (*itr)->SetActive(); + break; + + } + Thaw(); + RecalcAll(); +} + +IMPL_LINK_NOARG( ScCondFormatList, AddBtnHdl, weld::Button&, void ) +{ + Freeze(); + maEntries.emplace_back(new ScConditionFrmtEntry(this, mpDoc, mpDialogParent, maPos)); + for(auto& rxEntry : maEntries) + { + rxEntry->SetInactive(); + } + mpDialogParent->InvalidateRefData(); + maEntries.back()->SetActive(); + mpDialogParent->OnSelectionChange(maEntries.size() - 1, maEntries.size()); + Thaw(); + RecalcAll(); +} + +IMPL_LINK_NOARG( ScCondFormatList, RemoveBtnHdl, weld::Button&, void ) +{ + Freeze(); + auto itr = std::find_if(maEntries.begin(), maEntries.end(), + [](const std::unique_ptr<ScCondFrmtEntry>& widget) { return widget->IsSelected(); }); + if (itr != maEntries.end()) + { + maEntries.erase(itr); + } + mpDialogParent->InvalidateRefData(); + mpDialogParent->OnSelectionChange(0, maEntries.size(), false); + Thaw(); + RecalcAll(); +} + +IMPL_LINK_NOARG(ScCondFormatList, UpBtnHdl, weld::Button&, void) +{ + Freeze(); + size_t index = 0; + for (size_t i = 0; i < maEntries.size(); i++) + { + auto& widget = maEntries[i]; + if (widget->IsSelected() && i > 0) + { + std::swap(maEntries[i], maEntries[i - 1]); + index = i - 1; + break; + } + } + mpDialogParent->InvalidateRefData(); + mpDialogParent->OnSelectionChange(index, maEntries.size()); + Thaw(); + RecalcAll(); +} + +IMPL_LINK_NOARG(ScCondFormatList, DownBtnHdl, weld::Button&, void) +{ + Freeze(); + size_t index = 0; + for (size_t i = 0; i < maEntries.size(); i++) + { + auto& widget = maEntries[i]; + if (widget->IsSelected()) + { + index = i; + if (i < maEntries.size()-1) + { + std::swap(maEntries[i], maEntries[i + 1]); + index = i + 1; + break; + } + } + } + mpDialogParent->InvalidateRefData(); + mpDialogParent->OnSelectionChange(index, maEntries.size()); + Thaw(); + RecalcAll(); +} + +IMPL_LINK( ScCondFormatList, EntrySelectHdl, ScCondFrmtEntry&, rEntry, void ) +{ + if(rEntry.IsSelected()) + return; + + Freeze(); + size_t index = 0; + for(size_t i = 0; i < maEntries.size(); i++) + { + if (maEntries[i].get() == &rEntry) + { + index = i; + } + maEntries[i]->SetInactive(); + } + mpDialogParent->InvalidateRefData(); + mpDialogParent->OnSelectionChange(index, maEntries.size()); + rEntry.SetActive(); + Thaw(); + RecalcAll(); +} + +ScCondFormatDlg::ScCondFormatDlg(SfxBindings* pB, SfxChildWindow* pCW, + weld::Window* pParent, ScViewData* pViewData, + const ScCondFormatDlgItem* pItem) + : ScAnyRefDlgController(pB, pCW, pParent, + (SfxViewShell::Current() && SfxViewShell::Current()->isLOKMobilePhone())?OUString("modules/scalc/ui/conditionalformatdialogmobile.ui"):OUString("modules/scalc/ui/conditionalformatdialog.ui"), + "ConditionalFormatDialog") + , mpViewData(pViewData) + , mpDlgItem(pItem->Clone()) + , mpLastEdit(nullptr) + , mxBtnOk(m_xBuilder->weld_button("ok")) + , mxBtnAdd(m_xBuilder->weld_button("add")) + , mxBtnRemove(m_xBuilder->weld_button("delete")) + , mxBtnUp(m_xBuilder->weld_button("up")) + , mxBtnDown(m_xBuilder->weld_button("down")) + , mxBtnCancel(m_xBuilder->weld_button("cancel")) + , mxFtRange(m_xBuilder->weld_label("ftassign")) + , mxEdRange(new formula::RefEdit(m_xBuilder->weld_entry("edassign"))) + , mxRbRange(new formula::RefButton(m_xBuilder->weld_button("rbassign"))) + , mxCondFormList(new ScCondFormatList(this, m_xBuilder->weld_scrolled_window("listwindow"), + m_xBuilder->weld_container("list"))) +{ + mxEdRange->SetReferences(this, mxFtRange.get()); + mxRbRange->SetReferences(this, mxEdRange.get()); + + ScConditionalFormat* pFormat = nullptr; + mnKey = mpDlgItem->GetIndex(); + if (mpDlgItem->IsManaged() && mpDlgItem->GetConditionalFormatList()) + { + pFormat = mpDlgItem->GetConditionalFormatList()->GetFormat(mnKey); + } + else if (!mpDlgItem->IsManaged()) + { + ScDocument& rDoc = mpViewData->GetDocument(); + pFormat = rDoc.GetCondFormList(mpViewData->GetTabNo())->GetFormat ( mnKey ); + } + + ScRangeList aRange; + if (pFormat) + { + aRange = pFormat->GetRange(); + } + else + { + // this is for adding a new entry + mpViewData->GetMarkData().FillRangeListWithMarks(&aRange, false); + if(aRange.empty()) + { + ScAddress aPos(mpViewData->GetCurX(), mpViewData->GetCurY(), mpViewData->GetTabNo()); + aRange.push_back(ScRange(aPos)); + } + mnKey = 0; + } + maPos = aRange.GetTopLeftCorner(); + + mxCondFormList->init(mpViewData->GetDocument(), pFormat, aRange, maPos, mpDlgItem->GetDialogType()); + + mxBtnOk->connect_clicked(LINK(this, ScCondFormatDlg, BtnPressedHdl ) ); + mxBtnAdd->connect_clicked( LINK( mxCondFormList.get(), ScCondFormatList, AddBtnHdl ) ); + mxBtnRemove->connect_clicked( LINK( mxCondFormList.get(), ScCondFormatList, RemoveBtnHdl ) ); + mxBtnUp->connect_clicked(LINK(mxCondFormList.get(), ScCondFormatList, UpBtnHdl)); + mxBtnDown->connect_clicked(LINK(mxCondFormList.get(), ScCondFormatList, DownBtnHdl)); + mxBtnCancel->connect_clicked( LINK(this, ScCondFormatDlg, BtnPressedHdl ) ); + mxEdRange->SetModifyHdl( LINK( this, ScCondFormatDlg, EdRangeModifyHdl ) ); + mxEdRange->SetGetFocusHdl( LINK( this, ScCondFormatDlg, RangeGetFocusHdl ) ); + + OUString aRangeString; + const ScDocument& rDoc = pViewData->GetDocument(); + aRange.Format(aRangeString, ScRefFlags::VALID, rDoc, rDoc.GetAddressConvention()); + mxEdRange->SetText(aRangeString); + + msBaseTitle = m_xDialog->get_title(); + updateTitle(); +} + +void ScCondFormatDlg::updateTitle() +{ + OUString aTitle = msBaseTitle + " " + mxEdRange->GetText(); + + m_xDialog->set_title(aTitle); +} + +ScCondFormatDlg::~ScCondFormatDlg() +{ +} + +void ScCondFormatDlg::SetActive() +{ + if(mpLastEdit) + mpLastEdit->GrabFocus(); + else + mxEdRange->GrabFocus(); + + RefInputDone(); +} + +void ScCondFormatDlg::RefInputDone( bool bForced ) +{ + ScAnyRefDlgController::RefInputDone(bForced); + + // ScAnyRefModalDlg::RefInputDone resets the title back + // to its original state. + // I.e. if we open the dialog normally, and then click into the sheet + // to modify the selection, the title is updated such that the range + // is only a single cell (e.g. $A$1), after which the dialog switches + // into the RefInput mode. During the RefInput mode the title is updated + // as expected, however at the end RefInputDone overwrites the title + // with the initial (now incorrect) single cell range. Hence we correct + // it here. + updateTitle(); +} + +bool ScCondFormatDlg::IsTableLocked() const +{ + return !mpLastEdit || mpLastEdit == mxEdRange.get(); +} + +bool ScCondFormatDlg::IsRefInputMode() const +{ + return mxEdRange->GetWidget()->get_sensitive(); +} + +void ScCondFormatDlg::SetReference(const ScRange& rRef, ScDocument&) +{ + formula::RefEdit* pEdit = mpLastEdit; + if (!mpLastEdit) + pEdit = mxEdRange.get(); + + if (!pEdit->GetWidget()->get_sensitive()) + return; + + if(rRef.aStart != rRef.aEnd) + RefInputStart(pEdit); + + ScRefFlags nFlags; + if (mpLastEdit && mpLastEdit != mxEdRange.get()) + nFlags = ScRefFlags::RANGE_ABS_3D; + else + nFlags = ScRefFlags::RANGE_ABS; + + const ScDocument& rDoc = mpViewData->GetDocument(); + OUString aRefStr(rRef.Format(rDoc, nFlags, + ScAddress::Details(rDoc.GetAddressConvention(), 0, 0))); + if (pEdit != mxEdRange.get()) + { + Selection sel = pEdit->GetSelection(); + sel.Justify(); // in case of RTL selection + sel.Max() = sel.Min() + aRefStr.getLength(); + pEdit->GetWidget()->replace_selection(aRefStr); + pEdit->SetSelection(sel); // to replace it again with next drag event + } + else + pEdit->SetRefString( aRefStr ); + updateTitle(); +} + +std::unique_ptr<ScConditionalFormat> ScCondFormatDlg::GetConditionalFormat() const +{ + OUString aRangeStr = mxEdRange->GetText(); + if(aRangeStr.isEmpty()) + return nullptr; + + ScRangeList aRange; + ScRefFlags nFlags = aRange.Parse(aRangeStr, mpViewData->GetDocument(), + mpViewData->GetDocument().GetAddressConvention(), maPos.Tab()); + mxCondFormList->SetRange(aRange); + std::unique_ptr<ScConditionalFormat> pFormat = mxCondFormList->GetConditionalFormat(); + + if((nFlags & ScRefFlags::VALID) && !aRange.empty() && pFormat) + pFormat->SetRange(aRange); + else + pFormat.reset(); + + return pFormat; +} + +void ScCondFormatDlg::InvalidateRefData() +{ + mpLastEdit = nullptr; +} + +// Close the Conditional Format Dialog +// +void ScCondFormatDlg::Close() +{ + DoClose( ScCondFormatDlgWrapper::GetChildWindowId() ); +} + +// Occurs when the Conditional Format Dialog the OK button is pressed. +// +void ScCondFormatDlg::OkPressed() +{ + std::unique_ptr<ScConditionalFormat> pFormat = GetConditionalFormat(); + + if (!mpDlgItem->IsManaged()) + { + if(pFormat) + { + auto& rRangeList = pFormat->GetRange(); + mpViewData->GetDocShell()->GetDocFunc().ReplaceConditionalFormat(mnKey, + std::move(pFormat), maPos.Tab(), rRangeList); + } + else + mpViewData->GetDocShell()->GetDocFunc().ReplaceConditionalFormat(mnKey, + nullptr, maPos.Tab(), ScRangeList()); + } + else + { + ScConditionalFormatList* pList = mpDlgItem->GetConditionalFormatList(); + sal_uInt32 nKey = mnKey; + if (mnKey == 0) + { + nKey = pList->getMaxKey() + 1; + } + + pList->erase(nKey); + if (pFormat) + { + pFormat->SetKey(nKey); + pList->InsertNew(std::move(pFormat)); + } + mpViewData->GetViewShell()->GetPool().Put(*mpDlgItem); + + SetDispatcherLock( false ); + // Queue message to open Conditional Format Manager Dialog + GetBindings().GetDispatcher()->Execute( SID_OPENDLG_CONDFRMT_MANAGER, + SfxCallMode::ASYNCHRON ); + } + m_xDialog->response(RET_OK); +} + +// Occurs when the Conditional Format Dialog is cancelled. +// +void ScCondFormatDlg::CancelPressed() +{ + if ( mpDlgItem->IsManaged() ) + { + mpViewData->GetViewShell()->GetPool().Put(*mpDlgItem); + SetDispatcherLock( false ); + // Queue message to open Conditional Format Manager Dialog + GetBindings().GetDispatcher()->Execute( SID_OPENDLG_CONDFRMT_MANAGER, + SfxCallMode::ASYNCHRON ); + } + m_xDialog->response(RET_CANCEL); +} + +void ScCondFormatDlg::OnSelectionChange(size_t nIndex, size_t nSize, bool bSelected) +{ + if (nSize <= 1 || !bSelected) + { + mxBtnUp->set_sensitive(false); + mxBtnDown->set_sensitive(false); + } + else + { + mxBtnUp->set_sensitive(nIndex != 0); + mxBtnDown->set_sensitive(nIndex < nSize - 1); + } +} + +IMPL_LINK(ScCondFormatDlg, EdRangeModifyHdl, formula::RefEdit&, rEdit, void) +{ + OUString aRangeStr = rEdit.GetText(); + ScRangeList aRange; + ScRefFlags nFlags = aRange.Parse(aRangeStr, mpViewData->GetDocument(), + mpViewData->GetDocument().GetAddressConvention()); + if(nFlags & ScRefFlags::VALID) + { + rEdit.GetWidget()->set_message_type(weld::EntryMessageType::Normal); + mxBtnOk->set_sensitive(true); + } + else + { + rEdit.GetWidget()->set_message_type(weld::EntryMessageType::Error); + mxBtnOk->set_sensitive(false); + } + + updateTitle(); +} + +IMPL_LINK(ScCondFormatDlg, RangeGetFocusHdl, formula::RefEdit&, rControl, void) +{ + mpLastEdit = &rControl; +} + +IMPL_LINK( ScCondFormatDlg, BtnPressedHdl, weld::Button&, rBtn, void) +{ + if (&rBtn == mxBtnOk.get()) + OkPressed(); + else if (&rBtn == mxBtnCancel.get()) + CancelPressed(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/condformat/condformatdlgentry.cxx b/sc/source/ui/condformat/condformatdlgentry.cxx new file mode 100644 index 000000000..77175fa64 --- /dev/null +++ b/sc/source/ui/condformat/condformatdlgentry.cxx @@ -0,0 +1,1530 @@ +/* -*- 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/. + */ + +#include <memory> +#include <condformatdlg.hxx> +#include <condformatdlgentry.hxx> +#include <conditio.hxx> +#include <compiler.hxx> +#include <colorscale.hxx> +#include <condformathelper.hxx> + +#include <document.hxx> + +#include <o3tl/string_view.hxx> +#include <svl/style.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/frame.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <svl/numformat.hxx> +#include <svx/colorbox.hxx> +#include <vcl/svapp.hxx> +#include <formula/token.hxx> +#include <formula/errorcodes.hxx> +#include <tokenarray.hxx> +#include <stlpool.hxx> +#include <tabvwsh.hxx> +#include <unotools/charclass.hxx> + +#include <colorformat.hxx> +#include <scresid.hxx> +#include <globstr.hrc> +#include <strings.hrc> + +#include <set> + +// set the widget width to something to override their auto-width calc and +// force them to take a 1/3 of the available space +#define CommonWidgetWidth 10 + +ScCondFrmtEntry::ScCondFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos) + : mpParent(pParent) + , mxBuilder(Application::CreateBuilder(pParent->GetContainer(), (SfxViewShell::Current() && SfxViewShell::Current()->isLOKMobilePhone())?OUString("modules/scalc/ui/conditionalentrymobile.ui"):OUString("modules/scalc/ui/conditionalentry.ui"))) + , mxBorder(mxBuilder->weld_widget("border")) + , mxGrid(mxBuilder->weld_container("grid")) + , mxFtCondNr(mxBuilder->weld_label("number")) + , mxFtCondition(mxBuilder->weld_label("condition")) + , mbActive(false) + , maStrCondition(ScResId(SCSTR_CONDITION)) + , mxLbType(mxBuilder->weld_combo_box("type")) + , mpDoc(pDoc) + , maPos(rPos) +{ + mxLbType->set_size_request(CommonWidgetWidth, -1); + mxLbType->connect_changed(LINK(pParent, ScCondFormatList, TypeListHdl)); + mxGrid->connect_mouse_press(LINK(this, ScCondFrmtEntry, EntrySelectHdl)); + maClickHdl = LINK( pParent, ScCondFormatList, EntrySelectHdl ); + + Show(); +} + +ScCondFrmtEntry::~ScCondFrmtEntry() +{ + mpParent->GetContainer()->move(mxBorder.get(), nullptr); +} + +IMPL_LINK_NOARG(ScCondFrmtEntry, EntrySelectHdl, const MouseEvent&, bool) +{ + maClickHdl.Call(*this); + return false; +} + +void ScCondFrmtEntry::SetIndex(sal_Int32 nIndex) +{ + OUString sLabel = maStrCondition + OUString::number(nIndex); + mxFtCondNr->set_label(sLabel); + + // tdf#124412: uitest + mxFtCondition->set_buildable_name(sLabel.toUtf8()); +} + +void ScCondFrmtEntry::Select() +{ + mxFtCondition->set_label(OUString()); + mxFtCondition->hide(); + mxLbType->show(); + mbActive = true; +} + +void ScCondFrmtEntry::Deselect() +{ + OUString aCondText = GetExpressionString(); + mxFtCondition->set_label(aCondText); + mxFtCondition->show(); + mxLbType->hide(); + mbActive = false; +} + +//condition + +namespace { + +void FillStyleListBox( const ScDocument* pDoc, weld::ComboBox& rLbStyle ) +{ + std::set<OUString> aStyleNames; + SfxStyleSheetIterator aStyleIter( pDoc->GetStyleSheetPool(), SfxStyleFamily::Para ); + for ( SfxStyleSheetBase* pStyle = aStyleIter.First(); pStyle; pStyle = aStyleIter.Next() ) + { + aStyleNames.insert(pStyle->GetName()); + } + for(const auto& rStyleName : aStyleNames) + { + rLbStyle.append_text(rStyleName); + } +} + +} + +const ScConditionMode ScConditionFrmtEntry::mpEntryToCond[ScConditionFrmtEntry::NUM_COND_ENTRIES] = { + ScConditionMode::Equal, + ScConditionMode::Less, + ScConditionMode::Greater, + ScConditionMode::EqLess, + ScConditionMode::EqGreater, + ScConditionMode::NotEqual, + ScConditionMode::Between, + ScConditionMode::NotBetween, + ScConditionMode::Duplicate, + ScConditionMode::NotDuplicate, + ScConditionMode::Top10, + ScConditionMode::Bottom10, + ScConditionMode::TopPercent, + ScConditionMode::BottomPercent, + ScConditionMode::AboveAverage, + ScConditionMode::BelowAverage, + ScConditionMode::AboveEqualAverage, + ScConditionMode::BelowEqualAverage, + ScConditionMode::Error, + ScConditionMode::NoError, + ScConditionMode::BeginsWith, + ScConditionMode::EndsWith, + ScConditionMode::ContainsText, + ScConditionMode::NotContainsText +}; + +ScConditionFrmtEntry::ScConditionFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, ScCondFormatDlg* pDialogParent, + const ScAddress& rPos, const ScCondFormatEntry* pFormatEntry) + : ScCondFrmtEntry(pParent, pDoc, rPos) + , mxLbCondType(mxBuilder->weld_combo_box("typeis")) + , mxEdVal1(new formula::RefEdit(mxBuilder->weld_entry("val1"))) + , mxEdVal2(new formula::RefEdit(mxBuilder->weld_entry("val2"))) + , mxFtVal(mxBuilder->weld_label("valueft")) + , mxFtStyle(mxBuilder->weld_label("styleft")) + , mxLbStyle(mxBuilder->weld_combo_box("style")) + , mxWdPreviewWin(mxBuilder->weld_widget("previewwin")) + , mxWdPreview(new weld::CustomWeld(*mxBuilder, "preview", maWdPreview)) + , mbIsInStyleCreate(false) +{ + mxLbCondType->set_size_request(CommonWidgetWidth, -1); + mxLbType->set_size_request(CommonWidgetWidth, -1); + mxWdPreview->set_size_request(-1, mxLbStyle->get_preferred_size().Height()); + + mxLbType->set_active(1); + + Init(pDialogParent); + + StartListening(*pDoc->GetStyleSheetPool(), DuplicateHandling::Prevent); + + if(pFormatEntry) + { + mxLbStyle->set_active_text(pFormatEntry->GetStyle()); + StyleSelectHdl(*mxLbStyle); + ScConditionMode eMode = pFormatEntry->GetOperation(); + + mxLbCondType->set_active(ConditionModeToEntryPos(eMode)); + + switch(GetNumberEditFields(eMode)) + { + case 0: + mxEdVal1->GetWidget()->hide(); + mxEdVal2->GetWidget()->hide(); + break; + case 1: + mxEdVal1->GetWidget()->show(); + mxEdVal1->SetText(pFormatEntry->GetExpression(maPos, 0)); + mxEdVal2->GetWidget()->hide(); + OnEdChanged(*mxEdVal1); + break; + case 2: + mxEdVal1->GetWidget()->show(); + mxEdVal1->SetText(pFormatEntry->GetExpression(maPos, 0)); + OnEdChanged(*mxEdVal1); + mxEdVal2->GetWidget()->show(); + mxEdVal2->SetText(pFormatEntry->GetExpression(maPos, 1)); + OnEdChanged(*mxEdVal2); + break; + } + } + else + { + mxLbCondType->set_active(0); + mxEdVal2->GetWidget()->hide(); + mxLbStyle->set_active(1); + } +} + +ScConditionFrmtEntry::~ScConditionFrmtEntry() +{ +} + +void ScConditionFrmtEntry::Init(ScCondFormatDlg* pDialogParent) +{ + mxEdVal1->SetGetFocusHdl( LINK( pDialogParent, ScCondFormatDlg, RangeGetFocusHdl ) ); + mxEdVal2->SetGetFocusHdl( LINK( pDialogParent, ScCondFormatDlg, RangeGetFocusHdl ) ); + + mxEdVal1->SetModifyHdl( LINK( this, ScConditionFrmtEntry, OnEdChanged ) ); + mxEdVal2->SetModifyHdl( LINK( this, ScConditionFrmtEntry, OnEdChanged ) ); + + FillStyleListBox( mpDoc, *mxLbStyle ); + mxLbStyle->connect_changed( LINK( this, ScConditionFrmtEntry, StyleSelectHdl ) ); + + mxLbCondType->connect_changed( LINK( this, ScConditionFrmtEntry, ConditionTypeSelectHdl ) ); +} + +ScFormatEntry* ScConditionFrmtEntry::createConditionEntry() const +{ + ScConditionMode eMode = EntryPosToConditionMode(mxLbCondType->get_active()); + OUString aExpr1 = mxEdVal1->GetText(); + OUString aExpr2; + if (GetNumberEditFields(eMode) == 2) + { + aExpr2 = mxEdVal2->GetText(); + if (aExpr2.isEmpty()) + { + return nullptr; + } + } + + ScFormatEntry* pEntry = new ScCondFormatEntry(eMode, aExpr1, aExpr2, *mpDoc, maPos, mxLbStyle->get_active_text()); + return pEntry; +} + +IMPL_LINK(ScConditionFrmtEntry, OnEdChanged, formula::RefEdit&, rRefEdit, void) +{ + weld::Entry& rEdit = *rRefEdit.GetWidget(); + OUString aFormula = rEdit.get_text(); + + if( aFormula.isEmpty() ) + { + mxFtVal->set_label(ScResId(STR_ENTER_VALUE)); + return; + } + + ScCompiler aComp( *mpDoc, maPos, mpDoc->GetGrammar() ); + std::unique_ptr<ScTokenArray> ta(aComp.CompileString(aFormula)); + + // Error, warn the user + if( ta->GetCodeError() != FormulaError::NONE || ( ta->GetLen() == 0 ) ) + { + rEdit.set_message_type(weld::EntryMessageType::Error); + mxFtVal->set_label(ScResId(STR_VALID_DEFERROR)); + return; + } + + // Recognized col/row name or string token, warn the user + formula::FormulaToken* token = ta->FirstToken(); + formula::StackVar t = token->GetType(); + OpCode op = token->GetOpCode(); + if( ( op == ocColRowName ) || + ( ( op == ocBad ) && ( t == formula::svString ) ) + ) + { + rEdit.set_message_type(weld::EntryMessageType::Warning); + mxFtVal->set_label(ScResId(STR_UNQUOTED_STRING)); + return; + } + + rEdit.set_message_type(weld::EntryMessageType::Normal); + mxFtVal->set_label(""); +} + +void ScConditionFrmtEntry::Select() +{ + mxFtVal->show(); + ScCondFrmtEntry::Select(); +} + +void ScConditionFrmtEntry::Deselect() +{ + mxFtVal->hide(); + ScCondFrmtEntry::Deselect(); +} + +sal_Int32 ScConditionFrmtEntry::ConditionModeToEntryPos( ScConditionMode eMode ) +{ + for ( sal_Int32 i = 0; i < NUM_COND_ENTRIES; ++i ) + { + if (mpEntryToCond[i] == eMode) + { + return i; + } + } + assert(false); // should never get here + return 0; +} + +ScConditionMode ScConditionFrmtEntry::EntryPosToConditionMode( sal_Int32 aEntryPos ) +{ + assert( 0 <= aEntryPos && aEntryPos < NUM_COND_ENTRIES ); + return mpEntryToCond[aEntryPos]; +} + +sal_Int32 ScConditionFrmtEntry::GetNumberEditFields( ScConditionMode eMode ) +{ + switch(eMode) + { + case ScConditionMode::Equal: + case ScConditionMode::Less: + case ScConditionMode::Greater: + case ScConditionMode::EqLess: + case ScConditionMode::EqGreater: + case ScConditionMode::NotEqual: + case ScConditionMode::Top10: + case ScConditionMode::Bottom10: + case ScConditionMode::TopPercent: + case ScConditionMode::BottomPercent: + case ScConditionMode::BeginsWith: + case ScConditionMode::EndsWith: + case ScConditionMode::ContainsText: + case ScConditionMode::NotContainsText: + case ScConditionMode::Error: + case ScConditionMode::NoError: + return 1; + case ScConditionMode::AboveAverage: + case ScConditionMode::BelowAverage: + case ScConditionMode::AboveEqualAverage: + case ScConditionMode::BelowEqualAverage: + case ScConditionMode::Duplicate: + case ScConditionMode::NotDuplicate: + return 0; + case ScConditionMode::Between: + case ScConditionMode::NotBetween: + return 2; + default: + assert(false); // should never get here + return 0; + } +} + +OUString ScConditionFrmtEntry::GetExpressionString() +{ + return ScCondFormatHelper::GetExpression(CONDITION, mxLbCondType->get_active(), mxEdVal1->GetText(), mxEdVal2->GetText()); +} + +ScFormatEntry* ScConditionFrmtEntry::GetEntry() const +{ + return createConditionEntry(); +} + +void ScConditionFrmtEntry::SetActive() +{ + ScConditionMode eMode = EntryPosToConditionMode(mxLbCondType->get_active()); + mxLbCondType->show(); + switch(GetNumberEditFields(eMode)) + { + case 1: + mxEdVal1->GetWidget()->show(); + break; + case 2: + mxEdVal1->GetWidget()->show(); + mxEdVal2->GetWidget()->show(); + break; + } + mxFtStyle->show(); + mxLbStyle->show(); + mxWdPreviewWin->show(); + + Select(); +} + +void ScConditionFrmtEntry::SetInactive() +{ + mxLbCondType->hide(); + mxEdVal1->GetWidget()->hide(); + mxEdVal2->GetWidget()->hide(); + mxFtStyle->hide(); + mxLbStyle->hide(); + mxWdPreviewWin->hide(); + + Deselect(); +} + +namespace { + +void UpdateStyleList(weld::ComboBox& rLbStyle, const ScDocument* pDoc) +{ + OUString aSelectedStyle = rLbStyle.get_active_text(); + for (sal_Int32 i = rLbStyle.get_count(); i > 1; --i) + rLbStyle.remove(i - 1); + FillStyleListBox(pDoc, rLbStyle); + rLbStyle.set_active_text(aSelectedStyle); +} + +} + +void ScConditionFrmtEntry::Notify(SfxBroadcaster&, const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::StyleSheetModified) + { + if(!mbIsInStyleCreate) + UpdateStyleList(*mxLbStyle, mpDoc); + } +} + +namespace { + +void StyleSelect(weld::Window* pDialogParent, weld::ComboBox& rLbStyle, const ScDocument* pDoc, SvxFontPrevWindow& rWdPreview) +{ + if (rLbStyle.get_active() == 0) + { + // call new style dialog + SfxUInt16Item aFamilyItem( SID_STYLE_FAMILY, sal_uInt16(SfxStyleFamily::Para) ); + SfxStringItem aRefItem( SID_STYLE_REFERENCE, ScResId(STR_STYLENAME_STANDARD) ); + css::uno::Any aAny(pDialogParent->GetXWindow()); + SfxUnoAnyItem aDialogParent( SID_DIALOG_PARENT, aAny ); + + // unlock the dispatcher so SID_STYLE_NEW can be executed + // (SetDispatcherLock would affect all Calc documents) + ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); + SfxDispatcher* pDisp = pViewShell->GetDispatcher(); + bool bLocked = pDisp->IsLocked(); + if (bLocked) + pDisp->Lock(false); + + // Execute the "new style" slot, complete with undo and all necessary updates. + // The return value (SfxUInt16Item) is ignored, look for new styles instead. + pDisp->ExecuteList(SID_STYLE_NEW, + SfxCallMode::SYNCHRON | SfxCallMode::RECORD, + { &aFamilyItem, &aRefItem }, { &aDialogParent }); + + if (bLocked) + pDisp->Lock(true); + + // Find the new style and add it into the style list boxes + SfxStyleSheetIterator aStyleIter( pDoc->GetStyleSheetPool(), SfxStyleFamily::Para ); + bool bFound = false; + for ( SfxStyleSheetBase* pStyle = aStyleIter.First(); pStyle && !bFound; pStyle = aStyleIter.Next() ) + { + const OUString& aName = pStyle->GetName(); + if (rLbStyle.find_text(aName) == -1) // all lists contain the same entries + { + for( sal_Int32 i = 1, n = rLbStyle.get_count(); i <= n && !bFound; ++i) + { + OUString aStyleName = ScGlobal::getCharClass().uppercase(rLbStyle.get_text(i)); + if( i == n ) + { + rLbStyle.append_text(aName); + rLbStyle.set_active_text(aName); + bFound = true; + } + else if( aStyleName > ScGlobal::getCharClass().uppercase(aName) ) + { + rLbStyle.insert_text(i, aName); + rLbStyle.set_active_text(aName); + bFound = true; + } + } + } + } + } + + OUString aStyleName = rLbStyle.get_active_text(); + SfxStyleSheetBase* pStyleSheet = pDoc->GetStyleSheetPool()->Find( aStyleName, SfxStyleFamily::Para ); + if(pStyleSheet) + { + const SfxItemSet& rSet = pStyleSheet->GetItemSet(); + rWdPreview.SetFromItemSet(rSet, false); + } +} + +} + +IMPL_LINK_NOARG(ScConditionFrmtEntry, StyleSelectHdl, weld::ComboBox&, void) +{ + mbIsInStyleCreate = true; + StyleSelect(mpParent->GetFrameWeld(), *mxLbStyle, mpDoc, maWdPreview); + mbIsInStyleCreate = false; +} + +// formula + +ScFormulaFrmtEntry::ScFormulaFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, ScCondFormatDlg* pDialogParent, const ScAddress& rPos, const ScCondFormatEntry* pFormat) + : ScCondFrmtEntry(pParent, pDoc, rPos) + , mxFtStyle(mxBuilder->weld_label("styleft")) + , mxLbStyle(mxBuilder->weld_combo_box("style")) + , mxWdPreviewWin(mxBuilder->weld_widget("previewwin")) + , mxWdPreview(new weld::CustomWeld(*mxBuilder, "preview", maWdPreview)) + , mxEdFormula(new formula::RefEdit(mxBuilder->weld_entry("formula"))) +{ + mxLbType->set_size_request(CommonWidgetWidth, -1); + mxWdPreview->set_size_request(-1, mxLbStyle->get_preferred_size().Height()); + + Init(pDialogParent); + + mxLbType->set_active(2); + + if(pFormat) + { + mxEdFormula->SetText(pFormat->GetExpression(rPos, 0, 0, pDoc->GetGrammar())); + mxLbStyle->set_active_text(pFormat->GetStyle()); + } + else + { + mxLbStyle->set_active(1); + } + + StyleSelectHdl(*mxLbStyle); +} + +ScFormulaFrmtEntry::~ScFormulaFrmtEntry() +{ +} + +void ScFormulaFrmtEntry::Init(ScCondFormatDlg* pDialogParent) +{ + mxEdFormula->SetGetFocusHdl( LINK( pDialogParent, ScCondFormatDlg, RangeGetFocusHdl ) ); + + FillStyleListBox( mpDoc, *mxLbStyle ); + mxLbStyle->connect_changed( LINK( this, ScFormulaFrmtEntry, StyleSelectHdl ) ); +} + +IMPL_LINK_NOARG(ScFormulaFrmtEntry, StyleSelectHdl, weld::ComboBox&, void) +{ + StyleSelect(mpParent->GetFrameWeld(), *mxLbStyle, mpDoc, maWdPreview); +} + +ScFormatEntry* ScFormulaFrmtEntry::createFormulaEntry() const +{ + OUString aFormula = mxEdFormula->GetText(); + if(aFormula.isEmpty()) + return nullptr; + + ScFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct, aFormula, OUString(), *mpDoc, maPos, mxLbStyle->get_active_text()); + return pEntry; +} + +ScFormatEntry* ScFormulaFrmtEntry::GetEntry() const +{ + return createFormulaEntry(); +} + +OUString ScFormulaFrmtEntry::GetExpressionString() +{ + return ScCondFormatHelper::GetExpression(FORMULA, 0, mxEdFormula->GetText()); +} + +void ScFormulaFrmtEntry::SetActive() +{ + mxWdPreviewWin->show(); + mxFtStyle->show(); + mxLbStyle->show(); + mxEdFormula->GetWidget()->show(); + + Select(); +} + +void ScFormulaFrmtEntry::SetInactive() +{ + mxWdPreviewWin->hide(); + mxFtStyle->hide(); + mxLbStyle->hide(); + mxEdFormula->GetWidget()->hide(); + + Deselect(); +} + +//color scale + +namespace { + +OUString convertNumberToString(double nVal, const ScDocument* pDoc) +{ + SvNumberFormatter* pNumberFormatter = pDoc->GetFormatTable(); + OUString aText; + pNumberFormatter->GetInputLineString(nVal, 0, aText); + return aText; +} + +const struct +{ + ScColorScaleEntryType eType; + const char* sId; +} TypeIdMap[] = { + { COLORSCALE_AUTO, "auto" }, + { COLORSCALE_MIN, "min" }, + { COLORSCALE_MAX, "max" }, + { COLORSCALE_PERCENTILE, "percentil" }, + { COLORSCALE_VALUE, "value" }, + { COLORSCALE_PERCENT, "percent" }, + { COLORSCALE_FORMULA, "formula" }, +}; + +ScColorScaleEntryType getTypeForId(std::u16string_view sId) +{ + for (auto& r : TypeIdMap) + { + if (o3tl::equalsAscii(sId, r.sId)) + return r.eType; + } + assert(false); // The id is not in TypeIdMap - something not in sync? + return COLORSCALE_AUTO; // invalid id - use default +} + +// Item ids are imported from .ui into OUString* and are referenced by entry data. +// See commit 83cefb5ceb4428d61a5b9fae80d1e673131e9bfe + +ScColorScaleEntryType getSelectedType(const weld::ComboBox& rListBox) +{ + return getTypeForId(rListBox.get_active_id()); +} + +sal_Int32 getEntryPos(const weld::ComboBox& rListBox, ScColorScaleEntryType eType) +{ + const sal_Int32 nSize = rListBox.get_count(); + for (sal_Int32 i = 0; i < nSize; ++i) + { + if (getTypeForId(rListBox.get_id(i)) == eType) + return i; + } + return -1; +} + +void selectType(weld::ComboBox& rListBox, ScColorScaleEntryType eType) +{ + const sal_Int32 nPos = getEntryPos(rListBox, eType); + if (nPos >= 0) + rListBox.set_active(nPos); +} + +void removeType(weld::ComboBox& rListBox, ScColorScaleEntryType eType) +{ + const sal_Int32 nPos = getEntryPos(rListBox, eType); + if (nPos >= 0) + rListBox.remove(nPos); +} + +void SetColorScaleEntryTypes( const ScColorScaleEntry& rEntry, weld::ComboBox& rLbType, weld::Entry& rEdit, ColorListBox& rLbCol, const ScDocument* pDoc ) +{ + // entry Automatic is not available for color scales + assert(rEntry.GetType() > COLORSCALE_AUTO); + selectType(rLbType, rEntry.GetType()); + switch(rEntry.GetType()) + { + case COLORSCALE_MIN: + case COLORSCALE_MAX: + break; + case COLORSCALE_PERCENTILE: + case COLORSCALE_VALUE: + case COLORSCALE_PERCENT: + { + double nVal = rEntry.GetValue(); + rEdit.set_text(convertNumberToString(nVal, pDoc)); + } + break; + case COLORSCALE_FORMULA: + rEdit.set_text(rEntry.GetFormula(formula::FormulaGrammar::GRAM_DEFAULT)); + break; + case COLORSCALE_AUTO: + abort(); + break; + } + rLbCol.SelectEntry(rEntry.GetColor()); +} + +void SetColorScaleEntry(ScColorScaleEntry* pEntry, const weld::ComboBox& rType, const weld::Entry& rValue, + ScDocument* pDoc, const ScAddress& rPos) +{ + ScColorScaleEntryType eType = getSelectedType(rType); + + pEntry->SetType(eType); + switch (eType) + { + case COLORSCALE_AUTO: + case COLORSCALE_MIN: + case COLORSCALE_MAX: + break; + case COLORSCALE_PERCENTILE: + case COLORSCALE_VALUE: + case COLORSCALE_PERCENT: + { + sal_uInt32 nIndex = 0; + double nVal = 0; + SvNumberFormatter* pNumberFormatter = pDoc->GetFormatTable(); + (void)pNumberFormatter->IsNumberFormat(rValue.get_text(), nIndex, nVal); + pEntry->SetValue(nVal); + } + break; + case COLORSCALE_FORMULA: + pEntry->SetFormula(rValue.get_text(), *pDoc, rPos); + break; + default: + break; + } +} + +ScColorScaleEntry* createColorScaleEntry( const weld::ComboBox& rType, const ColorListBox& rColor, const weld::Entry& rValue, ScDocument* pDoc, const ScAddress& rPos ) +{ + ScColorScaleEntry* pEntry = new ScColorScaleEntry(); + + SetColorScaleEntry(pEntry, rType, rValue, pDoc, rPos); + Color aColor = rColor.GetSelectEntryColor(); + pEntry->SetColor(aColor); + return pEntry; +} + +} + +ScColorScale2FrmtEntry::ScColorScale2FrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos, const ScColorScaleFormat* pFormat) + : ScCondFrmtEntry(pParent, pDoc, rPos) + , mxLbColorFormat(mxBuilder->weld_combo_box("colorformat")) + , mxLbEntryTypeMin(mxBuilder->weld_combo_box("colscalemin")) + , mxLbEntryTypeMax(mxBuilder->weld_combo_box("colscalemax")) + , mxEdMin(mxBuilder->weld_entry("edcolscalemin")) + , mxEdMax(mxBuilder->weld_entry("edcolscalemax")) + , mxLbColMin(new ColorListBox(mxBuilder->weld_menu_button("lbcolmin"), [this]{ return mpParent->GetFrameWeld(); })) + , mxLbColMax(new ColorListBox(mxBuilder->weld_menu_button("lbcolmax"), [this]{ return mpParent->GetFrameWeld(); })) + , mxFtMin(mxBuilder->weld_label("Label_minimum")) + , mxFtMax(mxBuilder->weld_label("Label_maximum")) +{ + mxLbColorFormat->set_size_request(CommonWidgetWidth, -1); + mxLbEntryTypeMin->set_size_request(CommonWidgetWidth, -1); + mxLbEntryTypeMax->set_size_request(CommonWidgetWidth, -1); + mxLbColMin->get_widget().set_size_request(CommonWidgetWidth, -1); + mxLbColMax->get_widget().set_size_request(CommonWidgetWidth, -1); + + mxFtMin->show(); + mxFtMax->show(); + + // remove the automatic entry from color scales + removeType(*mxLbEntryTypeMin, COLORSCALE_AUTO); + removeType(*mxLbEntryTypeMax, COLORSCALE_AUTO); + // "min" selector doesn't need "max" entry, and vice versa + removeType(*mxLbEntryTypeMin, COLORSCALE_MAX); + removeType(*mxLbEntryTypeMax, COLORSCALE_MIN); + + mxLbType->set_active(0); + mxLbColorFormat->set_active(0); + Init(); + if(pFormat) + { + ScColorScaleEntries::const_iterator itr = pFormat->begin(); + SetColorScaleEntryTypes(*itr[0], *mxLbEntryTypeMin, *mxEdMin, *mxLbColMin, pDoc); + ++itr; + SetColorScaleEntryTypes(*itr[0], *mxLbEntryTypeMax, *mxEdMax, *mxLbColMax, pDoc); + } + else + { + selectType(*mxLbEntryTypeMin, COLORSCALE_MIN); + selectType(*mxLbEntryTypeMax, COLORSCALE_MAX); + } + + mxLbColorFormat->connect_changed( LINK( pParent, ScCondFormatList, ColFormatTypeHdl ) ); + + EntryTypeHdl(*mxLbEntryTypeMin); + EntryTypeHdl(*mxLbEntryTypeMax); +} + +ScColorScale2FrmtEntry::~ScColorScale2FrmtEntry() +{ +} + +void ScColorScale2FrmtEntry::Init() +{ + mxLbEntryTypeMin->connect_changed( LINK( this, ScColorScale2FrmtEntry, EntryTypeHdl ) ); + mxLbEntryTypeMax->connect_changed( LINK( this, ScColorScale2FrmtEntry, EntryTypeHdl ) ); + mxLbColMin->SelectEntry(Color(0xffff6d)); // Light Yellow 2 + mxLbColMax->SelectEntry(Color(0x77bc65)); // Light Green 2 +} + +ScFormatEntry* ScColorScale2FrmtEntry::createColorscaleEntry() const +{ + ScColorScaleFormat* pColorScale = new ScColorScaleFormat(mpDoc); + pColorScale->AddEntry(createColorScaleEntry(*mxLbEntryTypeMin, *mxLbColMin, *mxEdMin, mpDoc, maPos)); + pColorScale->AddEntry(createColorScaleEntry(*mxLbEntryTypeMax, *mxLbColMax, *mxEdMax, mpDoc, maPos)); + return pColorScale; +} + +OUString ScColorScale2FrmtEntry::GetExpressionString() +{ + return ScCondFormatHelper::GetExpression( COLORSCALE, 0 ); +} + +ScFormatEntry* ScColorScale2FrmtEntry::GetEntry() const +{ + return createColorscaleEntry(); +} + +void ScColorScale2FrmtEntry::SetActive() +{ + mxLbColorFormat->show(); + + mxLbEntryTypeMin->show(); + mxLbEntryTypeMax->show(); + + mxEdMin->show(); + mxEdMax->show(); + + mxLbColMin->show(); + mxLbColMax->show(); + + Select(); +} + +void ScColorScale2FrmtEntry::SetInactive() +{ + mxLbColorFormat->hide(); + + mxLbEntryTypeMin->hide(); + mxLbEntryTypeMax->hide(); + + mxEdMin->hide(); + mxEdMax->hide(); + + mxLbColMin->hide(); + mxLbColMax->hide(); + + Deselect(); +} + +IMPL_LINK( ScColorScale2FrmtEntry, EntryTypeHdl, weld::ComboBox&, rBox, void ) +{ + weld::Entry* pEd = nullptr; + if (&rBox == mxLbEntryTypeMin.get()) + pEd = mxEdMin.get(); + else if (&rBox == mxLbEntryTypeMax.get()) + pEd = mxEdMax.get(); + + if (!pEd) + return; + + bool bEnableEdit = true; + if (getSelectedType(rBox) <= COLORSCALE_MAX) + { + bEnableEdit = false; + } + + if (bEnableEdit) + pEd->set_sensitive(true); + else + pEd->set_sensitive(false); +} + +ScColorScale3FrmtEntry::ScColorScale3FrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos, const ScColorScaleFormat* pFormat) + : ScCondFrmtEntry(pParent, pDoc, rPos) + , mxLbColorFormat(mxBuilder->weld_combo_box("colorformat")) + , mxLbEntryTypeMin(mxBuilder->weld_combo_box("colscalemin")) + , mxLbEntryTypeMiddle(mxBuilder->weld_combo_box("colscalemiddle")) + , mxLbEntryTypeMax(mxBuilder->weld_combo_box("colscalemax")) + , mxEdMin(mxBuilder->weld_entry("edcolscalemin")) + , mxEdMiddle(mxBuilder->weld_entry("edcolscalemiddle")) + , mxEdMax(mxBuilder->weld_entry("edcolscalemax")) + , mxLbColMin(new ColorListBox(mxBuilder->weld_menu_button("lbcolmin"), [this]{ return mpParent->GetFrameWeld(); })) + , mxLbColMiddle(new ColorListBox(mxBuilder->weld_menu_button("lbcolmiddle"), [this]{ return mpParent->GetFrameWeld(); })) + , mxLbColMax(new ColorListBox(mxBuilder->weld_menu_button("lbcolmax"), [this]{ return mpParent->GetFrameWeld(); })) + , mxFtMin(mxBuilder->weld_label("Label_minimum")) + , mxFtMax(mxBuilder->weld_label("Label_maximum")) +{ + mxLbColorFormat->set_size_request(CommonWidgetWidth, -1); + mxLbEntryTypeMin->set_size_request(CommonWidgetWidth, -1); + mxLbEntryTypeMiddle->set_size_request(CommonWidgetWidth, -1); + mxLbEntryTypeMax->set_size_request(CommonWidgetWidth, -1); + mxLbColMin->get_widget().set_size_request(CommonWidgetWidth, -1); + mxLbColMiddle->get_widget().set_size_request(CommonWidgetWidth, -1); + mxLbColMax->get_widget().set_size_request(CommonWidgetWidth, -1); + mxFtMin->show(); + mxFtMax->show(); + + // remove the automatic entry from color scales + removeType(*mxLbEntryTypeMin, COLORSCALE_AUTO); + removeType(*mxLbEntryTypeMiddle, COLORSCALE_AUTO); + removeType(*mxLbEntryTypeMax, COLORSCALE_AUTO); + // "min" selector doesn't need "max" entry, and vice versa + removeType(*mxLbEntryTypeMin, COLORSCALE_MAX); + removeType(*mxLbEntryTypeMax, COLORSCALE_MIN); + mxLbColorFormat->set_active(1); + + Init(); + mxLbType->set_active(0); + if(pFormat) + { + ScColorScaleEntries::const_iterator itr = pFormat->begin(); + SetColorScaleEntryTypes(*itr[0], *mxLbEntryTypeMin, *mxEdMin, *mxLbColMin, pDoc); + assert(pFormat->size() == 3); + ++itr; + SetColorScaleEntryTypes(*itr[0], *mxLbEntryTypeMiddle, *mxEdMiddle, *mxLbColMiddle, pDoc); + ++itr; + SetColorScaleEntryTypes(*itr[0], *mxLbEntryTypeMax, *mxEdMax, *mxLbColMax, pDoc); + } + else + { + mxLbColorFormat->set_active(1); + selectType(*mxLbEntryTypeMin, COLORSCALE_MIN); + selectType(*mxLbEntryTypeMiddle, COLORSCALE_PERCENTILE); + selectType(*mxLbEntryTypeMax, COLORSCALE_MAX); + mxEdMiddle->set_text(OUString::number(50)); + } + + mxLbColorFormat->connect_changed( LINK( pParent, ScCondFormatList, ColFormatTypeHdl ) ); + EntryTypeHdl(*mxLbEntryTypeMin); + EntryTypeHdl(*mxLbEntryTypeMiddle); + EntryTypeHdl(*mxLbEntryTypeMax); +} + +ScColorScale3FrmtEntry::~ScColorScale3FrmtEntry() +{ +} + +void ScColorScale3FrmtEntry::Init() +{ + mxLbEntryTypeMin->connect_changed( LINK( this, ScColorScale3FrmtEntry, EntryTypeHdl ) ); + mxLbEntryTypeMax->connect_changed( LINK( this, ScColorScale3FrmtEntry, EntryTypeHdl ) ); + mxLbEntryTypeMiddle->connect_changed( LINK( this, ScColorScale3FrmtEntry, EntryTypeHdl ) ); + mxLbColMin->SelectEntry(COL_LIGHTRED); + mxLbColMiddle->SelectEntry(COL_YELLOW); + mxLbColMax->SelectEntry(Color(0x00a933)); +} + +ScFormatEntry* ScColorScale3FrmtEntry::createColorscaleEntry() const +{ + ScColorScaleFormat* pColorScale = new ScColorScaleFormat(mpDoc); + pColorScale->AddEntry(createColorScaleEntry(*mxLbEntryTypeMin, *mxLbColMin, *mxEdMin, mpDoc, maPos)); + if (mxLbColorFormat->get_active() == 1) + pColorScale->AddEntry(createColorScaleEntry(*mxLbEntryTypeMiddle, *mxLbColMiddle, *mxEdMiddle, mpDoc, maPos)); + pColorScale->AddEntry(createColorScaleEntry(*mxLbEntryTypeMax, *mxLbColMax, *mxEdMax, mpDoc, maPos)); + return pColorScale; +} + +OUString ScColorScale3FrmtEntry::GetExpressionString() +{ + return ScCondFormatHelper::GetExpression( COLORSCALE, 0 ); +} + +ScFormatEntry* ScColorScale3FrmtEntry::GetEntry() const +{ + return createColorscaleEntry(); +} + +void ScColorScale3FrmtEntry::SetActive() +{ + mxLbColorFormat->show(); + mxLbEntryTypeMin->show(); + mxLbEntryTypeMiddle->show(); + mxLbEntryTypeMax->show(); + + mxEdMin->show(); + mxEdMiddle->show(); + mxEdMax->show(); + + mxLbColMin->show(); + mxLbColMiddle->show(); + mxLbColMax->show(); + + Select(); +} + +void ScColorScale3FrmtEntry::SetInactive() +{ + mxLbColorFormat->hide(); + + mxLbEntryTypeMin->hide(); + mxLbEntryTypeMiddle->hide(); + mxLbEntryTypeMax->hide(); + + mxEdMin->hide(); + mxEdMiddle->hide(); + mxEdMax->hide(); + + mxLbColMin->hide(); + mxLbColMiddle->hide(); + mxLbColMax->hide(); + + Deselect(); +} + +IMPL_LINK( ScColorScale3FrmtEntry, EntryTypeHdl, weld::ComboBox&, rBox, void ) +{ + weld::Entry* pEd = nullptr; + if(&rBox == mxLbEntryTypeMin.get()) + pEd = mxEdMin.get(); + else if(&rBox == mxLbEntryTypeMiddle.get()) + pEd = mxEdMiddle.get(); + else if(&rBox == mxLbEntryTypeMax.get()) + pEd = mxEdMax.get(); + + if (!pEd) + return; + + bool bEnableEdit = true; + if (getSelectedType(rBox) <= COLORSCALE_MAX) + { + bEnableEdit = false; + } + + if(bEnableEdit) + pEd->set_sensitive(true); + else + pEd->set_sensitive(false); +} + +IMPL_LINK_NOARG(ScConditionFrmtEntry, ConditionTypeSelectHdl, weld::ComboBox&, void) +{ + sal_Int32 nSelectPos = mxLbCondType->get_active(); + ScConditionMode eMode = EntryPosToConditionMode(nSelectPos); + switch(GetNumberEditFields(eMode)) + { + case 0: + mxEdVal1->GetWidget()->hide(); + mxEdVal2->GetWidget()->hide(); + mxFtVal->hide(); + break; + case 1: + mxEdVal1->GetWidget()->show(); + mxEdVal2->GetWidget()->hide(); + mxFtVal->show(); + break; + case 2: + mxEdVal1->GetWidget()->show(); + mxEdVal2->GetWidget()->show(); + mxFtVal->show(); + break; + } +} + +//databar + +namespace { + +void SetDataBarEntryTypes( const ScColorScaleEntry& rEntry, weld::ComboBox& rLbType, weld::Entry& rEdit, const ScDocument* pDoc ) +{ + selectType(rLbType, rEntry.GetType()); + switch(rEntry.GetType()) + { + case COLORSCALE_AUTO: + case COLORSCALE_MIN: + case COLORSCALE_MAX: + break; + case COLORSCALE_VALUE: + case COLORSCALE_PERCENT: + case COLORSCALE_PERCENTILE: + { + double nVal = rEntry.GetValue(); + SvNumberFormatter* pNumberFormatter = pDoc->GetFormatTable(); + OUString aText; + pNumberFormatter->GetInputLineString(nVal, 0, aText); + rEdit.set_text(aText); + } + break; + case COLORSCALE_FORMULA: + rEdit.set_text(rEntry.GetFormula(formula::FormulaGrammar::GRAM_DEFAULT)); + break; + } +} + +} + +ScDataBarFrmtEntry::ScDataBarFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos, const ScDataBarFormat* pFormat) + : ScCondFrmtEntry(pParent, pDoc, rPos) + , mxLbColorFormat(mxBuilder->weld_combo_box("colorformat")) + , mxLbDataBarMinType(mxBuilder->weld_combo_box("colscalemin")) + , mxLbDataBarMaxType(mxBuilder->weld_combo_box("colscalemax")) + , mxEdDataBarMin(mxBuilder->weld_entry("edcolscalemin")) + , mxEdDataBarMax(mxBuilder->weld_entry("edcolscalemax")) + , mxBtOptions(mxBuilder->weld_button("options")) + , mxFtMin(mxBuilder->weld_label("Label_minimum")) + , mxFtMax(mxBuilder->weld_label("Label_maximum")) +{ + mxLbColorFormat->set_size_request(CommonWidgetWidth, -1); + mxLbDataBarMinType->set_size_request(CommonWidgetWidth, -1); + mxLbDataBarMaxType->set_size_request(CommonWidgetWidth, -1); + + // "min" selector doesn't need "max" entry, and vice versa + removeType(*mxLbDataBarMinType, COLORSCALE_MAX); + removeType(*mxLbDataBarMaxType, COLORSCALE_MIN); + + mxFtMin->show(); + mxFtMax->show(); + + mxLbColorFormat->set_active(2); + mxLbType->set_active(0); + if(pFormat) + { + mpDataBarData.reset(new ScDataBarFormatData(*pFormat->GetDataBarData())); + SetDataBarEntryTypes(*mpDataBarData->mpLowerLimit, *mxLbDataBarMinType, *mxEdDataBarMin, pDoc); + SetDataBarEntryTypes(*mpDataBarData->mpUpperLimit, *mxLbDataBarMaxType, *mxEdDataBarMax, pDoc); + DataBarTypeSelectHdl(*mxLbDataBarMinType); + } + else + { + selectType(*mxLbDataBarMinType, COLORSCALE_AUTO); + selectType(*mxLbDataBarMaxType, COLORSCALE_AUTO); + DataBarTypeSelectHdl(*mxLbDataBarMinType); + } + Init(); + + mxLbColorFormat->connect_changed( LINK( pParent, ScCondFormatList, ColFormatTypeHdl ) ); +} + +ScDataBarFrmtEntry::~ScDataBarFrmtEntry() +{ +} + +ScFormatEntry* ScDataBarFrmtEntry::GetEntry() const +{ + return createDatabarEntry(); +} + +void ScDataBarFrmtEntry::Init() +{ + mxLbDataBarMinType->connect_changed( LINK( this, ScDataBarFrmtEntry, DataBarTypeSelectHdl ) ); + mxLbDataBarMaxType->connect_changed( LINK( this, ScDataBarFrmtEntry, DataBarTypeSelectHdl ) ); + + mxBtOptions->connect_clicked( LINK( this, ScDataBarFrmtEntry, OptionBtnHdl ) ); + + if(!mpDataBarData) + { + mpDataBarData.reset(new ScDataBarFormatData()); + mpDataBarData->mpUpperLimit.reset(new ScColorScaleEntry()); + mpDataBarData->mpLowerLimit.reset(new ScColorScaleEntry()); + mpDataBarData->mpLowerLimit->SetType(COLORSCALE_AUTO); + mpDataBarData->mpUpperLimit->SetType(COLORSCALE_AUTO); + mpDataBarData->maPositiveColor = 0x2a6099; + } +} + +ScFormatEntry* ScDataBarFrmtEntry::createDatabarEntry() const +{ + SetColorScaleEntry(mpDataBarData->mpLowerLimit.get(), *mxLbDataBarMinType, + *mxEdDataBarMin, mpDoc, maPos); + SetColorScaleEntry(mpDataBarData->mpUpperLimit.get(), *mxLbDataBarMaxType, + *mxEdDataBarMax, mpDoc, maPos); + ScDataBarFormat* pDataBar = new ScDataBarFormat(mpDoc); + pDataBar->SetDataBarData(new ScDataBarFormatData(*mpDataBarData)); + return pDataBar; +} + +OUString ScDataBarFrmtEntry::GetExpressionString() +{ + return ScCondFormatHelper::GetExpression( DATABAR, 0 ); +} + +void ScDataBarFrmtEntry::SetActive() +{ + mxLbColorFormat->show(); + + mxLbDataBarMinType->show(); + mxLbDataBarMaxType->show(); + mxEdDataBarMin->show(); + mxEdDataBarMax->show(); + mxBtOptions->show(); + + Select(); +} + +void ScDataBarFrmtEntry::SetInactive() +{ + mxLbColorFormat->hide(); + + mxLbDataBarMinType->hide(); + mxLbDataBarMaxType->hide(); + mxEdDataBarMin->hide(); + mxEdDataBarMax->hide(); + mxBtOptions->hide(); + + Deselect(); +} + +IMPL_LINK_NOARG( ScDataBarFrmtEntry, DataBarTypeSelectHdl, weld::ComboBox&, void ) +{ + if (getSelectedType(*mxLbDataBarMinType) <= COLORSCALE_MAX) + mxEdDataBarMin->set_sensitive(false); + else + mxEdDataBarMin->set_sensitive(true); + + if (getSelectedType(*mxLbDataBarMaxType) <= COLORSCALE_MAX) + mxEdDataBarMax->set_sensitive(false); + else + mxEdDataBarMax->set_sensitive(true); +} + +IMPL_LINK_NOARG( ScDataBarFrmtEntry, OptionBtnHdl, weld::Button&, void ) +{ + SetColorScaleEntry(mpDataBarData->mpLowerLimit.get(), *mxLbDataBarMinType, + *mxEdDataBarMin, mpDoc, maPos); + SetColorScaleEntry(mpDataBarData->mpUpperLimit.get(), *mxLbDataBarMaxType, + *mxEdDataBarMax, mpDoc, maPos); + ScDataBarSettingsDlg aDlg(mpParent->GetFrameWeld(), *mpDataBarData, mpDoc, maPos); + if (aDlg.run() == RET_OK) + { + mpDataBarData.reset(aDlg.GetData()); + SetDataBarEntryTypes(*mpDataBarData->mpLowerLimit, *mxLbDataBarMinType, *mxEdDataBarMin, mpDoc); + SetDataBarEntryTypes(*mpDataBarData->mpUpperLimit, *mxLbDataBarMaxType, *mxEdDataBarMax, mpDoc); + DataBarTypeSelectHdl(*mxLbDataBarMinType); + } +} + +ScDateFrmtEntry::ScDateFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScCondDateFormatEntry* pFormat) + : ScCondFrmtEntry(pParent, pDoc, ScAddress()) + , mxLbDateEntry(mxBuilder->weld_combo_box("datetype")) + , mxFtStyle(mxBuilder->weld_label("styleft")) + , mxLbStyle(mxBuilder->weld_combo_box("style")) + , mxWdPreviewWin(mxBuilder->weld_widget("previewwin")) + , mxWdPreview(new weld::CustomWeld(*mxBuilder, "preview", maWdPreview)) + , mbIsInStyleCreate(false) +{ + mxLbDateEntry->set_size_request(CommonWidgetWidth, -1); + mxLbStyle->set_size_request(CommonWidgetWidth, -1); + + mxWdPreview->set_size_request(mxLbStyle->get_preferred_size().Height(), -1); + + Init(); + + StartListening(*pDoc->GetStyleSheetPool(), DuplicateHandling::Prevent); + + if(pFormat) + { + sal_Int32 nPos = static_cast<sal_Int32>(pFormat->GetDateType()); + mxLbDateEntry->set_active(nPos); + + mxLbStyle->set_active_text(pFormat->GetStyleName()); + } + + StyleSelectHdl(*mxLbStyle); +} + +ScDateFrmtEntry::~ScDateFrmtEntry() +{ +} + +void ScDateFrmtEntry::Init() +{ + mxLbDateEntry->set_active(0); + mxLbType->set_active(3); + + FillStyleListBox( mpDoc, *mxLbStyle ); + mxLbStyle->connect_changed( LINK( this, ScDateFrmtEntry, StyleSelectHdl ) ); + mxLbStyle->set_active(1); +} + +void ScDateFrmtEntry::SetActive() +{ + mxLbDateEntry->show(); + mxFtStyle->show(); + mxWdPreviewWin->show(); + mxLbStyle->show(); + + Select(); +} + +void ScDateFrmtEntry::SetInactive() +{ + mxLbDateEntry->hide(); + mxFtStyle->hide(); + mxWdPreviewWin->hide(); + mxLbStyle->hide(); + + Deselect(); +} + +void ScDateFrmtEntry::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + if(rHint.GetId() == SfxHintId::StyleSheetModified) + { + if(!mbIsInStyleCreate) + UpdateStyleList(*mxLbStyle, mpDoc); + } +} + +ScFormatEntry* ScDateFrmtEntry::GetEntry() const +{ + ScCondDateFormatEntry* pNewEntry = new ScCondDateFormatEntry(mpDoc); + condformat::ScCondFormatDateType eType = static_cast<condformat::ScCondFormatDateType>(mxLbDateEntry->get_active()); + pNewEntry->SetDateType(eType); + pNewEntry->SetStyleName(mxLbStyle->get_active_text()); + return pNewEntry; +} + +OUString ScDateFrmtEntry::GetExpressionString() +{ + // tdf#124412 - set actual condition for an inactive date entry + return ScCondFormatHelper::GetExpression(DATE, mxLbDateEntry->get_active()); +} + +IMPL_LINK_NOARG( ScDateFrmtEntry, StyleSelectHdl, weld::ComboBox&, void ) +{ + mbIsInStyleCreate = true; + StyleSelect(mpParent->GetFrameWeld(), *mxLbStyle, mpDoc, maWdPreview); + mbIsInStyleCreate = false; +} + +class ScIconSetFrmtDataEntry +{ +protected: + std::unique_ptr<weld::Builder> mxBuilder; +private: + std::unique_ptr<weld::Container> mxGrid; + std::unique_ptr<weld::Image> mxImgIcon; + std::unique_ptr<weld::Label> mxFtEntry; + std::unique_ptr<weld::Entry> mxEdEntry; + std::unique_ptr<weld::ComboBox> mxLbEntryType; + weld::Container* mpContainer; + +public: + ScIconSetFrmtDataEntry(weld::Container* pParent, ScIconSetType eType, const ScDocument* pDoc, + sal_Int32 i, const ScColorScaleEntry* pEntry = nullptr); + ~ScIconSetFrmtDataEntry(); + void Show() { mxGrid->show(); } + void Hide() { mxGrid->hide(); } + void set_grid_top_attach(int nTop) + { + mxGrid->set_grid_left_attach(0); + mxGrid->set_grid_top_attach(nTop); + } + + ScColorScaleEntry* CreateEntry(ScDocument& rDoc, const ScAddress& rPos) const; + + void SetFirstEntry(); +}; + +ScIconSetFrmtDataEntry::ScIconSetFrmtDataEntry(weld::Container* pParent, ScIconSetType eType, const ScDocument* pDoc, sal_Int32 i, const ScColorScaleEntry* pEntry) + : mxBuilder(Application::CreateBuilder(pParent, "modules/scalc/ui/conditionaliconset.ui")) + , mxGrid(mxBuilder->weld_container("ConditionalIconSet")) + , mxImgIcon(mxBuilder->weld_image("icon")) + , mxFtEntry(mxBuilder->weld_label("label")) + , mxEdEntry(mxBuilder->weld_entry("entry")) + , mxLbEntryType(mxBuilder->weld_combo_box("listbox")) + , mpContainer(pParent) +{ + mxImgIcon->set_from_icon_name(ScIconSetFormat::getIconName(eType, i)); + if(pEntry) + { + switch(pEntry->GetType()) + { + case COLORSCALE_VALUE: + mxLbEntryType->set_active(0); + mxEdEntry->set_text(convertNumberToString(pEntry->GetValue(), pDoc)); + break; + case COLORSCALE_PERCENTILE: + mxLbEntryType->set_active(2); + mxEdEntry->set_text(convertNumberToString(pEntry->GetValue(), pDoc)); + break; + case COLORSCALE_PERCENT: + mxLbEntryType->set_active(1); + mxEdEntry->set_text(convertNumberToString(pEntry->GetValue(), pDoc)); + break; + case COLORSCALE_FORMULA: + mxLbEntryType->set_active(3); + mxEdEntry->set_text(pEntry->GetFormula(formula::FormulaGrammar::GRAM_DEFAULT)); + break; + default: + assert(false); + } + } + else + { + mxLbEntryType->set_active(1); + } +} + +ScIconSetFrmtDataEntry::~ScIconSetFrmtDataEntry() +{ + mpContainer->move(mxGrid.get(), nullptr); +} + +ScColorScaleEntry* ScIconSetFrmtDataEntry::CreateEntry(ScDocument& rDoc, const ScAddress& rPos) const +{ + sal_Int32 nPos = mxLbEntryType->get_active(); + OUString aText = mxEdEntry->get_text(); + ScColorScaleEntry* pEntry = new ScColorScaleEntry(); + + sal_uInt32 nIndex = 0; + double nVal = 0; + SvNumberFormatter* pNumberFormatter = rDoc.GetFormatTable(); + (void)pNumberFormatter->IsNumberFormat(aText, nIndex, nVal); + pEntry->SetValue(nVal); + + switch(nPos) + { + case 0: + pEntry->SetType(COLORSCALE_VALUE); + break; + case 1: + pEntry->SetType(COLORSCALE_PERCENT); + break; + case 2: + pEntry->SetType(COLORSCALE_PERCENTILE); + break; + case 3: + pEntry->SetType(COLORSCALE_FORMULA); + pEntry->SetFormula(aText, rDoc, rPos, rDoc.GetGrammar()); + break; + default: + assert(false); + } + + return pEntry; +} + +void ScIconSetFrmtDataEntry::SetFirstEntry() +{ + mxEdEntry->hide(); + mxLbEntryType->hide(); + mxFtEntry->hide(); + mxEdEntry->set_text("0"); + mxLbEntryType->set_active(1); +} + +ScIconSetFrmtEntry::ScIconSetFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos, const ScIconSetFormat* pFormat) + : ScCondFrmtEntry(pParent, pDoc, rPos) + , mxLbColorFormat(mxBuilder->weld_combo_box("colorformat")) + , mxLbIconSetType(mxBuilder->weld_combo_box("iconsettype")) + , mxIconParent(mxBuilder->weld_container("iconparent")) +{ + mxLbColorFormat->set_size_request(CommonWidgetWidth, -1); + mxLbIconSetType->set_size_request(CommonWidgetWidth, -1); + + Init(); + mxLbColorFormat->connect_changed(LINK(pParent, ScCondFormatList, ColFormatTypeHdl)); + + if(pFormat) + { + const ScIconSetFormatData* pIconSetFormatData = pFormat->GetIconSetData(); + ScIconSetType eType = pIconSetFormatData->eIconSetType; + sal_Int32 nType = static_cast<sal_Int32>(eType); + mxLbIconSetType->set_active(nType); + + for (size_t i = 0, n = pIconSetFormatData->m_Entries.size(); + i < n; ++i) + { + maEntries.emplace_back(new ScIconSetFrmtDataEntry( + mxIconParent.get(), eType, pDoc, i, pIconSetFormatData->m_Entries[i].get())); + maEntries[i]->set_grid_top_attach(i); + } + maEntries[0]->SetFirstEntry(); + } + else + IconSetTypeHdl(*mxLbIconSetType); +} + +ScIconSetFrmtEntry::~ScIconSetFrmtEntry() +{ +} + +void ScIconSetFrmtEntry::Init() +{ + mxLbColorFormat->set_active(3); + mxLbType->set_active(0); + mxLbIconSetType->set_active(0); + + mxLbIconSetType->connect_changed(LINK(this, ScIconSetFrmtEntry, IconSetTypeHdl)); +} + +IMPL_LINK_NOARG( ScIconSetFrmtEntry, IconSetTypeHdl, weld::ComboBox&, void ) +{ + const ScIconSetMap* pMap = ScIconSetFormat::g_IconSetMap; + + sal_Int32 nPos = mxLbIconSetType->get_active(); + sal_uInt32 nElements = pMap[nPos].nElements; + + maEntries.clear(); + + for(size_t i = 0; i < nElements; ++i) + { + maEntries.emplace_back(new ScIconSetFrmtDataEntry(mxIconParent.get(), static_cast<ScIconSetType>(nPos), mpDoc, i)); + maEntries[i]->set_grid_top_attach(i); + maEntries[i]->Show(); + } + maEntries[0]->SetFirstEntry(); +} + +OUString ScIconSetFrmtEntry::GetExpressionString() +{ + return ScCondFormatHelper::GetExpression(ICONSET, 0); +} + +void ScIconSetFrmtEntry::SetActive() +{ + mxLbColorFormat->show(); + mxLbIconSetType->show(); + for(auto& rxEntry : maEntries) + { + rxEntry->Show(); + } + + Select(); +} + +void ScIconSetFrmtEntry::SetInactive() +{ + mxLbColorFormat->hide(); + mxLbIconSetType->hide(); + for(auto& rxEntry : maEntries) + { + rxEntry->Hide(); + } + + Deselect(); +} + +ScFormatEntry* ScIconSetFrmtEntry::GetEntry() const +{ + ScIconSetFormat* pFormat = new ScIconSetFormat(mpDoc); + + ScIconSetFormatData* pData = new ScIconSetFormatData; + pData->eIconSetType = static_cast<ScIconSetType>(mxLbIconSetType->get_active()); + for(const auto& rxEntry : maEntries) + { + pData->m_Entries.emplace_back(rxEntry->CreateEntry(*mpDoc, maPos)); + } + pFormat->SetIconSetData(pData); + + return pFormat; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/condformat/condformatdlgitem.cxx b/sc/source/ui/condformat/condformatdlgitem.cxx new file mode 100644 index 000000000..b0bf511c3 --- /dev/null +++ b/sc/source/ui/condformat/condformatdlgitem.cxx @@ -0,0 +1,66 @@ +/* -*- 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/. + */ + + +#include <utility> + +#include <scitems.hxx> +#include <condformatdlgitem.hxx> + +ScCondFormatDlgItem::ScCondFormatDlgItem(std::shared_ptr<ScConditionalFormatList> pCondFormats, + sal_Int32 nItem, bool bManaged): + SfxPoolItem(SCITEM_CONDFORMATDLGDATA), + mpCondFormats(std::move(pCondFormats)), + mnItem(nItem), + meDialogType(condformat::dialog::CONDITION), + mbManaged(bManaged) +{ +} + +ScCondFormatDlgItem::~ScCondFormatDlgItem() +{ +} + +bool ScCondFormatDlgItem::operator==(const SfxPoolItem& rItem) const +{ + assert(SfxPoolItem::operator==(rItem)); (void)rItem; + return false; +} + +ScCondFormatDlgItem* ScCondFormatDlgItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new ScCondFormatDlgItem(*this); +} + +bool ScCondFormatDlgItem::IsManaged() const +{ + return mbManaged; +} + +condformat::dialog::ScCondFormatDialogType ScCondFormatDlgItem::GetDialogType() const +{ + return meDialogType; +} + +sal_Int32 ScCondFormatDlgItem::GetIndex() const +{ + return mnItem; +} + +ScConditionalFormatList* ScCondFormatDlgItem::GetConditionalFormatList() +{ + return mpCondFormats.get(); +} + +void ScCondFormatDlgItem::SetDialogType(condformat::dialog::ScCondFormatDialogType eType) +{ + meDialogType = eType; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/condformat/condformathelper.cxx b/sc/source/ui/condformat/condformathelper.cxx new file mode 100644 index 000000000..00509b7e2 --- /dev/null +++ b/sc/source/ui/condformat/condformathelper.cxx @@ -0,0 +1,229 @@ +/* -*- 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/. + */ + +#include <sal/config.h> + +#include <o3tl/safeint.hxx> +#include <rtl/ustrbuf.hxx> +#include <condformathelper.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <conditio.hxx> + +namespace { + +OUString getTextForType(ScCondFormatEntryType eType) +{ + switch(eType) + { + case CONDITION: + return ScResId(STR_COND_CONDITION); + case COLORSCALE: + return ScResId(STR_COND_COLORSCALE); + case DATABAR: + return ScResId(STR_COND_DATABAR); + case FORMULA: + return ScResId(STR_COND_FORMULA); + case ICONSET: + return ScResId(STR_COND_ICONSET); + case DATE: + return ScResId(STR_COND_DATE); + default: + break; + } + + return OUString(); +} + +OUString getExpression(sal_Int32 nIndex) +{ + switch(nIndex) + { + case 0: + return "="; + case 1: + return "<"; + case 2: + return ">"; + case 3: + return "<="; + case 4: + return ">="; + case 5: + return "!="; + case 6: + return ScResId(STR_COND_BETWEEN); + case 7: + return ScResId(STR_COND_NOTBETWEEN); + case 8: + return ScResId(STR_COND_DUPLICATE); + case 9: + return ScResId(STR_COND_UNIQUE); + + case 11: + return ScResId(STR_COND_TOP10); + case 12: + return ScResId(STR_COND_BOTTOM10); + case 13: + return ScResId(STR_COND_TOP_PERCENT); + case 14: + return ScResId(STR_COND_BOTTOM_PERCENT); + case 15: + return ScResId(STR_COND_ABOVE_AVERAGE); + case 16: + return ScResId(STR_COND_BELOW_AVERAGE); + case 17: + return ScResId(STR_COND_ABOVE_EQUAL_AVERAGE); + case 18: + return ScResId(STR_COND_BELOW_EQUAL_AVERAGE); + case 19: + return ScResId(STR_COND_ERROR); + case 20: + return ScResId(STR_COND_NOERROR); + case 21: + return ScResId(STR_COND_BEGINS_WITH); + case 22: + return ScResId(STR_COND_ENDS_WITH); + case 23: + return ScResId(STR_COND_CONTAINS); + case 24: + return ScResId(STR_COND_NOT_CONTAINS); + + case 10: + assert(false); + } + return OUString(); +} + +OUString getDateString(sal_Int32 nIndex) +{ + const TranslateId aCondStrs[] = + { + STR_COND_TODAY, + STR_COND_YESTERDAY, + STR_COND_TOMORROW, + STR_COND_LAST7DAYS, + STR_COND_THISWEEK, + STR_COND_LASTWEEK, + STR_COND_NEXTWEEK, + STR_COND_THISMONTH, + STR_COND_LASTMONTH, + STR_COND_NEXTMONTH, + STR_COND_THISYEAR, + STR_COND_LASTYEAR, + STR_COND_NEXTYEAR + }; + + if (nIndex >= 0 && o3tl::make_unsigned(nIndex) < SAL_N_ELEMENTS(aCondStrs)) + return ScResId(aCondStrs[nIndex]); + assert(false); + return OUString(); +} + +} + +OUString ScCondFormatHelper::GetExpression(const ScConditionalFormat& rFormat, const ScAddress& rPos) +{ + OUStringBuffer aBuffer; + if(!rFormat.IsEmpty()) + { + switch(rFormat.GetEntry(0)->GetType()) + { + case ScFormatEntry::Type::Condition: + case ScFormatEntry::Type::ExtCondition: + { + const ScConditionEntry* pEntry = static_cast<const ScConditionEntry*>(rFormat.GetEntry(0)); + ScConditionMode eMode = pEntry->GetOperation(); + if(eMode == ScConditionMode::Direct) + { + aBuffer.append(getTextForType(FORMULA)); + aBuffer.append(" "); + aBuffer.append(pEntry->GetExpression(rPos, 0)); + } + else + { + aBuffer.append(getTextForType(CONDITION)); + aBuffer.append(" "); + aBuffer.append(getExpression(static_cast<sal_Int32>(eMode))); + aBuffer.append(" "); + if(eMode == ScConditionMode::Between || eMode == ScConditionMode::NotBetween) + { + aBuffer.append(pEntry->GetExpression(rPos, 0)); + aBuffer.append(" "); + aBuffer.append(ScResId(STR_COND_AND)); + aBuffer.append(" "); + aBuffer.append(pEntry->GetExpression(rPos, 1)); + } + else if(eMode <= ScConditionMode::NotEqual || eMode >= ScConditionMode::BeginsWith) + { + aBuffer.append(pEntry->GetExpression(rPos, 0)); + } + } + } + + break; + case ScFormatEntry::Type::Databar: + aBuffer.append(getTextForType(DATABAR)); + break; + case ScFormatEntry::Type::Colorscale: + aBuffer.append(getTextForType(COLORSCALE)); + break; + case ScFormatEntry::Type::Iconset: + aBuffer.append(getTextForType(ICONSET)); + break; + case ScFormatEntry::Type::Date: + { + aBuffer.append(getTextForType(DATE)); + aBuffer.append(" "); + sal_Int32 nDateEntry = static_cast<sal_Int32>(static_cast<const ScCondDateFormatEntry*>(rFormat.GetEntry(0))->GetDateType()); + aBuffer.append(getDateString(nDateEntry)); + } + break; + } + } + return aBuffer.makeStringAndClear(); +} + +OUString ScCondFormatHelper::GetExpression( ScCondFormatEntryType eType, sal_Int32 nIndex, + std::u16string_view aStr1, std::u16string_view aStr2 ) +{ + OUStringBuffer aBuffer(getTextForType(eType)); + aBuffer.append(" "); + if(eType == CONDITION) + { + // workaround missing FORMULA option in the conditions case + // FORMULA is handled later + if(nIndex > 9) + ++nIndex; + aBuffer.append(getExpression(nIndex)); + if(nIndex <= 7 || nIndex >= 19) + { + aBuffer.append(OUString::Concat(" ") + aStr1); + if(nIndex == 6 || nIndex == 7) + { + aBuffer.append(" "); + aBuffer.append(ScResId(STR_COND_AND)); + aBuffer.append(" "); + aBuffer.append(aStr2); + } + } + } + else if(eType == FORMULA) + { + aBuffer.append(OUString::Concat(" ") + aStr1); + } + else if(eType == DATE) + { + aBuffer.append(getDateString(nIndex)); + } + + return aBuffer.makeStringAndClear(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/condformat/condformatmgr.cxx b/sc/source/ui/condformat/condformatmgr.cxx new file mode 100644 index 000000000..79f41bf5c --- /dev/null +++ b/sc/source/ui/condformat/condformatmgr.cxx @@ -0,0 +1,180 @@ +/* -*- 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/. + */ + +#include <condformatmgr.hxx> +#include <condformathelper.hxx> +#include <condformatdlg.hxx> +#include <document.hxx> +#include <conditio.hxx> +#include <o3tl/safeint.hxx> +#include <unotools/viewoptions.hxx> + +ScCondFormatManagerWindow::ScCondFormatManagerWindow(weld::TreeView& rTreeView, + ScDocument& rDoc, ScConditionalFormatList* pFormatList) + : mrTreeView(rTreeView) + , mrDoc(rDoc) + , mpFormatList(pFormatList) +{ + mrTreeView.set_size_request(mrTreeView.get_approximate_digit_width() * 70, + mrTreeView.get_height_rows(20)); + setColSizes(); + + Init(); + mrTreeView.set_selection_mode(SelectionMode::Multiple); + mrTreeView.make_sorted(); +} + +void ScCondFormatManagerWindow::Init() +{ + mrTreeView.freeze(); + + if (mpFormatList) + { + int nRow = 0; + OUString sRangeStr; + for(const auto& rItem : *mpFormatList) + { + const ScRangeList& aRange = rItem->GetRange(); + aRange.Format(sRangeStr, ScRefFlags::VALID, mrDoc, mrDoc.GetAddressConvention()); + mrTreeView.append(OUString::number(rItem->GetKey()), sRangeStr); + mrTreeView.set_text(nRow, ScCondFormatHelper::GetExpression(*rItem, aRange.GetTopLeftCorner()), 1); + ++nRow; + } + } + + mrTreeView.thaw(); + + if (mpFormatList && !mpFormatList->empty()) + mrTreeView.select(0); +} + +void ScCondFormatManagerWindow::DeleteSelection() +{ + auto aSelectedRows = mrTreeView.get_selected_rows(); + std::sort(aSelectedRows.begin(), aSelectedRows.end()); + for (auto it = aSelectedRows.rbegin(); it != aSelectedRows.rend(); ++it) + { + sal_Int32 nIndex = mrTreeView.get_id(*it).toInt32(); + mpFormatList->erase(nIndex); + mrTreeView.remove(*it); + } +} + +ScConditionalFormat* ScCondFormatManagerWindow::GetSelection() +{ + int nEntry = mrTreeView.get_selected_index(); + if (nEntry == -1) + return nullptr; + + sal_Int32 nIndex = mrTreeView.get_id(nEntry).toInt32(); + return mpFormatList->GetFormat(nIndex); +} + +void ScCondFormatManagerWindow::setColSizes() +{ + std::vector<int> aWidths + { + o3tl::narrowing<int>(mrTreeView.get_size_request().Width() / 2) + }; + mrTreeView.set_column_fixed_widths(aWidths); +} + +ScCondFormatManagerDlg::ScCondFormatManagerDlg(weld::Window* pParent, ScDocument& rDoc, const ScConditionalFormatList* pFormatList) + : GenericDialogController(pParent, "modules/scalc/ui/condformatmanager.ui", "CondFormatManager") + , m_bModified(false) + , m_xFormatList( pFormatList ? new ScConditionalFormatList(*pFormatList) : nullptr) + , m_xBtnAdd(m_xBuilder->weld_button("add")) + , m_xBtnRemove(m_xBuilder->weld_button("remove")) + , m_xBtnEdit(m_xBuilder->weld_button("edit")) + , m_xTreeView(m_xBuilder->weld_tree_view("CONTAINER")) + , m_xCtrlManager(new ScCondFormatManagerWindow(*m_xTreeView, rDoc, m_xFormatList.get())) +{ + m_xBtnRemove->connect_clicked(LINK(this, ScCondFormatManagerDlg, RemoveBtnHdl)); + m_xBtnEdit->connect_clicked(LINK(this, ScCondFormatManagerDlg, EditBtnClickHdl)); + m_xBtnAdd->connect_clicked(LINK(this, ScCondFormatManagerDlg, AddBtnHdl)); + m_xTreeView->connect_row_activated(LINK(this, ScCondFormatManagerDlg, EditBtnHdl)); + + SvtViewOptions aDlgOpt(EViewType::Dialog, "CondFormatDialog"); + if (aDlgOpt.Exists()) + m_xDialog->set_window_state(aDlgOpt.GetWindowState().toUtf8()); + + UpdateButtonSensitivity(); +} + +ScCondFormatManagerDlg::~ScCondFormatManagerDlg() +{ + // tdf#101285 - Remember position of dialog + SvtViewOptions aDlgOpt(EViewType::Dialog, "CondFormatDialog"); + OString sWindowState + = m_xDialog->get_window_state(WindowStateMask::Pos); + aDlgOpt.SetWindowState(OUString::fromUtf8(sWindowState)); +} + +std::unique_ptr<ScConditionalFormatList> ScCondFormatManagerDlg::GetConditionalFormatList() +{ + return std::move(m_xFormatList); +} + +void ScCondFormatManagerDlg::UpdateButtonSensitivity() +{ + bool bNewSensitivity = !m_xFormatList->empty(); + m_xBtnRemove->set_sensitive(bNewSensitivity); + m_xBtnEdit->set_sensitive(bNewSensitivity); +} + +// Get the current conditional format selected. +// +ScConditionalFormat* ScCondFormatManagerDlg::GetCondFormatSelected() +{ + return m_xCtrlManager->GetSelection(); +} + +IMPL_LINK_NOARG(ScCondFormatManagerDlg, RemoveBtnHdl, weld::Button&, void) +{ + m_xCtrlManager->DeleteSelection(); + m_bModified = true; + UpdateButtonSensitivity(); +} + +IMPL_LINK_NOARG(ScCondFormatManagerDlg, EditBtnClickHdl, weld::Button&, void) +{ + EditBtnHdl(*m_xTreeView); +} + +IMPL_LINK_NOARG(ScCondFormatManagerDlg, EditBtnHdl, weld::TreeView&, bool) +{ + ScConditionalFormat* pFormat = m_xCtrlManager->GetSelection(); + + if (!pFormat) + return true; + + m_bModified = true; + m_xDialog->response( DLG_RET_EDIT ); + + return true; +} + +IMPL_LINK_NOARG(ScCondFormatManagerDlg, AddBtnHdl, weld::Button&, void) +{ + m_bModified = true; + m_xDialog->response( DLG_RET_ADD ); +} + +void ScCondFormatManagerDlg::SetModified() +{ + m_bModified = true; + UpdateButtonSensitivity(); +} + +bool ScCondFormatManagerDlg::CondFormatsChanged() const +{ + return m_bModified; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |