diff options
Diffstat (limited to 'sc/source/ui/dialogs/SparklineDialog.cxx')
-rw-r--r-- | sc/source/ui/dialogs/SparklineDialog.cxx | 552 |
1 files changed, 552 insertions, 0 deletions
diff --git a/sc/source/ui/dialogs/SparklineDialog.cxx b/sc/source/ui/dialogs/SparklineDialog.cxx new file mode 100644 index 000000000..f27e0eb4a --- /dev/null +++ b/sc/source/ui/dialogs/SparklineDialog.cxx @@ -0,0 +1,552 @@ +/* -*- 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 <SparklineDialog.hxx> +#include <SparklineData.hxx> +#include <SparklineGroup.hxx> +#include <Sparkline.hxx> +#include <reffact.hxx> + +#include <docfunc.hxx> + +#include <svx/colorbox.hxx> +#include <vcl/formatter.hxx> + +namespace sc +{ +SparklineDialog::SparklineDialog(SfxBindings* pBindings, SfxChildWindow* pChildWindow, + weld::Window* pWindow, ScViewData& rViewData) + : ScAnyRefDlgController(pBindings, pChildWindow, pWindow, + u"modules/scalc/ui/sparklinedialog.ui", "SparklineDialog") + , mrViewData(rViewData) + , mrDocument(rViewData.GetDocument()) + , mpActiveEdit(nullptr) + , mbDialogLostFocus(false) + , mxButtonOk(m_xBuilder->weld_button("ok")) + , mxButtonCancel(m_xBuilder->weld_button("cancel")) + , mxFrameData(m_xBuilder->weld_frame("frmData")) + , mxInputRangeLabel(m_xBuilder->weld_label("lbInputRange")) + , mxInputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("edInputRange"))) + , mxInputRangeButton(new formula::RefButton(m_xBuilder->weld_button("btnInputRange"))) + , mxOutputRangeLabel(m_xBuilder->weld_label("lbOutputRange")) + , mxOutputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("edOutputRange"))) + , mxOutputRangeButton(new formula::RefButton(m_xBuilder->weld_button("btnOutputRange"))) + , mxColorSeries(new ColorListBox(m_xBuilder->weld_menu_button("colSeries"), + [pWindow] { return pWindow; })) + , mxColorNegative(new ColorListBox(m_xBuilder->weld_menu_button("colNegative"), + [pWindow] { return pWindow; })) + , mxColorMarker(new ColorListBox(m_xBuilder->weld_menu_button("colMarker"), + [pWindow] { return pWindow; })) + , mxColorHigh( + new ColorListBox(m_xBuilder->weld_menu_button("colHigh"), [pWindow] { return pWindow; })) + , mxColorLow( + new ColorListBox(m_xBuilder->weld_menu_button("colLow"), [pWindow] { return pWindow; })) + , mxColorFirst( + new ColorListBox(m_xBuilder->weld_menu_button("colFirst"), [pWindow] { return pWindow; })) + , mxColorLast( + new ColorListBox(m_xBuilder->weld_menu_button("colLast"), [pWindow] { return pWindow; })) + , mxCheckButtonNegative(m_xBuilder->weld_check_button("cbNegative")) + , mxCheckButtonMarker(m_xBuilder->weld_check_button("cbMarker")) + , mxCheckButtonHigh(m_xBuilder->weld_check_button("cbHigh")) + , mxCheckButtonLow(m_xBuilder->weld_check_button("cbLow")) + , mxCheckButtonFirst(m_xBuilder->weld_check_button("cbFirst")) + , mxCheckButtonLast(m_xBuilder->weld_check_button("cbLast")) + , mxSpinLineWidth(m_xBuilder->weld_spin_button("seLineWidth")) + , mxType(m_xBuilder->weld_combo_box("cbType")) + , mxCheckDisplayXAxis(m_xBuilder->weld_check_button("cbDisplayXAxis")) + , mxCheckDisplayHidden(m_xBuilder->weld_check_button("cbHidden")) + , mxCheckRightToLeft(m_xBuilder->weld_check_button("cbRTL")) + , mxDisplayEmptyGap(m_xBuilder->weld_combo_box("cbEmptyCells")) + , mxComboMinAxisType(m_xBuilder->weld_combo_box("cbMinAxisType")) + , mxComboMaxAxisType(m_xBuilder->weld_combo_box("cbMaxAxisType")) + , mxSpinCustomMin(m_xBuilder->weld_formatted_spin_button("seMinAxis")) + , mxSpinCustomMax(m_xBuilder->weld_formatted_spin_button("seMaxAxis")) + , mbEditMode(false) +{ + mxInputRangeEdit->SetReferences(this, mxInputRangeLabel.get()); + mxInputRangeButton->SetReferences(this, mxInputRangeEdit.get()); + + mxOutputRangeEdit->SetReferences(this, mxOutputRangeLabel.get()); + mxOutputRangeButton->SetReferences(this, mxOutputRangeEdit.get()); + + mxButtonCancel->connect_clicked(LINK(this, SparklineDialog, ButtonClicked)); + mxButtonOk->connect_clicked(LINK(this, SparklineDialog, ButtonClicked)); + mxButtonOk->set_sensitive(false); + + Link<formula::RefEdit&, void> aEditLink = LINK(this, SparklineDialog, EditFocusHandler); + mxInputRangeEdit->SetGetFocusHdl(aEditLink); + mxOutputRangeEdit->SetGetFocusHdl(aEditLink); + aEditLink = LINK(this, SparklineDialog, LoseEditFocusHandler); + mxInputRangeEdit->SetLoseFocusHdl(aEditLink); + mxOutputRangeEdit->SetLoseFocusHdl(aEditLink); + + Link<formula::RefButton&, void> aButtonLink = LINK(this, SparklineDialog, ButtonFocusHandler); + mxInputRangeButton->SetGetFocusHdl(aButtonLink); + mxOutputRangeButton->SetGetFocusHdl(aButtonLink); + aButtonLink = LINK(this, SparklineDialog, LoseButtonFocusHandler); + mxInputRangeButton->SetLoseFocusHdl(aButtonLink); + mxOutputRangeButton->SetLoseFocusHdl(aButtonLink); + + Link<formula::RefEdit&, void> aModifyLink = LINK(this, SparklineDialog, RefInputModifyHandler); + mxInputRangeEdit->SetModifyHdl(aModifyLink); + mxOutputRangeEdit->SetModifyHdl(aModifyLink); + + mxType->connect_changed(LINK(this, SparklineDialog, SelectSparklineType)); + mxDisplayEmptyGap->connect_changed(LINK(this, SparklineDialog, SelectSparklineType)); + + Link<weld::Toggleable&, void> aLink = LINK(this, SparklineDialog, ToggleHandler); + mxCheckButtonNegative->connect_toggled(aLink); + mxCheckButtonMarker->connect_toggled(aLink); + mxCheckButtonHigh->connect_toggled(aLink); + mxCheckButtonLow->connect_toggled(aLink); + mxCheckButtonFirst->connect_toggled(aLink); + mxCheckButtonLast->connect_toggled(aLink); + mxCheckDisplayXAxis->connect_toggled(aLink); + mxCheckDisplayHidden->connect_toggled(aLink); + mxCheckRightToLeft->connect_toggled(aLink); + + mxSpinLineWidth->connect_value_changed(LINK(this, SparklineDialog, SpinLineWidthChanged)); + + mxComboMinAxisType->connect_changed(LINK(this, SparklineDialog, ComboValueChanged)); + mxComboMaxAxisType->connect_changed(LINK(this, SparklineDialog, ComboValueChanged)); + + mxSpinCustomMin->connect_value_changed(LINK(this, SparklineDialog, SpinCustomChanged)); + Formatter& rSpinCustomMinFormatter = mxSpinCustomMin->GetFormatter(); + rSpinCustomMinFormatter.ClearMinValue(); + rSpinCustomMinFormatter.ClearMaxValue(); + rSpinCustomMinFormatter.UseInputStringForFormatting(); + + mxSpinCustomMax->connect_value_changed(LINK(this, SparklineDialog, SpinCustomChanged)); + Formatter& rSpinCustomMaxFormatter = mxSpinCustomMax->GetFormatter(); + rSpinCustomMaxFormatter.ClearMinValue(); + rSpinCustomMaxFormatter.ClearMaxValue(); + rSpinCustomMaxFormatter.UseInputStringForFormatting(); + + setupValues(); + + mxOutputRangeEdit->GrabFocus(); + mxButtonOk->set_sensitive(checkValidInputOutput()); +} + +SparklineDialog::~SparklineDialog() = default; + +void SparklineDialog::setInputSelection() +{ + mrViewData.GetSimpleArea(maInputRange); + OUString aString = maInputRange.Format(mrDocument, ScRefFlags::VALID | ScRefFlags::TAB_3D, + mrDocument.GetAddressConvention()); + mxInputRangeEdit->SetRefString(aString); +} + +void SparklineDialog::setupValues() +{ + ScRange aSelectionRange; + mrViewData.GetSimpleArea(aSelectionRange); + + if (mrDocument.HasOneSparklineGroup(aSelectionRange)) + { + if (auto pSparkline = mrDocument.GetSparkline(aSelectionRange.aStart)) + { + mpSparklineGroup = pSparkline->getSparklineGroup(); + maAttributes = mpSparklineGroup->getAttributes(); + mxFrameData->set_visible(false); + mbEditMode = true; + } + } + else + { + maInputRange = aSelectionRange; + } + + setInputSelection(); + + switch (maAttributes.getType()) + { + case sc::SparklineType::Line: + mxType->set_active(0); + break; + case sc::SparklineType::Column: + mxType->set_active(1); + break; + case sc::SparklineType::Stacked: + mxType->set_active(2); + break; + } + + switch (maAttributes.getDisplayEmptyCellsAs()) + { + case sc::DisplayEmptyCellsAs::Gap: + mxDisplayEmptyGap->set_active(0); + break; + case sc::DisplayEmptyCellsAs::Zero: + mxDisplayEmptyGap->set_active(1); + break; + case sc::DisplayEmptyCellsAs::Span: + mxDisplayEmptyGap->set_active(2); + break; + } + + mxColorSeries->SelectEntry(maAttributes.getColorSeries()); + mxColorNegative->SelectEntry(maAttributes.getColorNegative()); + mxColorMarker->SelectEntry(maAttributes.getColorMarkers()); + mxColorHigh->SelectEntry(maAttributes.getColorHigh()); + mxColorLow->SelectEntry(maAttributes.getColorLow()); + mxColorFirst->SelectEntry(maAttributes.getColorFirst()); + mxColorLast->SelectEntry(maAttributes.getColorLast()); + + mxCheckButtonNegative->set_active(maAttributes.isNegative()); + mxCheckButtonMarker->set_active(maAttributes.isMarkers()); + mxCheckButtonHigh->set_active(maAttributes.isHigh()); + mxCheckButtonLow->set_active(maAttributes.isLow()); + mxCheckButtonFirst->set_active(maAttributes.isFirst()); + mxCheckButtonLast->set_active(maAttributes.isLast()); + + mxSpinLineWidth->set_value(sal_Int64(maAttributes.getLineWeight() * 100.0)); + + mxCheckDisplayXAxis->set_active(maAttributes.shouldDisplayXAxis()); + mxCheckDisplayHidden->set_active(maAttributes.shouldDisplayHidden()); + mxCheckRightToLeft->set_active(maAttributes.isRightToLeft()); + + switch (maAttributes.getMinAxisType()) + { + case sc::AxisType::Individual: + mxComboMinAxisType->set_active(0); + mxSpinCustomMin->GetFormatter().SetValue(0.0); + break; + case sc::AxisType::Group: + mxComboMinAxisType->set_active(1); + mxSpinCustomMin->GetFormatter().SetValue(0.0); + break; + case sc::AxisType::Custom: + mxComboMinAxisType->set_active(2); + if (maAttributes.getManualMin()) + mxSpinCustomMin->GetFormatter().SetValue(*maAttributes.getManualMin()); + break; + } + ComboValueChanged(*mxComboMinAxisType); + + switch (maAttributes.getMaxAxisType()) + { + case sc::AxisType::Individual: + mxComboMaxAxisType->set_active(0); + mxSpinCustomMax->GetFormatter().SetValue(0.0); + break; + case sc::AxisType::Group: + mxComboMaxAxisType->set_active(1); + mxSpinCustomMax->GetFormatter().SetValue(0.0); + break; + case sc::AxisType::Custom: + mxComboMaxAxisType->set_active(2); + if (maAttributes.getManualMax()) + mxSpinCustomMax->GetFormatter().SetValue(*maAttributes.getManualMax()); + break; + } + ComboValueChanged(*mxComboMaxAxisType); +} + +void SparklineDialog::Close() { DoClose(sc::SparklineDialogWrapper::GetChildWindowId()); } + +void SparklineDialog::SetActive() +{ + if (mbDialogLostFocus) + { + mbDialogLostFocus = false; + if (mpActiveEdit) + mpActiveEdit->GrabFocus(); + } + else + { + m_xDialog->grab_focus(); + } + RefInputDone(); +} + +void SparklineDialog::SetReference(const ScRange& rReferenceRange, ScDocument& rDocument) +{ + if (mpActiveEdit) + { + if (rReferenceRange.aStart != rReferenceRange.aEnd) + RefInputStart(mpActiveEdit); + + OUString aString; + const ScRefFlags eFlags = ScRefFlags::VALID | ScRefFlags::TAB_3D; + auto eAddressConvention = rDocument.GetAddressConvention(); + + if (mpActiveEdit == mxInputRangeEdit.get()) + { + maInputRange = rReferenceRange; + aString = maInputRange.Format(rDocument, eFlags, eAddressConvention); + mxInputRangeEdit->SetRefString(aString); + } + else if (mpActiveEdit == mxOutputRangeEdit.get()) + { + maOutputRange = rReferenceRange; + aString = maOutputRange.Format(rDocument, eFlags, eAddressConvention); + mxOutputRangeEdit->SetRefString(aString); + } + } + + mxButtonOk->set_sensitive(checkValidInputOutput()); +} + +IMPL_LINK(SparklineDialog, EditFocusHandler, formula::RefEdit&, rEdit, void) +{ + auto* pEdit = &rEdit; + + if (mxInputRangeEdit.get() == pEdit) + mpActiveEdit = mxInputRangeEdit.get(); + else if (mxOutputRangeEdit.get() == pEdit) + mpActiveEdit = mxOutputRangeEdit.get(); + else + mpActiveEdit = nullptr; + + if (mpActiveEdit) + mpActiveEdit->SelectAll(); +} + +IMPL_LINK(SparklineDialog, ButtonFocusHandler, formula::RefButton&, rButton, void) +{ + auto* pButton = &rButton; + + if (mxInputRangeButton.get() == pButton) + mpActiveEdit = mxInputRangeEdit.get(); + else if (mxOutputRangeButton.get() == pButton) + mpActiveEdit = mxOutputRangeEdit.get(); + else + mpActiveEdit = nullptr; + + if (mpActiveEdit) + mpActiveEdit->SelectAll(); +} + +IMPL_LINK_NOARG(SparklineDialog, LoseEditFocusHandler, formula::RefEdit&, void) +{ + mbDialogLostFocus = !m_xDialog->has_toplevel_focus(); +} + +IMPL_LINK_NOARG(SparklineDialog, LoseButtonFocusHandler, formula::RefButton&, void) +{ + mbDialogLostFocus = !m_xDialog->has_toplevel_focus(); +} + +IMPL_LINK_NOARG(SparklineDialog, RefInputModifyHandler, formula::RefEdit&, void) +{ + if (mpActiveEdit) + { + if (mpActiveEdit == mxInputRangeEdit.get()) + { + ScRangeList aRangeList; + bool bValid = ParseWithNames(aRangeList, mxInputRangeEdit->GetText(), mrDocument); + const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr; + if (pRange) + { + maInputRange = *pRange; + mxInputRangeEdit->StartUpdateData(); + } + else + { + maInputRange = ScRange(ScAddress::INITIALIZE_INVALID); + } + } + else if (mpActiveEdit == mxOutputRangeEdit.get()) + { + ScRangeList aRangeList; + bool bValid = ParseWithNames(aRangeList, mxOutputRangeEdit->GetText(), mrDocument); + const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr; + if (pRange) + { + maOutputRange = *pRange; + mxOutputRangeEdit->StartUpdateData(); + } + else + { + maOutputRange = ScRange(ScAddress::INITIALIZE_INVALID); + } + } + } + + mxButtonOk->set_sensitive(checkValidInputOutput()); +} + +IMPL_LINK(SparklineDialog, ButtonClicked, weld::Button&, rButton, void) +{ + if (mxButtonOk.get() == &rButton) + { + perform(); + response(RET_OK); + } + else + { + response(RET_CANCEL); + } +} + +IMPL_LINK(SparklineDialog, ToggleHandler, weld::Toggleable&, rToggle, void) +{ + if (mxCheckButtonNegative.get() == &rToggle) + maAttributes.setNegative(mxCheckButtonNegative->get_active()); + if (mxCheckButtonMarker.get() == &rToggle) + maAttributes.setMarkers(mxCheckButtonMarker->get_active()); + if (mxCheckButtonHigh.get() == &rToggle) + maAttributes.setHigh(mxCheckButtonHigh->get_active()); + if (mxCheckButtonLow.get() == &rToggle) + maAttributes.setLow(mxCheckButtonLow->get_active()); + if (mxCheckButtonFirst.get() == &rToggle) + maAttributes.setFirst(mxCheckButtonFirst->get_active()); + if (mxCheckButtonLast.get() == &rToggle) + maAttributes.setLast(mxCheckButtonLast->get_active()); + if (mxCheckDisplayXAxis.get() == &rToggle) + maAttributes.setDisplayXAxis(mxCheckDisplayXAxis->get_active()); + if (mxCheckDisplayHidden.get() == &rToggle) + maAttributes.setDisplayHidden(mxCheckDisplayHidden->get_active()); + if (mxCheckRightToLeft.get() == &rToggle) + maAttributes.setRightToLeft(mxCheckRightToLeft->get_active()); +} + +IMPL_LINK_NOARG(SparklineDialog, SelectSparklineType, weld::ComboBox&, void) +{ + switch (mxType->get_active()) + { + case 0: + maAttributes.setType(sc::SparklineType::Line); + break; + case 1: + maAttributes.setType(sc::SparklineType::Column); + break; + case 2: + maAttributes.setType(sc::SparklineType::Stacked); + break; + } + switch (mxDisplayEmptyGap->get_active()) + { + case 1: + maAttributes.setDisplayEmptyCellsAs(sc::DisplayEmptyCellsAs::Gap); + break; + case 2: + maAttributes.setDisplayEmptyCellsAs(sc::DisplayEmptyCellsAs::Zero); + break; + case 3: + maAttributes.setDisplayEmptyCellsAs(sc::DisplayEmptyCellsAs::Span); + break; + } +} + +IMPL_LINK_NOARG(SparklineDialog, SpinLineWidthChanged, weld::SpinButton&, void) +{ + double value = mxSpinLineWidth->get_value() / 100.0; + maAttributes.setLineWeight(value); +} + +IMPL_LINK(SparklineDialog, SpinCustomChanged, weld::FormattedSpinButton&, rFormatted, void) +{ + if (mxSpinCustomMin.get() == &rFormatted) + { + maAttributes.setManualMin(rFormatted.GetFormatter().GetValue()); + } + else if (mxSpinCustomMax.get() == &rFormatted) + { + maAttributes.setManualMax(rFormatted.GetFormatter().GetValue()); + } +} + +IMPL_LINK(SparklineDialog, ComboValueChanged, weld::ComboBox&, rComboBox, void) +{ + int nActive = rComboBox.get_active(); + + if (mxComboMinAxisType.get() == &rComboBox) + { + switch (nActive) + { + case 0: + maAttributes.setMinAxisType(sc::AxisType::Individual); + mxSpinCustomMin->set_sensitive(false); + break; + case 1: + maAttributes.setMinAxisType(sc::AxisType::Group); + mxSpinCustomMin->set_sensitive(false); + break; + case 2: + maAttributes.setMinAxisType(sc::AxisType::Custom); + mxSpinCustomMin->set_sensitive(true); + break; + default: + break; + } + } + else if (mxComboMaxAxisType.get() == &rComboBox) + { + switch (nActive) + { + case 0: + maAttributes.setMaxAxisType(sc::AxisType::Individual); + mxSpinCustomMax->set_sensitive(false); + break; + case 1: + maAttributes.setMaxAxisType(sc::AxisType::Group); + mxSpinCustomMax->set_sensitive(false); + break; + case 2: + maAttributes.setMaxAxisType(sc::AxisType::Custom); + mxSpinCustomMax->set_sensitive(true); + break; + default: + break; + } + } +} + +bool SparklineDialog::checkValidInputOutput() +{ + if (mbEditMode) + return true; + + if (!maInputRange.IsValid() || !maOutputRange.IsValid()) + return false; + + sc::RangeOrientation eInputOrientation = sc::RangeOrientation::Unknown; + if (maOutputRange.aStart.Col() == maOutputRange.aEnd.Col()) + { + sal_Int32 nOutputRowSize = maOutputRange.aEnd.Row() - maOutputRange.aStart.Row(); + eInputOrientation = sc::calculateOrientation(nOutputRowSize, maInputRange); + } + else if (maOutputRange.aStart.Row() == maOutputRange.aEnd.Row()) + { + sal_Int32 nOutputColSize = maOutputRange.aEnd.Col() - maOutputRange.aStart.Col(); + eInputOrientation = sc::calculateOrientation(nOutputColSize, maInputRange); + } + + return eInputOrientation != sc::RangeOrientation::Unknown; +} + +void SparklineDialog::perform() +{ + maAttributes.setColorSeries(mxColorSeries->GetSelectEntryColor()); + maAttributes.setColorNegative(mxColorNegative->GetSelectEntryColor()); + maAttributes.setColorMarkers(mxColorMarker->GetSelectEntryColor()); + maAttributes.setColorHigh(mxColorHigh->GetSelectEntryColor()); + maAttributes.setColorLow(mxColorLow->GetSelectEntryColor()); + maAttributes.setColorFirst(mxColorFirst->GetSelectEntryColor()); + maAttributes.setColorLast(mxColorLast->GetSelectEntryColor()); + + auto& rDocFunc = mrViewData.GetDocShell()->GetDocFunc(); + + if (mpSparklineGroup) + { + rDocFunc.ChangeSparklineGroupAttributes(mpSparklineGroup, maAttributes); + } + else + { + auto pNewSparklineGroup = std::make_shared<sc::SparklineGroup>(maAttributes); + rDocFunc.InsertSparklines(maInputRange, maOutputRange, pNewSparklineGroup); + } +} + +} // end sc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |