summaryrefslogtreecommitdiff
path: root/sc/source/ui/dialogs
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2022-03-11 20:49:09 +0900
committerTomaž Vajngerl <quikee@gmail.com>2022-04-03 09:06:44 +0200
commitc61aa2dea120cc083f3cd51f0347284f47a9d566 (patch)
tree169305bd5f4fac8792c0b6bdda8c3a1514c755a3 /sc/source/ui/dialogs
parentca5f7efcd92c8bdf36bf64f0c78fd2e112206cfc (diff)
sc: SparklineDialog and "Insert Sparkline" to context menu
This adds a SparklineDialog, which is used to add/edit the Sparkline input/output ranges. The command for the context menu "Insert Sparkline" calls the SparklineDialog for inserting a new sparkline into cells. Currently the SparklineDialog include the properties for the SparklineGroup, which will be added in a later commit. Change-Id: I9036d788fdf2a035f1ce10fc7413327a92144137 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132465 Tested-by: Tomaž Vajngerl <quikee@gmail.com> Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'sc/source/ui/dialogs')
-rw-r--r--sc/source/ui/dialogs/SparklineDialog.cxx324
1 files changed, 324 insertions, 0 deletions
diff --git a/sc/source/ui/dialogs/SparklineDialog.cxx b/sc/source/ui/dialogs/SparklineDialog.cxx
new file mode 100644
index 000000000000..5a167fe8b7c1
--- /dev/null
+++ b/sc/source/ui/dialogs/SparklineDialog.cxx
@@ -0,0 +1,324 @@
+/* -*- 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 <SparklineGroup.hxx>
+#include <Sparkline.hxx>
+#include <reffact.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"))
+ , mxInputRangeText(m_xBuilder->weld_label("cell-range-label"))
+ , mxInputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("cell-range-edit")))
+ , mxInputRangeButton(new formula::RefButton(m_xBuilder->weld_button("cell-range-button")))
+ , mxOutputRangeLabel(m_xBuilder->weld_label("output-range-label"))
+ , mxOutputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("output-range-edit")))
+ , mxOutputRangeButton(new formula::RefButton(m_xBuilder->weld_button("output-range-button")))
+{
+ mxInputRangeEdit->SetReferences(this, mxInputRangeText.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);
+
+ mxOutputRangeEdit->GrabFocus();
+
+ GetRangeFromSelection();
+}
+
+SparklineDialog::~SparklineDialog() {}
+
+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::GetRangeFromSelection()
+{
+ mrViewData.GetSimpleArea(maInputRange);
+ OUString aString = maInputRange.Format(mrDocument, ScRefFlags::VALID | ScRefFlags::TAB_3D,
+ mrDocument.GetAddressConvention());
+ mxInputRangeEdit->SetRefString(aString);
+}
+
+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);
+ }
+}
+
+namespace
+{
+enum class RangeOrientation
+{
+ Unknown,
+ Row,
+ Col
+};
+
+RangeOrientation calculateOrientation(sal_Int32 nOutputSize, ScRange const& rInputRange)
+{
+ sal_Int32 nRowSize = rInputRange.aEnd.Row() - rInputRange.aStart.Row();
+ sal_Int32 nColSize = rInputRange.aEnd.Col() - rInputRange.aStart.Col();
+
+ auto eInputOrientation = RangeOrientation::Unknown;
+ if (nOutputSize == nRowSize)
+ eInputOrientation = RangeOrientation::Row;
+ else if (nOutputSize == nColSize)
+ eInputOrientation = RangeOrientation::Col;
+ return eInputOrientation;
+}
+
+} // end anonymous namespace
+
+bool SparklineDialog::checkValidInputOutput()
+{
+ if (!maInputRange.IsValid() || !maOutputRange.IsValid())
+ return false;
+
+ RangeOrientation eInputOrientation = RangeOrientation::Unknown;
+ if (maOutputRange.aStart.Col() == maOutputRange.aEnd.Col())
+ {
+ sal_Int32 nOutputRowSize = maOutputRange.aEnd.Row() - maOutputRange.aStart.Row();
+ eInputOrientation = calculateOrientation(nOutputRowSize, maInputRange);
+ }
+ else if (maOutputRange.aStart.Row() == maOutputRange.aEnd.Row())
+ {
+ sal_Int32 nOutputColSize = maOutputRange.aEnd.Col() - maOutputRange.aStart.Col();
+ eInputOrientation = calculateOrientation(nOutputColSize, maInputRange);
+ }
+
+ return eInputOrientation != RangeOrientation::Unknown;
+}
+
+void SparklineDialog::perform()
+{
+ auto pSparklineGroup = std::make_shared<sc::SparklineGroup>();
+
+ if (maOutputRange.aStart.Col() == maOutputRange.aEnd.Col())
+ {
+ sal_Int32 nOutputRowSize = maOutputRange.aEnd.Row() - maOutputRange.aStart.Row();
+
+ auto eInputOrientation = calculateOrientation(nOutputRowSize, maInputRange);
+
+ if (eInputOrientation == RangeOrientation::Unknown)
+ return;
+
+ sal_Int32 nIndex = 0;
+ for (ScAddress aAddress = maOutputRange.aStart; aAddress.Row() <= maOutputRange.aEnd.Row();
+ aAddress.IncRow())
+ {
+ ScRange aInputRangeSlice = maInputRange;
+ if (eInputOrientation == RangeOrientation::Row)
+ {
+ aInputRangeSlice.aStart.SetRow(maInputRange.aStart.Row() + nIndex);
+ aInputRangeSlice.aEnd.SetRow(maInputRange.aStart.Row() + nIndex);
+ }
+ else
+ {
+ aInputRangeSlice.aStart.SetCol(maInputRange.aStart.Col() + nIndex);
+ aInputRangeSlice.aEnd.SetCol(maInputRange.aStart.Col() + nIndex);
+ }
+ auto* pCreated = mrDocument.CreateSparkline(aAddress, pSparklineGroup);
+ pCreated->setInputRange(aInputRangeSlice);
+ nIndex++;
+ }
+ }
+ else if (maOutputRange.aStart.Row() == maOutputRange.aEnd.Row())
+ {
+ sal_Int32 nOutputColSize = maOutputRange.aEnd.Col() - maOutputRange.aStart.Col();
+
+ auto eInputOrientation = calculateOrientation(nOutputColSize, maInputRange);
+
+ if (eInputOrientation == RangeOrientation::Unknown)
+ return;
+
+ sal_Int32 nIndex = 0;
+
+ for (ScAddress aAddress = maOutputRange.aStart; aAddress.Col() <= maOutputRange.aEnd.Col();
+ aAddress.IncCol())
+ {
+ ScRange aInputRangeSlice = maInputRange;
+ if (eInputOrientation == RangeOrientation::Row)
+ {
+ aInputRangeSlice.aStart.SetRow(maInputRange.aStart.Row() + nIndex);
+ aInputRangeSlice.aEnd.SetRow(maInputRange.aStart.Row() + nIndex);
+ }
+ else
+ {
+ aInputRangeSlice.aStart.SetCol(maInputRange.aStart.Col() + nIndex);
+ aInputRangeSlice.aEnd.SetCol(maInputRange.aStart.Col() + nIndex);
+ }
+ auto* pCreated = mrDocument.CreateSparkline(aAddress, pSparklineGroup);
+ pCreated->setInputRange(aInputRangeSlice);
+ nIndex++;
+ }
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */