include/svl/hint.hxx                                              |    1 
 officecfg/registry/data/org/openoffice/Office/UI/MathCommands.xcu |    8 
 officecfg/registry/schema/org/openoffice/Office/Math.xcs          |   15 +
 starmath/inc/ElementsDockingWindow.hxx                            |   12 +
 starmath/inc/cfgitem.hxx                                          |    7 
 starmath/inc/starmath.hrc                                         |    1 
 starmath/inc/strings.hrc                                          |    3 
 starmath/sdi/smath.sdi                                            |   17 +
 starmath/sdi/smslots.sdi                                          |    5 
 starmath/source/ElementsDockingWindow.cxx                         |   87 
+++++++---
 starmath/source/SmElementsPanel.cxx                               |   22 ++
 starmath/source/SmElementsPanel.hxx                               |    6 
 starmath/source/cfgitem.cxx                                       |   44 ++++-
 starmath/source/view.cxx                                          |   38 ++++
 starmath/uiconfig/smath/menubar/menubar.xml                       |    1 
 starmath/uiconfig/smath/popupmenu/edit.xml                        |    1 
 starmath/uiconfig/smath/ui/sidebarelements_math.ui                |   12 +
 17 files changed, 253 insertions(+), 27 deletions(-)

New commits:
commit f395e6599facba41392eac3d646a0d505868e6fa
Author:     Heiko Tietze <[email protected]>
AuthorDate: Tue Nov 19 18:04:04 2024 +0100
Commit:     Heiko Tietze <[email protected]>
CommitDate: Tue Nov 26 13:56:48 2024 +0100

    Resolves tdf#163685 - Save user-defined formula
    
    Change-Id: I88a1c40d3e97d77c289c8b670b52dca50dea126f
    Co-authored-by: Rafael Lima <[email protected]>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176788
    Reviewed-by: Rafael Lima <[email protected]>
    Tested-by: Jenkins

diff --git a/include/svl/hint.hxx b/include/svl/hint.hxx
index 7fb28c5588de..894bdeec6786 100644
--- a/include/svl/hint.hxx
+++ b/include/svl/hint.hxx
@@ -156,6 +156,7 @@ enum class SfxHintId {
 
 // STARMATH
     MathFormatChanged,
+    SmNewUserFormula,
 
 // Sw
     SwDrawViewsCreated,
diff --git a/officecfg/registry/data/org/openoffice/Office/UI/MathCommands.xcu 
b/officecfg/registry/data/org/openoffice/Office/UI/MathCommands.xcu
index b8bade9b3e4f..f760d782e23b 100644
--- a/officecfg/registry/data/org/openoffice/Office/UI/MathCommands.xcu
+++ b/officecfg/registry/data/org/openoffice/Office/UI/MathCommands.xcu
@@ -161,6 +161,14 @@
           <value xml:lang="en-US">Gap</value>
         </prop>
       </node>
+      <node oor:name=".uno:SaveFormula" oor:op="replace">
+        <prop oor:name="Label" oor:type="xs:string">
+          <value xml:lang="en-US">Save as User-defined Formula</value>
+        </prop>
+        <prop oor:name="Properties" oor:type="xs:int">
+          <value>1</value>
+        </prop>
+      </node>
     </node>
     <node oor:name="Popups">
       <node oor:name=".uno:UnaryBinaryMenu" oor:op="replace">
diff --git a/officecfg/registry/schema/org/openoffice/Office/Math.xcs 
b/officecfg/registry/schema/org/openoffice/Office/Math.xcs
index b7eb0f358df8..83563268a64d 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Math.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Math.xcs
@@ -216,6 +216,16 @@
         </info>
       </prop>
     </group>
+    <group oor:name="Formula">
+      <info>
+        <desc>Contains user-defined formulas.</desc>
+      </info>
+      <prop oor:name="FormulaText" oor:type="xs:string">
+        <info>
+          <desc>Specifies the formula.</desc>
+        </info>
+      </prop>
+    </group>
   </templates>
   <component>
     <group oor:name="Print">
@@ -1036,5 +1046,10 @@
         <desc>Lists the defined symbols.</desc>
       </info>
     </set>
+    <set oor:name="User-Defined" oor:node-type="Formula">
+      <info>
+        <desc>List of user-defined formulas.</desc>
+      </info>
+    </set>
   </component>
 </oor:component-schema>
diff --git a/starmath/inc/ElementsDockingWindow.hxx 
b/starmath/inc/ElementsDockingWindow.hxx
index 971c2f3b6fb2..2e48afd10fdf 100644
--- a/starmath/inc/ElementsDockingWindow.hxx
+++ b/starmath/inc/ElementsDockingWindow.hxx
@@ -42,9 +42,12 @@ class SmElementsControl
     SmFormat      maFormat;
     int           mnCurrentSetIndex;
     sal_Int16     m_nSmSyntaxVersion;
+    bool          m_bAllowDelete;
+    OUString      m_sHoveredItem;
 
     std::vector<std::unique_ptr<ElementData>> maItemDatas;
     std::unique_ptr<weld::IconView> mpIconView;
+    std::unique_ptr<weld::Menu> mxPopup;
 
     Link<const OUString&, void> maSelectHdlLink;
 
@@ -55,22 +58,27 @@ class SmElementsControl
 
     DECL_LINK(QueryTooltipHandler, const weld::TreeIter&, OUString);
     DECL_LINK(ElementActivatedHandler, weld::IconView&, bool);
+    DECL_LINK(MousePressHdl, const MouseEvent&, bool);
 
     static OUString GetElementSource(const OUString& itemId);
     static OUString GetElementHelpText(const OUString& itemId);
+    static int GetElementPos(const OUString& itemId);
 
 public:
 
-    explicit SmElementsControl(std::unique_ptr<weld::IconView> pIconView);
+    explicit SmElementsControl(std::unique_ptr<weld::IconView> pIconView,
+                               std::unique_ptr<weld::Menu> pMenu);
     ~SmElementsControl();
 
     static const std::vector<TranslateId>& categories();
-    void setElementSetIndex(int nSetIndex);
+    void setElementSetIndex(int nSetIndex, bool bForceBuild = false);
 
     void setSmSyntaxVersion(sal_Int16 nSmSyntaxVersion);
 
     void SetSelectHdl(const Link<const OUString&, void>& rLink) { 
maSelectHdlLink = rLink; }
 
+    void SetAllowDelete(bool bAllow) { m_bAllowDelete = bAllow; }
+
     static Color GetTextColor();
     static Color GetControlBackground();
 };
diff --git a/starmath/inc/cfgitem.hxx b/starmath/inc/cfgitem.hxx
index 08a6e834f1fd..dbd477de9e7a 100644
--- a/starmath/inc/cfgitem.hxx
+++ b/starmath/inc/cfgitem.hxx
@@ -100,6 +100,7 @@ class SmMathConfig final : public utl::ConfigItem, public 
SfxBroadcaster
     std::unique_ptr<SmCfgOther> pOther;
     std::unique_ptr<SmFontFormatList> pFontFormatList;
     std::unique_ptr<SmSymbolManager> pSymbolMgr;
+    css::uno::Sequence<OUString> m_sUserDefinedNames;
     bool bIsOtherModified;
     bool bIsFormatModified;
     SmFontPickList vFontPickList[8];
@@ -169,6 +170,12 @@ public:
     const SmFormat& GetStandardFormat() const;
     void SetStandardFormat(const SmFormat& rFormat, bool bSaveFontFormatList = 
false);
 
+    css::uno::Sequence<OUString> LoadUserDefinedNames();
+    void GetUserDefinedFormula(std::u16string_view sName, OUString& sFormula);
+    bool HasUserDefinedFormula(std::u16string_view sName);
+    void SaveUserDefinedFormula(std::u16string_view sName, const OUString& 
sElement);
+    void DeleteUserDefinedFormula(std::u16string_view sName);
+
     bool IsPrintTitle() const;
     void SetPrintTitle(bool bVal);
     bool IsPrintFormulaText() const;
diff --git a/starmath/inc/starmath.hrc b/starmath/inc/starmath.hrc
index 1127e6660cbd..468fd444cbfa 100644
--- a/starmath/inc/starmath.hrc
+++ b/starmath/inc/starmath.hrc
@@ -74,5 +74,6 @@ class SfxUInt16Item;
 #define SID_SMEDITWINDOWZOOM        TypedWhichId<SfxUInt16Item>(SID_SMA_START 
+ 129)
 #define SID_DEFAULT_SM_SYNTAX_VERSION 
TypedWhichId<SfxUInt16Item>(SID_SMA_START + 130)
 #define SID_INLINE_EDIT_ENABLE      TypedWhichId<SfxBoolItem>(SID_SMA_START + 
131)
+#define SID_SAVE_FORMULA            (SID_SMA_START + 132)
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/starmath/inc/strings.hrc b/starmath/inc/strings.hrc
index 4afb0d2598e6..8f891439e5ab 100644
--- a/starmath/inc/strings.hrc
+++ b/starmath/inc/strings.hrc
@@ -324,6 +324,7 @@
 #define RID_CATEGORY_FORMATS                NC_("RID_CATEGORY_FORMATS", 
"Formats" )
 #define RID_CATEGORY_OTHERS                 NC_("RID_CATEGORY_OTHERS", 
"Others" )
 #define RID_CATEGORY_EXAMPLES               NC_("RID_CATEGORY_EXAMPLES", 
"Examples" )
+#define RID_CATEGORY_USERDEFINED            NC_("RID_CATEGORY_USERDEFINED", 
"User-defined" )
 
 #define RID_EXAMPLE_CIRCUMFERENCE_HELP      
NC_("RID_EXAMPLE_CIRCUMFERENCE_HELP", "Circumference" )
 #define RID_EXAMPLE_MASS_ENERGY_EQUIV_HELP  
NC_("RID_EXAMPLE_MASS_ENERGY_EQUIV_HELP", "Mass–energy equivalence" )
@@ -406,6 +407,8 @@
 #define RID_PRINTUIOPT_ORIGSIZE             NC_("RID_PRINTUIOPT_ORIGSIZE", 
"O~riginal size" )
 #define RID_PRINTUIOPT_FITTOPAGE            NC_("RID_PRINTUIOPT_FITTOPAGE", 
"Fit to ~page" )
 #define RID_PRINTUIOPT_SCALING              NC_("RID_PRINTUIOPT_SCALING", 
"~Scaling" )
+#define STR_USER_DEFINED_FORMULA            NC_("STR_USER_DEFINED_FORMULA", 
"Save formula as:" )
+#define STR_USER_DEFINED_FORMULA_EXISTS     
NC_("STR_USER_DEFINED_FORMULA_EXISTS", "The Formula %1 exists.
Do you want to overwrite?" )
 // clang-format on
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/starmath/sdi/smath.sdi b/starmath/sdi/smath.sdi
index 48045629ecd7..f1578010d0a1 100644
--- a/starmath/sdi/smath.sdi
+++ b/starmath/sdi/smath.sdi
@@ -562,3 +562,20 @@ SfxVoidItem ZoomOut SID_ZOOMOUT
     ToolBoxConfig = TRUE,
     GroupId = SfxGroupId::View;
 ]
+
+SfxVoidItem SaveFormula SID_SAVE_FORMULA
+()
+[
+    AutoUpdate = FALSE,
+    FastCall = FALSE,
+    ReadOnlyDoc = TRUE,
+    Toggle = FALSE,
+    Container = FALSE,
+    RecordAbsolute = FALSE,
+    RecordPerSet;
+
+    AccelConfig = TRUE,
+    MenuConfig = TRUE,
+    ToolBoxConfig = TRUE,
+    GroupId = SfxGroupId::View;
+]
\ No newline at end of file
diff --git a/starmath/sdi/smslots.sdi b/starmath/sdi/smslots.sdi
index 2cf17fa342f4..0c3db53704ea 100644
--- a/starmath/sdi/smslots.sdi
+++ b/starmath/sdi/smslots.sdi
@@ -297,6 +297,11 @@ interface FormulaView
         ExecMethod = Execute ;
         StateMethod = GetState ;
     ]
+    SID_SAVE_FORMULA
+    [
+        ExecMethod = Execute ;
+        StateMethod = GetState ;
+    ]
 }
 
 shell SmViewShell
diff --git a/starmath/source/ElementsDockingWindow.cxx 
b/starmath/source/ElementsDockingWindow.cxx
index 351e4773b6bc..f202d1bd74e0 100644
--- a/starmath/source/ElementsDockingWindow.cxx
+++ b/starmath/source/ElementsDockingWindow.cxx
@@ -460,6 +460,7 @@ const std::vector<TranslateId> s_a5Categories{
     RID_CATEGORY_FORMATS,
     RID_CATEGORY_OTHERS,
     RID_CATEGORY_EXAMPLES,
+    RID_CATEGORY_USERDEFINED,
 };
 
 template <size_t N>
@@ -493,24 +494,30 @@ struct ElementData
 {
     OUString maElementSource;
     OUString maHelpText;
-    ElementData(const OUString& aElementSource, const OUString& aHelpText)
+    int maPos;
+    ElementData(const OUString& aElementSource, const OUString& aHelpText, 
const int& aPos)
         : maElementSource(aElementSource)
         , maHelpText(aHelpText)
+        , maPos(aPos)
     {
     }
 };
 
-SmElementsControl::SmElementsControl(std::unique_ptr<weld::IconView> pIconView)
+SmElementsControl::SmElementsControl(std::unique_ptr<weld::IconView> pIconView,
+                                     std::unique_ptr<weld::Menu> pMenu)
     : mpDocShell(new SmDocShell(SfxModelFlags::EMBEDDED_OBJECT))
     , mnCurrentSetIndex(-1)
     , 
m_nSmSyntaxVersion(SmModule::get()->GetConfig()->GetDefaultSmSyntaxVersion())
+    , m_bAllowDelete(false)
     , mpIconView(std::move(pIconView))
+    , mxPopup(std::move(pMenu))
 {
     maParser.reset(starmathdatabase::GetVersionSmParser(m_nSmSyntaxVersion));
     maParser->SetImportSymbolNames(true);
 
     mpIconView->connect_query_tooltip(LINK(this, SmElementsControl, 
QueryTooltipHandler));
     mpIconView->connect_item_activated(LINK(this, SmElementsControl, 
ElementActivatedHandler));
+    mpIconView->connect_mouse_press(LINK(this, SmElementsControl, 
MousePressHdl));
 }
 
 SmElementsControl::~SmElementsControl()
@@ -585,7 +592,7 @@ void SmElementsControl::addElement(const OUString& 
aElementVisual, const OUStrin
     pDevice->SetOutputSizePixel(aSize);
     SmDrawingVisitor(*pDevice, pDevice->PixelToLogic(Point(5, 0)), 
pNode.get(), maFormat);
 
-    maItemDatas.push_back(std::make_unique<ElementData>(aElementSource, 
aHelpText));
+    maItemDatas.push_back(std::make_unique<ElementData>(aElementSource, 
aHelpText, maItemDatas.size()));
     const OUString aId(weld::toId(maItemDatas.back().get()));
     mpIconView->insert(-1, nullptr, &aId, pDevice, nullptr);
     if (mpIconView->get_item_width() < aSize.Width())
@@ -602,9 +609,14 @@ OUString SmElementsControl::GetElementHelpText(const 
OUString& itemId)
     return weld::fromId<ElementData*>(itemId)->maHelpText;
 }
 
-void SmElementsControl::setElementSetIndex(int nSetIndex)
+int SmElementsControl::GetElementPos(const OUString& itemId)
 {
-    if (mnCurrentSetIndex == nSetIndex)
+    return weld::fromId<ElementData*>(itemId)->maPos;
+}
+
+void SmElementsControl::setElementSetIndex(int nSetIndex, bool bForceBuild)
+{
+    if (!bForceBuild && mnCurrentSetIndex == nSetIndex)
         return;
     mnCurrentSetIndex = nSetIndex;
     build();
@@ -617,25 +629,36 @@ void SmElementsControl::addElements(int nCategory)
     mpIconView->set_item_width(0);
     maItemDatas.clear();
 
-    assert(nCategory >= 0 && o3tl::make_unsigned(nCategory) < 
s_a5CategoryDescriptions.size());
-
-    const auto& [aElementsArray, aElementsArraySize] = 
s_a5CategoryDescriptions[nCategory];
-
-    for (size_t i = 0; i < aElementsArraySize; i++)
+    if (o3tl::make_unsigned(nCategory) < s_a5CategoryDescriptions.size())
     {
-        const auto& [element, elementHelp, elementVisual, visualTranslatable] 
= aElementsArray[i];
-        if (element.empty())
+        const auto& [aElementsArray, aElementsArraySize] = 
s_a5CategoryDescriptions[nCategory];
+
+        for (size_t i = 0; i < aElementsArraySize; i++)
         {
-            mpIconView->append_separator({});
+            const auto& [element, elementHelp, elementVisual, 
visualTranslatable] = aElementsArray[i];
+            if (element.empty())
+            {
+                mpIconView->append_separator({});
+            }
+            else
+            {
+                OUString aElement(element);
+                OUString aVisual(elementVisual.empty() ? aElement : 
OUString(elementVisual));
+                if (visualTranslatable)
+                    aVisual = aVisual.replaceFirst("$1", 
SmResId(visualTranslatable));
+                OUString aHelp(elementHelp ? SmResId(elementHelp) : 
OUString());
+                addElement(aVisual, aElement, aHelp);
+            }
         }
-        else
+    }
+    else
+    {
+        css::uno::Sequence<OUString> sNames = 
SmModule::get()->GetConfig()->LoadUserDefinedNames();
+        OUString sFormula;
+        for (int i = 0; i < sNames.getLength(); i++)
         {
-            OUString aElement(element);
-            OUString aVisual(elementVisual.empty() ? aElement : 
OUString(elementVisual));
-            if (visualTranslatable)
-                aVisual = aVisual.replaceFirst("$1", 
SmResId(visualTranslatable));
-            OUString aHelp(elementHelp ? SmResId(elementHelp) : OUString());
-            addElement(aVisual, aElement, aHelp);
+            SmModule::get()->GetConfig()->GetUserDefinedFormula(sNames[i], 
sFormula);
+            addElement(sFormula, sFormula, sNames[i]);
         }
     }
 
@@ -649,6 +672,7 @@ void SmElementsControl::build()
     {
         case 5:
             addElements(mnCurrentSetIndex);
+            m_sHoveredItem = "nil"; // if list is empty we must not use the 
previously hovered item
             break;
         case 6:
         default:
@@ -671,7 +695,10 @@ void SmElementsControl::setSmSyntaxVersion(sal_Int16 
nSmSyntaxVersion)
 IMPL_LINK(SmElementsControl, QueryTooltipHandler, const weld::TreeIter&, iter, 
OUString)
 {
     if (const OUString id = mpIconView->get_id(iter); !id.isEmpty())
+    {
+        m_sHoveredItem = id;
         return GetElementHelpText(id);
+    }
     return {};
 }
 
@@ -684,4 +711,24 @@ IMPL_LINK_NOARG(SmElementsControl, 
ElementActivatedHandler, weld::IconView&, boo
     return true;
 }
 
+IMPL_LINK(SmElementsControl, MousePressHdl, const MouseEvent&, rEvt, bool)
+{
+    if (rEvt.IsRight() && m_bAllowDelete && (m_sHoveredItem != "nil"))
+    {
+        mpIconView->select( GetElementPos(m_sHoveredItem) );
+        OUString sElementId = mpIconView->get_selected_id();
+        if (!sElementId.isEmpty())
+        {
+            OUString sResponse = mxPopup->popup_at_rect(
+                mpIconView.get(), tools::Rectangle(rEvt.GetPosPixel(), Size(1, 
1)));
+            if (sResponse == "delete")
+            {
+                SmModule::get()->GetConfig()->DeleteUserDefinedFormula( 
GetElementHelpText(m_sHoveredItem) );
+                build(); //refresh view
+            }
+            mpIconView->unselect_all();
+        }
+    }
+    return true;
+}
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/starmath/source/SmElementsPanel.cxx 
b/starmath/source/SmElementsPanel.cxx
index ad0fb7089890..afe27a80fc50 100644
--- a/starmath/source/SmElementsPanel.cxx
+++ b/starmath/source/SmElementsPanel.cxx
@@ -24,6 +24,7 @@
 #include <sfx2/lokcomponenthelpers.hxx>
 #include <svl/stritem.hxx>
 #include <svl/itemset.hxx>
+#include <svl/hint.hxx>
 
 #include "SmElementsPanel.hxx"
 #include <starmath.hrc>
@@ -45,8 +46,8 @@ SmElementsPanel::SmElementsPanel(weld::Widget& rParent, const 
SfxBindings& rBind
                   u"modules/smath/ui/sidebarelements_math.ui"_ustr)
     , mrBindings(rBindings)
     , mxCategoryList(m_xBuilder->weld_combo_box(u"categorylist"_ustr))
-    , mxElementsControl(
-          
std::make_unique<SmElementsControl>(m_xBuilder->weld_icon_view(u"elements"_ustr)))
+    , mxElementsControl(std::make_unique<SmElementsControl>(
+          m_xBuilder->weld_icon_view(u"elements"_ustr), 
m_xBuilder->weld_menu("deletemenu")))
 {
     for (const auto& rCategoryId : SmElementsControl::categories())
         mxCategoryList->append_text(SmResId(rCategoryId));
@@ -58,6 +59,8 @@ SmElementsPanel::SmElementsPanel(weld::Widget& rParent, const 
SfxBindings& rBind
 
     mxElementsControl->setElementSetIndex(0);
     mxElementsControl->SetSelectHdl(LINK(this, SmElementsPanel, 
ElementClickHandler));
+
+    StartListening(*GetView());
 }
 
 SmElementsPanel::~SmElementsPanel()
@@ -66,6 +69,15 @@ SmElementsPanel::~SmElementsPanel()
     mxCategoryList.reset();
 }
 
+void SmElementsPanel::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+    if (rHint.GetId() == SfxHintId::SmNewUserFormula)
+    {
+        mxCategoryList->set_active_text(SmResId(RID_CATEGORY_USERDEFINED));
+        mxElementsControl->setElementSetIndex(mxCategoryList->get_active(), 
true);
+    }
+}
+
 IMPL_LINK(SmElementsPanel, CategorySelectedHandle, weld::ComboBox&, rList, 
void)
 {
     const int nActive = rList.get_active();
@@ -74,6 +86,12 @@ IMPL_LINK(SmElementsPanel, CategorySelectedHandle, 
weld::ComboBox&, rList, void)
     mxElementsControl->setElementSetIndex(nActive);
     if (SmViewShell* pViewSh = GetView())
         
mxElementsControl->setSmSyntaxVersion(pViewSh->GetDoc()->GetSmSyntaxVersion());
+
+    // If the "User-defined" category is selected, allow deletion
+    if (mxCategoryList->get_active_text() == SmResId(RID_CATEGORY_USERDEFINED))
+        mxElementsControl->SetAllowDelete(true);
+    else
+        mxElementsControl->SetAllowDelete(false);
 }
 
 IMPL_LINK(SmElementsPanel, ElementClickHandler, const OUString&, 
ElementSource, void)
diff --git a/starmath/source/SmElementsPanel.hxx 
b/starmath/source/SmElementsPanel.hxx
index c3dde01c6724..c1f4b2ab31f3 100644
--- a/starmath/source/SmElementsPanel.hxx
+++ b/starmath/source/SmElementsPanel.hxx
@@ -21,6 +21,7 @@
 
 #include <sal/config.h>
 
+#include <svl/lstner.hxx>
 #include <sfx2/bindings.hxx>
 #include <sfx2/sidebar/PanelLayout.hxx>
 #include <vcl/customweld.hxx>
@@ -32,10 +33,13 @@
 
 namespace sm::sidebar
 {
-class SmElementsPanel : public PanelLayout
+class SmElementsPanel : public PanelLayout, public SfxListener
 {
 public:
     static std::unique_ptr<PanelLayout> Create(weld::Widget& rParent, const 
SfxBindings& rBindings);
+
+    void Notify(SfxBroadcaster& rBC, const SfxHint& rHint);
+
     SmElementsPanel(weld::Widget& rParent, const SfxBindings& rBindings);
     ~SmElementsPanel();
 
diff --git a/starmath/source/cfgitem.cxx b/starmath/source/cfgitem.cxx
index 78cdbc97e131..6f0134047d07 100644
--- a/starmath/source/cfgitem.cxx
+++ b/starmath/source/cfgitem.cxx
@@ -44,6 +44,7 @@ using namespace com::sun::star::beans;
 
 constexpr OUString SYMBOL_LIST = u"SymbolList"_ustr;
 constexpr OUString FONT_FORMAT_LIST = u"FontFormatList"_ustr;
+constexpr OUString USER_DEFINED_LIST = u"User-Defined"_ustr;
 
 static Sequence< OUString > lcl_GetFontPropertyNames()
 {
@@ -575,7 +576,6 @@ void SmMathConfig::SetSymbols( const std::vector< SmSym > 
&rNewSymbols )
     StripFontFormatList( rNewSymbols );
 }
 
-
 SmFontFormatList & SmMathConfig::GetFontFormatList()
 {
     if (!pFontFormatList)
@@ -585,7 +585,6 @@ SmFontFormatList & SmMathConfig::GetFontFormatList()
     return *pFontFormatList;
 }
 
-
 void SmMathConfig::LoadFontFormatList()
 {
     if (!pFontFormatList)
@@ -661,6 +660,47 @@ void SmMathConfig::ReadFontFormat( SmFontFormat 
&rFontFormat,
     OSL_ENSURE( bOK, "read FontFormat failed" );
 }
 
+css::uno::Sequence<OUString> SmMathConfig::LoadUserDefinedNames()
+{
+    m_sUserDefinedNames = GetNodeNames(USER_DEFINED_LIST);
+    return m_sUserDefinedNames;
+}
+
+void SmMathConfig::GetUserDefinedFormula(std::u16string_view sName, OUString 
&sFormula)
+{
+    css::uno::Sequence<OUString> aNames(1);
+    OUString* pName = aNames.getArray();
+    pName[0] = USER_DEFINED_LIST + "/" + sName + "/FormulaText";
+    const Sequence<Any> aValues(GetProperties(aNames));
+    const Any* pValues = aValues.getConstArray();
+    const Any* pVal = pValues;
+    *pVal >>= sFormula;
+}
+
+bool SmMathConfig::HasUserDefinedFormula(std::u16string_view sName)
+{
+    for (int i = 0; i < m_sUserDefinedNames.getLength(); i++)
+        if (m_sUserDefinedNames[i] == sName)
+            return true;
+    return false;
+}
+
+void SmMathConfig::SaveUserDefinedFormula(std::u16string_view sName, const 
OUString& sElement)
+{
+    Sequence<PropertyValue> pValues(1);
+    auto pArgs = pValues.getArray();
+
+    pArgs[0].Name = USER_DEFINED_LIST + "/" + sName + "/FormulaText";
+    pArgs[0].Value <<= sElement;
+
+    SetSetProperties( USER_DEFINED_LIST, pValues );
+}
+
+void SmMathConfig::DeleteUserDefinedFormula(std::u16string_view sName)
+{
+    Sequence<OUString> aElements { OUString(sName) };
+    ClearNodeElements(USER_DEFINED_LIST, aElements);
+}
 
 void SmMathConfig::SaveFontFormatList()
 {
diff --git a/starmath/source/view.cxx b/starmath/source/view.cxx
index f1130e5701de..da074984964d 100644
--- a/starmath/source/view.cxx
+++ b/starmath/source/view.cxx
@@ -89,6 +89,7 @@
 #include <mathmlimport.hxx>
 #include <cursor.hxx>
 #include "accessibility.hxx"
+#include <svl/hint.hxx>
 #include <ElementsDockingWindow.hxx>
 #include <helpids.h>
 
@@ -1840,6 +1841,39 @@ void SmViewShell::Execute(SfxRequest& rReq)
             GetViewFrame().GetBindings().Invalidate(bRTL ? 
SID_ATTR_PARA_LEFT_TO_RIGHT : SID_ATTR_PARA_RIGHT_TO_LEFT);
         }
         break;
+        case SID_SAVE_FORMULA:
+        {
+            OUString aName = "My Formula 1";
+            OUString aDesc(SmResId(STR_USER_DEFINED_FORMULA));
+            SvxAbstractDialogFactory* pFact = 
SvxAbstractDialogFactory::Create();
+            ScopedVclPtr<AbstractSvxNameDialog> pDlg(
+                pFact->CreateSvxNameDialog(GetFrameWeld(), aName, aDesc));
+
+            if (pDlg->Execute() == RET_OK)
+            {
+                aName = pDlg->GetName();
+                if (SmModule::get()->GetConfig()->HasUserDefinedFormula(aName))
+                {
+                    std::unique_ptr<weld::MessageDialog> 
xQuery(Application::CreateMessageDialog(
+                        GetFrameWeld(), VclMessageType::Question, 
VclButtonsType::YesNo,
+                        
SmResId(STR_USER_DEFINED_FORMULA_EXISTS).replaceAll("%1", aName)));
+                    if (xQuery->run() == RET_NO)
+                        break;
+                }
+                SmEditWindow* pEditWin = GetEditWindow();
+                SmModule::get()->GetConfig()->SaveUserDefinedFormula(aName, 
pEditWin->GetText());
+
+                // Show the Elements sidebar with the "User-defined" entry 
selected
+                GetViewFrame().ShowChildWindow(SID_SIDEBAR);
+                sfx2::sidebar::Sidebar::ShowPanel(u"MathElementsPanel",
+                                                  
GetViewFrame().GetFrame().GetFrameInterface());
+                GetViewFrame().GetBindings().Invalidate( 
SID_ELEMENTSDOCKINGWINDOW );
+                Broadcast(SfxHint(SfxHintId::SmNewUserFormula));
+                rReq.Ignore ();
+            }
+            pDlg.disposeAndClear();
+        }
+        break;
     }
     rReq.Done();
 }
@@ -1949,6 +1983,10 @@ void SmViewShell::GetState(SfxItemSet &rSet)
         case SID_ATTR_PARA_RIGHT_TO_LEFT:
             rSet.Put(SfxBoolItem(nWh, GetDoc()->GetFormat().IsRightToLeft()));
             break;
+        case SID_SAVE_FORMULA:
+            if (!pEditWin || pEditWin->IsEmpty())
+                rSet.DisableItem(nWh);
+            break;
         }
     }
 }
diff --git a/starmath/uiconfig/smath/menubar/menubar.xml 
b/starmath/uiconfig/smath/menubar/menubar.xml
index 903ba7189664..74b478aaf3b0 100644
--- a/starmath/uiconfig/smath/menubar/menubar.xml
+++ b/starmath/uiconfig/smath/menubar/menubar.xml
@@ -125,6 +125,7 @@
       <menu:menuitem menu:id=".uno:InsertSymbol"/>
       <menu:menuitem menu:id=".uno:ImportFormula"/>
       <menu:menuitem menu:id=".uno:ImportMathMLClipboard"/>
+      <menu:menuitem menu:id=".uno:SaveFormula"/>
       <menu:menuseparator/>
       <menu:menu menu:id=".uno:MacrosMenu">
         <menu:menupopup>
diff --git a/starmath/uiconfig/smath/popupmenu/edit.xml 
b/starmath/uiconfig/smath/popupmenu/edit.xml
index c9626cc6a033..385baa4c33cd 100644
--- a/starmath/uiconfig/smath/popupmenu/edit.xml
+++ b/starmath/uiconfig/smath/popupmenu/edit.xml
@@ -15,6 +15,7 @@
   <menu:menuitem menu:id=".uno:Cut"/>
   <menu:menuitem menu:id=".uno:Copy"/>
   <menu:menuitem menu:id=".uno:Paste"/>
+  <menu:menuitem menu:id=".uno:SaveFormula"/>
   <menu:menuseparator/>
   <menu:menu menu:id=".uno:UnaryBinaryMenu">
     <menu:menupopup>
diff --git a/starmath/uiconfig/smath/ui/sidebarelements_math.ui 
b/starmath/uiconfig/smath/ui/sidebarelements_math.ui
index b9a5736abb9d..8552baba3e18 100644
--- a/starmath/uiconfig/smath/ui/sidebarelements_math.ui
+++ b/starmath/uiconfig/smath/ui/sidebarelements_math.ui
@@ -2,6 +2,18 @@
 <!-- Generated with glade 3.38.1 -->
 <interface domain="sm">
   <requires lib="gtk+" version="3.20"/>
+  <object class="GtkMenu" id="deletemenu">
+    <property name="visible">True</property>
+    <property name="can-focus">False</property>
+    <child>
+      <object class="GtkMenuItem" id="delete">
+        <property name="visible">True</property>
+        <property name="can-focus">False</property>
+        <property name="label" translatable="yes" 
context="mathelementspanel|popupmenu|delete">Delete Formula</property>
+        <property name="use-underline">True</property>
+      </object>
+    </child>
+  </object>
   <object class="GtkTreeStore" id="liststore2">
     <columns>
       <!-- column-name expander -->

Reply via email to