basctl/Library_basctl.mk                                             |    2 
 basctl/inc/pch/precompiled_basctl.hxx                                |    2 
 basctl/source/basicide/basobj3.cxx                                   |    2 
 basctl/source/basicide/bastypes.cxx                                  |    5 
 basctl/source/basicide/doceventnotifier.cxx                          |    2 
 basctl/source/basicide/docsignature.cxx                              |    2 
 basctl/source/basicide/moduldl2.cxx                                  |  145 
 basctl/source/basicide/moduldlg.hxx                                  |   15 
 basctl/source/basicide/sbxitem.cxx                                   |    2 
 basctl/source/basicide/scriptdocument.cxx                            |    2 
 basctl/source/inc/IDEComboBox.hxx                                    |    2 
 basctl/source/inc/basidesh.hxx                                       |    2 
 basctl/source/inc/basobj.hxx                                         |    9 
 basctl/source/inc/bastype2.hxx                                       |    2 
 basctl/source/inc/bastypes.hxx                                       |   10 
 basctl/source/inc/localizationmgr.hxx                                |    2 
 chart2/uiconfig/menubar/menubar.xml                                  |    2 
 cui/Library_cui.mk                                                   |    2 
 cui/UIConfig_cui.mk                                                  |    1 
 cui/inc/bitmaps.hlst                                                 |    3 
 cui/inc/strings.hrc                                                  |   29 
 cui/source/customize/cfgutil.cxx                                     |  137 
 cui/source/dialogs/MacroManagerDialog.cxx                            | 2512 
++++++++++
 cui/source/factory/dlgfact.cxx                                       |   15 
 cui/source/factory/dlgfact.hxx                                       |   13 
 cui/source/inc/MacroManagerDialog.hxx                                |  255 +
 cui/source/inc/cfgutil.hxx                                           |   10 
 cui/uiconfig/ui/macromanagerdialog.ui                                |  564 ++
 dbaccess/uiconfig/dbapp/menubar/menubar.xml                          |    2 
 dbaccess/uiconfig/dbquery/menubar/menubar.xml                        |    2 
 dbaccess/uiconfig/dbrelation/menubar/menubar.xml                     |    2 
 dbaccess/uiconfig/dbtable/menubar/menubar.xml                        |    2 
 dbaccess/uiconfig/dbtdata/menubar/menubar.xml                        |    2 
 extensions/uiconfig/sbibliography/menubar/menubar.xml                |    2 
 framework/uiconfig/startmodule/menubar/menubar.xml                   |    2 
 include/basctl/basctldllapi.h                                        |   23 
 include/basctl/basctldllpublic.hxx                                   |   43 
 include/basctl/sbxitem.hxx                                           |    3 
 include/basctl/scriptdocument.hxx                                    |    4 
 include/sfx2/minfitem.hxx                                            |    5 
 include/sfx2/sfxdlg.hxx                                              |   15 
 include/sfx2/sfxsids.hrc                                             |    1 
 include/svl/hint.hxx                                                 |    3 
 include/svx/passwd.hxx                                               |    2 
 include/svx/svxdlg.hxx                                               |    3 
 officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu |   11 
 reportdesign/uiconfig/dbreport/menubar/menubar.xml                   |    2 
 sc/uiconfig/scalc/menubar/menubar.xml                                |    2 
 sd/uiconfig/sdraw/menubar/menubar.xml                                |    2 
 sd/uiconfig/simpress/menubar/menubar.xml                             |    2 
 sfx2/sdi/appslots.sdi                                                |    5 
 sfx2/sdi/sfx.sdi                                                     |   17 
 sfx2/source/appl/appserv.cxx                                         |   51 
 sfx2/source/control/minfitem.cxx                                     |    6 
 solenv/clang-format/excludelist                                      |    4 
 starmath/uiconfig/smath/menubar/menubar.xml                          |    2 
 sw/uiconfig/sglobal/menubar/menubar.xml                              |    2 
 sw/uiconfig/sweb/menubar/menubar.xml                                 |    2 
 sw/uiconfig/swform/menubar/menubar.xml                               |    2 
 sw/uiconfig/swreport/menubar/menubar.xml                             |    2 
 sw/uiconfig/swriter/menubar/menubar.xml                              |    2 
 sw/uiconfig/swxform/menubar/menubar.xml                              |    2 
 62 files changed, 3830 insertions(+), 151 deletions(-)

New commits:
commit 55e86edcb37a37123a69ce3e1eb9e20758415fb6
Author:     Jim Raykowski <[email protected]>
AuthorDate: Mon Oct 7 10:56:34 2024 -0800
Commit:     Jim Raykowski <[email protected]>
CommitDate: Mon Dec 2 07:13:00 2024 +0100

    tdf#120658 - Reworking of dialogues Organize macros
    
    (make from 5 existing only one)
    
    Much of what makes up this patch is adapted from existing code that is
    used to organize and select macros and to assign macros to shortcut
    keys. Comments in the patch say where code is borrowed from.
    
    Known issues:
    
    + Scripting framework library rename for BeanShell, Java, and JavaScript
    always returns fail when there are no macro entries in the library even
    though it actually succeeds. The same thing happens using
    SvxScriptOrgDialog::renameEntry.
    
    + Deleting Basic macros from the Macro Manager dialog is not implemented
    yet.
    
    Change-Id: If4da04549f8b39675910cbbd1f94dd9a6b73c31a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176254
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <[email protected]>

diff --git a/basctl/Library_basctl.mk b/basctl/Library_basctl.mk
index cb41fa9e461c..9006a9aadd17 100644
--- a/basctl/Library_basctl.mk
+++ b/basctl/Library_basctl.mk
@@ -29,6 +29,8 @@ $(eval $(call gb_Library_set_include,basctl,\
        -I$(WORKDIR)/SdiTarget/basctl/sdi \
 ))
 
+$(eval $(call gb_Library_add_defs,basctl,-DBASCTL_DLLIMPLEMENTATION))
+
 $(eval $(call gb_Library_use_external,basctl,boost_headers))
 
 $(eval $(call gb_Library_use_custom_headers,basctl,\
diff --git a/basctl/inc/pch/precompiled_basctl.hxx 
b/basctl/inc/pch/precompiled_basctl.hxx
index 1794f96f90e9..41afc13b5199 100644
--- a/basctl/inc/pch/precompiled_basctl.hxx
+++ b/basctl/inc/pch/precompiled_basctl.hxx
@@ -576,7 +576,7 @@
 #include <iderid.hxx>
 #include <localizationmgr.hxx>
 #include <managelang.hxx>
-#include <scriptdocument.hxx>
+#include <basctl/scriptdocument.hxx>
 #endif // PCH_LEVEL >= 4
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/basobj3.cxx 
b/basctl/source/basicide/basobj3.cxx
index 8e1eaf40c79f..44c5adc072b8 100644
--- a/basctl/source/basicide/basobj3.cxx
+++ b/basctl/source/basicide/basobj3.cxx
@@ -244,6 +244,8 @@ BasicManager* FindBasicManager( StarBASIC const * pLib )
 
 void MarkDocumentModified( const ScriptDocument& rDocument )
 {
+    SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScriptDocumentChanged));
+
     Shell* pShell = GetShell();
 
     // does not have to come from a document...
diff --git a/basctl/source/basicide/bastypes.cxx 
b/basctl/source/basicide/bastypes.cxx
index edc9fe32149a..e01b9d1861dd 100644
--- a/basctl/source/basicide/bastypes.cxx
+++ b/basctl/source/basicide/bastypes.cxx
@@ -764,21 +764,26 @@ bool QueryReplaceMacro( std::u16string_view rName, 
weld::Widget* pParent )
 
 bool QueryDelDialog( std::u16string_view rName, weld::Widget* pParent )
 {
+    EnsureIde();
     return QueryDel( rName, IDEResId( RID_STR_QUERYDELDIALOG ), pParent );
 }
 
 bool QueryDelLib( std::u16string_view rName, bool bRef, weld::Widget* pParent )
 {
+    EnsureIde();
     return QueryDel( rName, IDEResId( bRef ? RID_STR_QUERYDELLIBREF : 
RID_STR_QUERYDELLIB ), pParent );
 }
 
 bool QueryDelModule( std::u16string_view rName, weld::Widget* pParent )
 {
+    EnsureIde();
     return QueryDel( rName, IDEResId( RID_STR_QUERYDELMODULE ), pParent );
 }
 
 bool QueryPassword(weld::Widget* pDialogParent, const Reference< 
script::XLibraryContainer >& xLibContainer, const OUString& rLibName, OUString& 
rPassword, bool bRepeat, bool bNewTitle)
 {
+    EnsureIde();
+
     bool bOK = false;
     sal_uInt16 nRet = 0;
 
diff --git a/basctl/source/basicide/doceventnotifier.cxx 
b/basctl/source/basicide/doceventnotifier.cxx
index abee782c09fe..2365aef2ee16 100644
--- a/basctl/source/basicide/doceventnotifier.cxx
+++ b/basctl/source/basicide/doceventnotifier.cxx
@@ -18,7 +18,7 @@
  */
 
 #include <doceventnotifier.hxx>
-#include <scriptdocument.hxx>
+#include <basctl/scriptdocument.hxx>
 
 #include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
 
diff --git a/basctl/source/basicide/docsignature.cxx 
b/basctl/source/basicide/docsignature.cxx
index ee04435274db..f516a4d24458 100644
--- a/basctl/source/basicide/docsignature.cxx
+++ b/basctl/source/basicide/docsignature.cxx
@@ -18,7 +18,7 @@
  */
 
 #include <docsignature.hxx>
-#include <scriptdocument.hxx>
+#include <basctl/scriptdocument.hxx>
 
 #include <sfx2/objsh.hxx>
 #include <sfx2/signaturestate.hxx>
diff --git a/basctl/source/basicide/moduldl2.cxx 
b/basctl/source/basicide/moduldl2.cxx
index 5b3d49547dc7..49cf87a2d0d8 100644
--- a/basctl/source/basicide/moduldl2.cxx
+++ b/basctl/source/basicide/moduldl2.cxx
@@ -464,7 +464,13 @@ IMPL_LINK( LibPage, ButtonHdl, weld::Button&, rButton, 
void )
     else if (&rButton == m_xInsertLibButton.get())
         InsertLib();
     else if (&rButton == m_xExportButton.get())
-        Export();
+    {
+        std::unique_ptr<weld::TreeIter> xCurEntry(m_xLibBox->make_iterator());
+        if (!m_xLibBox->get_cursor(xCurEntry.get()))
+            return;
+        OUString aLibName(m_xLibBox->get_text(*xCurEntry, 0));
+        Export(m_aCurDocument, aLibName, m_pDialog->getDialog());
+    }
     else if (&rButton == m_xDelButton.get())
         DeleteCurrent();
     else if (&rButton == m_xPasswordButton.get())
@@ -565,9 +571,32 @@ void LibPage::NewLib()
 
 void LibPage::InsertLib()
 {
+    auto remove_entry = [this](OUString& rLibName) { // remove listbox entry
+        int nEntry = FindEntry(*m_xLibBox, rLibName);
+        if (nEntry != -1)
+            m_xLibBox->remove(nEntry);
+    };
+
+    auto insert_entry = [this](OUString& rLibName) { // insert listbox entry
+        m_xLibBox->make_unsorted();
+        ImpInsertLibEntry(rLibName, m_xLibBox->n_children());
+        m_xLibBox->make_sorted();
+        m_xLibBox->set_cursor(m_xLibBox->find_text(rLibName));
+    };
+
+    ImportLib(m_aCurDocument, m_pDialog->getDialog(), remove_entry, 
insert_entry, {});
+}
+
+void ImportLib(const ScriptDocument& rDocument, weld::Dialog* pDialog,
+               const std::function<void(OUString& rLibName)>& 
func_remove_entry,
+               const std::function<void(OUString& rLibName)>& 
func_insert_entry,
+               const std::function<void()>& func_insert_entries)
+{
+    basctl::EnsureIde();
+
     const Reference< uno::XComponentContext >& xContext( 
::comphelper::getProcessComponentContext() );
     // file open dialog
-    sfx2::FileDialogHelper 
aDlg(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, 
m_pDialog->getDialog());
+    sfx2::FileDialogHelper 
aDlg(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, 
pDialog);
     aDlg.SetContext(sfx2::FileDialogHelper::BasicInsertLib);
     const Reference <XFilePicker3>& xFP = aDlg.GetFilePicker();
 
@@ -643,7 +672,7 @@ void LibPage::InsertLib()
     if (aLibNames.hasElements())
     {
         // library import dialog
-        xLibDlg = std::make_shared<LibDialog>(m_pDialog->getDialog());
+        xLibDlg = std::make_shared<LibDialog>(pDialog);
         xLibDlg->SetStorageName(aURLObj.getName());
         weld::TreeView& rView = xLibDlg->GetLibBox();
         rView.make_unsorted();
@@ -671,7 +700,7 @@ void LibPage::InsertLib()
 
     if (!xLibDlg)
     {
-        std::unique_ptr<weld::MessageDialog> 
xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
+        std::unique_ptr<weld::MessageDialog> 
xErrorBox(Application::CreateMessageDialog(pDialog,
                                                        
VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_NOLIBINSTORAGE)));
         xErrorBox->run();
         return;
@@ -685,9 +714,12 @@ void LibPage::InsertLib()
     if ( aExtension != aLibExtension && aExtension != aContExtension )
         xLibDlg->EnableReference(false);
 
-    weld::DialogController::runAsync(xLibDlg, [aContExtension, 
xDlgURLObj=std::move(xDlgURLObj), aExtension,
-                                               aLibExtension, 
xModURLObj=std::move(xModURLObj), xLibDlg,
-                                               xDlgLibContImport, 
xModLibContImport, this](sal_Int32 nResult)
+    weld::DialogController::runAsync(
+        xLibDlg,
+        [aContExtension, xDlgURLObj = std::move(xDlgURLObj), aExtension, 
aLibExtension,
+         xModURLObj = std::move(xModURLObj), xLibDlg, xDlgLibContImport, 
xModLibContImport,
+         rDocument, pDialog, func_remove_entry, func_insert_entry,
+         func_insert_entries](sal_Int32 nResult)
         {
             if (!nResult )
                 return;
@@ -702,8 +734,10 @@ void LibPage::InsertLib()
                 if (rView.get_toggle(nLib) == TRISTATE_TRUE)
                 {
                     OUString aLibName(rView.get_text(nLib));
-                    Reference< script::XLibraryContainer2 > xModLibContainer( 
m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
-                    Reference< script::XLibraryContainer2 > xDlgLibContainer( 
m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+                    Reference<script::XLibraryContainer2> xModLibContainer(
+                        rDocument.getLibraryContainer(E_SCRIPTS), UNO_QUERY);
+                    Reference<script::XLibraryContainer2> xDlgLibContainer(
+                        rDocument.getLibraryContainer(E_DIALOGS), UNO_QUERY);
 
                     // check, if the library is already existing
                     if ( ( xModLibContainer.is() && 
xModLibContainer->hasByName( aLibName ) ) ||
@@ -714,8 +748,10 @@ void LibPage::InsertLib()
                             // check, if the library is the Standard library
                             if ( aLibName == "Standard" )
                             {
-                                std::unique_ptr<weld::MessageDialog> 
xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
-                                                                               
VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_REPLACESTDLIB)));
+                                std::unique_ptr<weld::MessageDialog> xErrorBox(
+                                    Application::CreateMessageDialog(
+                                        pDialog, VclMessageType::Warning, 
VclButtonsType::Ok,
+                                        IDEResId(RID_STR_REPLACESTDLIB)));
                                 xErrorBox->run();
                                 continue;
                             }
@@ -726,8 +762,10 @@ void LibPage::InsertLib()
                             {
                                 OUString aErrStr( IDEResId(RID_STR_REPLACELIB) 
);
                                 aErrStr = aErrStr.replaceAll("XX", aLibName) + 
"
" + IDEResId(RID_STR_LIBISREADONLY);
-                                std::unique_ptr<weld::MessageDialog> 
xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
-                                                                               
VclMessageType::Warning, VclButtonsType::Ok, aErrStr));
+                                std::unique_ptr<weld::MessageDialog> xErrorBox(
+                                    Application::CreateMessageDialog(pDialog,
+                                                                     
VclMessageType::Warning,
+                                                                     
VclButtonsType::Ok, aErrStr));
                                 xErrorBox->run();
                                 continue;
                             }
@@ -743,8 +781,9 @@ void LibPage::InsertLib()
                             else
                                 aErrStr = IDEResId(RID_STR_IMPORTNOTPOSSIBLE);
                             aErrStr = aErrStr.replaceAll("XX", aLibName) + "
" +IDEResId(RID_STR_SBXNAMEALLREADYUSED);
-                            std::unique_ptr<weld::MessageDialog> 
xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
-                                                                           
VclMessageType::Warning, VclButtonsType::Ok, aErrStr));
+                            std::unique_ptr<weld::MessageDialog> xErrorBox(
+                                Application::CreateMessageDialog(pDialog, 
VclMessageType::Warning,
+                                                                 
VclButtonsType::Ok, aErrStr));
                             xErrorBox->run();
                             continue;
                         }
@@ -758,14 +797,17 @@ void LibPage::InsertLib()
                         Reference< script::XLibraryContainerPassword > 
xPasswd( xModLibContImport, UNO_QUERY );
                         if ( xPasswd.is() && 
xPasswd->isLibraryPasswordProtected( aLibName ) && 
!xPasswd->isLibraryPasswordVerified( aLibName ) && !bReference )
                         {
-                            bOK = QueryPassword(m_pDialog->getDialog(), 
xModLibContImport, aLibName, aPassword, true, true);
+                            bOK = QueryPassword(pDialog, xModLibContImport, 
aLibName, aPassword,
+                                                true, true);
 
                             if ( !bOK )
                             {
                                 OUString aErrStr( IDEResId(RID_STR_NOIMPORT) );
                                 aErrStr = aErrStr.replaceAll("XX", aLibName);
-                                std::unique_ptr<weld::MessageDialog> 
xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
-                                                                               
VclMessageType::Warning, VclButtonsType::Ok, aErrStr));
+                                std::unique_ptr<weld::MessageDialog> xErrorBox(
+                                    Application::CreateMessageDialog(pDialog,
+                                                                     
VclMessageType::Warning,
+                                                                     
VclButtonsType::Ok, aErrStr));
                                 xErrorBox->run();
                                 continue;
                             }
@@ -775,10 +817,7 @@ void LibPage::InsertLib()
                     // remove existing libraries
                     if ( bRemove )
                     {
-                        // remove listbox entry
-                        int nEntry_ = FindEntry(*m_xLibBox, aLibName);
-                        if (nEntry_ != -1)
-                            m_xLibBox->remove(nEntry_);
+                        func_remove_entry(aLibName); // LibPage::InsertLib
 
                         // remove module library
                         if ( xModLibContainer.is() && 
xModLibContainer->hasByName( aLibName ) )
@@ -901,29 +940,24 @@ void LibPage::InsertLib()
                         }
                     }
 
-                    // insert listbox entry
-                    m_xLibBox->make_unsorted();
-                    ImpInsertLibEntry( aLibName, m_xLibBox->n_children() );
-                    m_xLibBox->make_sorted();
-                    m_xLibBox->set_cursor( m_xLibBox->find_text(aLibName) );
+                    func_insert_entry(aLibName); // LibPage::InsertLib
                     bChanges = true;
                 }
             }
 
-            if ( bChanges )
-                MarkDocumentModified( m_aCurDocument );
+            if (bChanges)
+            {
+                func_insert_entries(); // MacroManager
+                MarkDocumentModified(rDocument);
+            }
         });
 }
 
-void LibPage::Export()
+void Export(const ScriptDocument& rDocument, const OUString& aLibName, 
weld::Dialog* pDialog)
 {
-    std::unique_ptr<weld::TreeIter> xCurEntry(m_xLibBox->make_iterator());
-    if (!m_xLibBox->get_cursor(xCurEntry.get()))
-        return;
-    OUString aLibName(m_xLibBox->get_text(*xCurEntry, 0));
-
     // Password verification
-    Reference< script::XLibraryContainer2 > xModLibContainer( 
m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+    Reference<script::XLibraryContainer2> 
xModLibContainer(rDocument.getLibraryContainer(E_SCRIPTS),
+                                                           UNO_QUERY);
 
     if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && 
!xModLibContainer->isLibraryLoaded( aLibName ) )
     {
@@ -934,13 +968,13 @@ void LibPage::Export()
         if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) 
&& !xPasswd->isLibraryPasswordVerified( aLibName ) )
         {
             OUString aPassword;
-            bOK = QueryPassword(m_pDialog->getDialog(), xModLibContainer, 
aLibName, aPassword);
+            bOK = QueryPassword(pDialog, xModLibContainer, aLibName, 
aPassword);
         }
         if ( !bOK )
             return;
     }
 
-    std::unique_ptr<ExportDialog> xNewDlg(new 
ExportDialog(m_pDialog->getDialog()));
+    std::unique_ptr<ExportDialog> xNewDlg(new ExportDialog(pDialog));
     if (xNewDlg->run() != RET_OK)
         return;
 
@@ -951,24 +985,24 @@ void LibPage::Export()
         //parent of file dialog from ExportAs...
         xNewDlg.reset();
         if (bExportAsPackage)
-            ExportAsPackage( aLibName );
+            ExportAsPackage(rDocument, aLibName, pDialog);
         else
-            ExportAsBasic( aLibName );
+            ExportAsBasic(rDocument, aLibName, pDialog);
     }
     catch(const util::VetoException& ) // user canceled operation
     {
     }
 }
 
-void LibPage::implExportLib( const OUString& aLibName, const OUString& 
aTargetURL,
-    const Reference< task::XInteractionHandler >& Handler )
+void implExportLib(const ScriptDocument& rScriptDocument, const OUString& 
aLibName,
+                   const OUString& aTargetURL, const 
Reference<task::XInteractionHandler>& Handler)
 {
-    Reference< script::XLibraryContainerExport > xModLibContainerExport
-        ( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
-    Reference< script::XLibraryContainerExport > xDlgLibContainerExport
-        ( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+    Reference<script::XLibraryContainerExport> xModLibContainerExport(
+        rScriptDocument.getLibraryContainer(E_SCRIPTS), UNO_QUERY);
+    Reference<script::XLibraryContainerExport> xDlgLibContainerExport(
+        rScriptDocument.getLibraryContainer(E_DIALOGS), UNO_QUERY);
     if ( xModLibContainerExport.is() )
-        xModLibContainerExport->exportLibrary( aLibName, aTargetURL, Handler );
+        xModLibContainerExport->exportLibrary(aLibName, aTargetURL, Handler);
 
     if (!xDlgLibContainerExport.is())
         return;
@@ -1011,10 +1045,13 @@ Reference< XProgressHandler > 
OLibCommandEnvironment::getProgressHandler()
     return xRet;
 }
 
-void LibPage::ExportAsPackage( const OUString& aLibName )
+void ExportAsPackage(const ScriptDocument& rScriptDocument, const OUString& 
aLibName,
+                     weld::Dialog* pDialog)
 {
+    EnsureIde();
     // file open dialog
-    sfx2::FileDialogHelper 
aDlg(ui::dialogs::TemplateDescription::FILESAVE_SIMPLE, FileDialogFlags::NONE, 
m_pDialog->getDialog());
+    sfx2::FileDialogHelper 
aDlg(ui::dialogs::TemplateDescription::FILESAVE_SIMPLE,
+                                FileDialogFlags::NONE, pDialog);
     aDlg.SetContext(sfx2::FileDialogHelper::BasicExportPackage);
     const Reference <XFilePicker3>& xFP = aDlg.GetFilePicker();
 
@@ -1049,7 +1086,7 @@ void LibPage::ExportAsPackage( const OUString& aLibName )
     if( xSFA->exists( aSourcePath ) )
         xSFA->kill( aSourcePath );
     Reference< task::XInteractionHandler > xDummyHandler( new 
DummyInteractionHandler( xHandler ) );
-    implExportLib( aLibName, aTmpPath, xDummyHandler );
+    implExportLib(rScriptDocument, aLibName, aTmpPath, xDummyHandler);
 
     Reference< XCommandEnvironment > xCmdEnv = new 
OLibCommandEnvironment(xHandler);
 
@@ -1113,11 +1150,13 @@ void LibPage::ExportAsPackage( const OUString& aLibName 
)
         xSFA->kill( aMetaInfFolder );
 }
 
-void LibPage::ExportAsBasic( const OUString& aLibName )
+void ExportAsBasic(const ScriptDocument& rScriptDocument, const OUString& 
aLibName,
+                   weld::Dialog* pDialog)
 {
+    EnsureIde();
     // Folder picker
     const Reference< uno::XComponentContext >& xContext( 
::comphelper::getProcessComponentContext() );
-    Reference< XFolderPicker2 > xFolderPicker = 
sfx2::createFolderPicker(xContext, m_pDialog->getDialog());
+    Reference<XFolderPicker2> xFolderPicker = 
sfx2::createFolderPicker(xContext, pDialog);
     Reference< task::XInteractionHandler2 > xHandler( 
task::InteractionHandler::createWithParent(xContext, nullptr) );
 
     xFolderPicker->setTitle(IDEResId(RID_STR_EXPORTBASIC));
@@ -1136,7 +1175,7 @@ void LibPage::ExportAsBasic( const OUString& aLibName )
         GetExtraData()->SetAddLibPath(aTargetURL);
 
         Reference< task::XInteractionHandler > xDummyHandler( new 
DummyInteractionHandler( xHandler ) );
-        implExportLib( aLibName, aTargetURL, xDummyHandler );
+        implExportLib(rScriptDocument, aLibName, aTargetURL, xDummyHandler);
     }
 }
 
diff --git a/basctl/source/basicide/moduldlg.hxx 
b/basctl/source/basicide/moduldlg.hxx
index c6ff166c5bb7..4491a4709371 100644
--- a/basctl/source/basicide/moduldlg.hxx
+++ b/basctl/source/basicide/moduldlg.hxx
@@ -27,6 +27,8 @@
 #include <vcl/weld.hxx>
 #include <com/sun/star/task/XInteractionHandler.hpp>
 
+#include <basctl/basctldllpublic.hxx>
+
 class SvxPasswordDialog;
 
 namespace basctl
@@ -185,11 +187,6 @@ class LibPage final : public OrganizePage
     void                DeleteCurrent();
     void                NewLib();
     void                InsertLib();
-    void                implExportLib( const OUString& aLibName, const 
OUString& aTargetURL,
-                                       const css::uno::Reference< 
css::task::XInteractionHandler >& Handler );
-    void                Export();
-    void                ExportAsPackage( const OUString& aLibName );
-    void                ExportAsBasic( const OUString& aLibName );
     void                EndTabDialog();
     void                FillListBox();
     void                InsertListBoxEntry( const ScriptDocument& rDocument, 
LibraryLocation eLocation );
@@ -202,6 +199,14 @@ public:
     virtual void        ActivatePage() override;
 };
 
+void implExportLib(const ScriptDocument& rScriptDocument, const OUString& 
aLibName,
+                   const OUString& aTargetURL,
+                   const css::uno::Reference<css::task::XInteractionHandler>& 
Handler);
+void ExportAsPackage(const ScriptDocument& rScriptDocument, const OUString& 
aLibName,
+                     weld::Dialog* pDialog);
+void ExportAsBasic(const ScriptDocument& rScriptDocument, const OUString& 
aLibName,
+                   weld::Dialog* pDialog);
+
 class OrganizeDialog : public weld::GenericDialogController
 {
 private:
diff --git a/basctl/source/basicide/sbxitem.cxx 
b/basctl/source/basicide/sbxitem.cxx
index b3ceccc4727d..8d098c5ab68e 100644
--- a/basctl/source/basicide/sbxitem.cxx
+++ b/basctl/source/basicide/sbxitem.cxx
@@ -17,7 +17,7 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
  */
 
-#include <sbxitem.hxx>
+#include <basctl/sbxitem.hxx>
 #include <sal/log.hxx>
 #include <utility>
 
diff --git a/basctl/source/basicide/scriptdocument.cxx 
b/basctl/source/basicide/scriptdocument.cxx
index 00ef24a1b279..722c5c1d8ba8 100644
--- a/basctl/source/basicide/scriptdocument.cxx
+++ b/basctl/source/basicide/scriptdocument.cxx
@@ -18,7 +18,7 @@
  */
 
 #include <memory>
-#include <scriptdocument.hxx>
+#include <basctl/scriptdocument.hxx>
 #include <basobj.hxx>
 #include <strings.hrc>
 #include <iderid.hxx>
diff --git a/basctl/source/inc/IDEComboBox.hxx 
b/basctl/source/inc/IDEComboBox.hxx
index a5e7008a42e9..0baf28b13cac 100644
--- a/basctl/source/inc/IDEComboBox.hxx
+++ b/basctl/source/inc/IDEComboBox.hxx
@@ -24,7 +24,7 @@
 #include <vcl/InterimItemWindow.hxx>
 
 #include "doceventnotifier.hxx"
-#include "scriptdocument.hxx"
+#include <basctl/scriptdocument.hxx>
 
 namespace basctl
 {
diff --git a/basctl/source/inc/basidesh.hxx b/basctl/source/inc/basidesh.hxx
index 3bf3abaa1a05..c1cedb982046 100644
--- a/basctl/source/inc/basidesh.hxx
+++ b/basctl/source/inc/basidesh.hxx
@@ -19,7 +19,7 @@
 #pragma once
 
 #include "doceventnotifier.hxx"
-#include "sbxitem.hxx"
+#include <basctl/sbxitem.hxx>
 #include "ObjectCatalog.hxx"
 
 #include <com/sun/star/container/XContainerListener.hpp>
diff --git a/basctl/source/inc/basobj.hxx b/basctl/source/inc/basobj.hxx
index 95e46b097f56..01ac1cbbb13a 100644
--- a/basctl/source/inc/basobj.hxx
+++ b/basctl/source/inc/basobj.hxx
@@ -18,7 +18,8 @@
  */
 #pragma once
 
-#include "scriptdocument.hxx"
+#include <basctl/basctldllpublic.hxx>
+#include <basctl/scriptdocument.hxx>
 #include <tools/long.hxx>
 
 class SbMethod;
@@ -44,14 +45,10 @@ namespace basctl
     void            BasicStopped( bool* pbAppWindowDisabled = nullptr, bool* 
pbDispatcherLocked = nullptr, sal_uInt16* pnWaitCount = nullptr,
                             SfxUInt16Item** ppSWActionCount = nullptr, 
SfxUInt16Item** ppSWLockViewCount = nullptr );
 
-    bool            IsValidSbxName( std::u16string_view rName );
-
     SAL_RET_MAYBENULL BasicManager*   FindBasicManager( StarBASIC const * pLib 
);
 
     SAL_RET_MAYBENULL SfxBindings*    GetBindingsPtr();
 
-    SAL_RET_MAYBENULL SfxDispatcher*  GetDispatcher ();
-
     void            InvalidateDebuggerSlots();
 
     // libraries
@@ -98,8 +95,6 @@ namespace basctl
 
     bool            RemoveDialog( const ScriptDocument& rDocument, const 
OUString& rLibName, const OUString& rDlgName );
 
-    void            MarkDocumentModified( const ScriptDocument& rDocument );
-
 } // namespace basctl
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/bastype2.hxx b/basctl/source/inc/bastype2.hxx
index 34115a1dff7d..292d59b3ea8a 100644
--- a/basctl/source/inc/bastype2.hxx
+++ b/basctl/source/inc/bastype2.hxx
@@ -26,7 +26,7 @@
 #include "doceventnotifier.hxx"
 
 #include <vcl/weld.hxx>
-#include "sbxitem.hxx"
+#include <basctl/sbxitem.hxx>
 #include <o3tl/typed_flags_set.hxx>
 
 class SbModule;
diff --git a/basctl/source/inc/bastypes.hxx b/basctl/source/inc/bastypes.hxx
index ecd744528056..e0362ef2163b 100644
--- a/basctl/source/inc/bastypes.hxx
+++ b/basctl/source/inc/bastypes.hxx
@@ -18,9 +18,9 @@
  */
 #pragma once
 
-#include "scriptdocument.hxx"
-
-#include "sbxitem.hxx"
+#include <basctl/basctldllpublic.hxx>
+#include <basctl/scriptdocument.hxx>
+#include <basctl/sbxitem.hxx>
 #include <svtools/scrolladaptor.hxx>
 #include <svtools/tabbar.hxx>
 #include <basic/sbdef.hxx>
@@ -297,10 +297,6 @@ sal_uInt32           CalcLineCount( SvStream& rStream );
 
 bool QueryReplaceMacro( std::u16string_view rName, weld::Widget* pParent );
 bool QueryDelMacro( std::u16string_view rName, weld::Widget* pParent );
-bool QueryDelDialog( std::u16string_view rName, weld::Widget* pParent );
-bool QueryDelModule( std::u16string_view rName, weld::Widget* pParent );
-bool QueryDelLib( std::u16string_view rName, bool bRef, weld::Widget* pParent 
);
-bool QueryPassword(weld::Widget* pDialogParent, const css::uno::Reference< 
css::script::XLibraryContainer >& xLibContainer, const OUString& rLibName, 
OUString& rPassword, bool bRepeat = false, bool bNewTitle = false);
 
 class ModuleInfoHelper
 {
diff --git a/basctl/source/inc/localizationmgr.hxx 
b/basctl/source/inc/localizationmgr.hxx
index 3e2ff0fc58a8..1070e609f18d 100644
--- a/basctl/source/inc/localizationmgr.hxx
+++ b/basctl/source/inc/localizationmgr.hxx
@@ -23,7 +23,7 @@
 
 #include <string_view>
 
-#include "scriptdocument.hxx"
+#include <basctl/scriptdocument.hxx>
 
 #include <com/sun/star/resource/XStringResourceManager.hpp>
 
diff --git a/chart2/uiconfig/menubar/menubar.xml 
b/chart2/uiconfig/menubar/menubar.xml
index e295d77a3943..53e300045e44 100644
--- a/chart2/uiconfig/menubar/menubar.xml
+++ b/chart2/uiconfig/menubar/menubar.xml
@@ -134,6 +134,8 @@
     <menu:menupopup>
       <menu:menu menu:id=".uno:MacrosMenu">
         <menu:menupopup>
+          <menu:menuitem menu:id=".uno:MacroManager"/>
+          <menu:menuseparator/>
           <menu:menuitem menu:id=".uno:MacroRecorder"/>
           <menu:menuitem menu:id=".uno:RunMacro"/>
           <menu:menuitem menu:id=".uno:BasicIDEAppear"/>
diff --git a/cui/Library_cui.mk b/cui/Library_cui.mk
index e01e33ecb4ec..4942d1548524 100644
--- a/cui/Library_cui.mk
+++ b/cui/Library_cui.mk
@@ -32,6 +32,7 @@ $(eval $(call gb_Library_use_sdk_api,cui))
 
 $(eval $(call gb_Library_use_libraries,cui,\
        $(call gb_Helper_optional,AVMEDIA,avmedia) \
+    basctl \
     basegfx \
     comphelper \
     cppu \
@@ -147,6 +148,7 @@ $(eval $(call gb_Library_add_exception_objects,cui,\
     cui/source/dialogs/GraphicTestsDialog \
     cui/source/dialogs/ImageViewerDialog \
     cui/source/dialogs/scriptdlg \
+    cui/source/dialogs/MacroManagerDialog \
     cui/source/dialogs/SignatureLineDialogBase \
     cui/source/dialogs/SignatureLineDialog \
     cui/source/dialogs/SignSignatureLineDialog \
diff --git a/cui/UIConfig_cui.mk b/cui/UIConfig_cui.mk
index 10acd83c8c39..601e58d2c9c4 100644
--- a/cui/UIConfig_cui.mk
+++ b/cui/UIConfig_cui.mk
@@ -116,6 +116,7 @@ $(eval $(call gb_UIConfig_add_uifiles,cui,\
        cui/uiconfig/ui/listdialog \
        cui/uiconfig/ui/macroassigndialog \
        cui/uiconfig/ui/macroassignpage \
+        cui/uiconfig/ui/macromanagerdialog \
        cui/uiconfig/ui/macroselectordialog \
        cui/uiconfig/ui/menuassignpage \
        cui/uiconfig/ui/mosaicdialog \
diff --git a/cui/inc/bitmaps.hlst b/cui/inc/bitmaps.hlst
index aab916827507..4b2d667f4673 100644
--- a/cui/inc/bitmaps.hlst
+++ b/cui/inc/bitmaps.hlst
@@ -62,8 +62,11 @@ inline constexpr OUString RID_SVXBMP_THEME_DEFAULT_BIG = 
u"svx/res/galdefl.png"_
 
 inline constexpr OUString RID_CUIBMP_HARDDISK = u"res/harddisk_16.png"_ustr;
 inline constexpr OUString RID_CUIBMP_LIB = u"res/im30820.png"_ustr;
+inline constexpr OUString RID_CUIBMP_DIALOG = u"res/im30823.png"_ustr;
 inline constexpr OUString RID_CUIBMP_MACRO = u"res/im30821.png"_ustr;
 inline constexpr OUString RID_CUIBMP_DOC = u"res/im30826.png"_ustr;
+inline constexpr OUString RID_CUIBMP_LOCKED = u"res/lock.png"_ustr;
+inline constexpr OUString RID_CUIBMP_LINKED = u"sw/res/nc20007.png"_ustr;
 
 inline constexpr OUString RID_SVXBMP_SCRIPT = u"res/script.png"_ustr;
 
diff --git a/cui/inc/strings.hrc b/cui/inc/strings.hrc
index 1674f7299f9a..0b5068b6fcae 100644
--- a/cui/inc/strings.hrc
+++ b/cui/inc/strings.hrc
@@ -436,4 +436,33 @@
 #define STR_STYLE_NO_LANGUAGE                       
NC_("STR_STYLE_NO_LANGUAGE", "Check if styles have a language set.")
 #define STR_DOCUMENT_TITLE                          NC_("STR_DOCUMENT_TITLE", 
"Check if the document title is set.")
 
+// Unified script organizer selector
+#define STR_LIBRARY                                 NC_("STR_LIBRARY", 
"Library")
+#define STR_MODULE                                  NC_("STR_MODULE", "Module")
+#define STR_DIALOG                                  NC_("STR_DIALOG", "Dialog")
+#define STR_MACRO                                   NC_("STR_MACRO", "Macro")
+
+#define STR_INPUTDIALOG_NEWLIBRARYTITLE             
NC_("STR_INPUTDIALOG_NEWLIBRARYTITLE", "New Library")
+#define STR_INPUTDIALOG_NEWLIBRARYLABEL             
NC_("STR_INPUTDIALOG_NEWLIBRARYLABEL", "Please enter a name for the new 
library:")
+#define STR_INPUTDIALOG_NEWMODULETITLE              
NC_("STR_INPUTDIALOG_NEWMODULETITLE", "New Module")
+#define STR_INPUTDIALOG_NEWMODULELABEL              
NC_("STR_INPUTDIALOG_NEWMODULELABEL", "Please enter a name for the new module:")
+#define STR_INPUTDIALOG_NEWDIALOGTITLE              
NC_("STR_INPUTDIALOG_NEWDIALOGTITLE", "New Dialog")
+#define STR_INPUTDIALOG_NEWDIALOGLABEL              
NC_("STR_INPUTDIALOG_NEWDIALOGLABEL", "Please enter a name for the new dialog:")
+#define STR_INPUTDIALOG_NEWMACROTITLE               
NC_("STR_INPUTDIALOG_NEWMACROTITLE", "New Macro")
+#define STR_INPUTDIALOG_NEWMACROLABEL               
NC_("STR_INPUTDIALOG_NEWMACROLABEL", "Please enter a name for the new macro:")
+
+#define STR_INPUTDIALOG_RENAMELIBRARYTITLE          
NC_("STR_INPUTDIALOG_RENAMELIBRARYTITLE", "Rename Library")
+#define STR_INPUTDIALOG_RENAMELIBRARYLABEL          
NC_("STR_INPUTDIALOG_RENAMELIBRARYLABEL", "Please enter a name to rename the 
library:")
+#define STR_INPUTDIALOG_RENAMEMODULETITLE           
NC_("STR_INPUTDIALOG_RENAMEMODULETITLE", "Rename Module")
+#define STR_INPUTDIALOG_RENAMEMODULELABEL           
NC_("STR_INPUTDIALOG_RENAMEMODULELABEL", "Please enter a name to rename the 
module:")
+#define STR_INPUTDIALOG_RENAMEDIALOGTITLE           
NC_("STR_INPUTDIALOG_RENAMEDIALOGTITLE", "Rename Dialog")
+#define STR_INPUTDIALOG_RENAMEDIALOGLABEL           
NC_("STR_INPUTDIALOG_RENAMEDIALOGLABEL", "Please enter a name to rename the 
dialog:")
+#define STR_INPUTDIALOG_RENAMEMACROTITLE            
NC_("STR_INPUTDIALOG_RENAMEMACROTITLE", "Rename Macro")
+#define STR_INPUTDIALOG_RENAMEMACROLABEL            
NC_("STR_INPUTDIALOG_RENAMEMACROLABEL", "Please enter a name to rename the 
macro:")
+
+#define STR_LIBISREADONLY                           NC_("STR_LIBISREADONLY", 
"This library is read-only.")
+#define STR_SBXNAMEALLREADYUSED                     
NC_("STR_SBXNAMEALLREADYUSED", "Name already exists")
+
+#define STR_SELECTEDENTRYNOTFOUND                   
NC_("STR_SELECTEDENTRYNOTFOUND", "The selected entry doesn't exist. It will be 
removed from the list.")
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/customize/cfgutil.cxx b/cui/source/customize/cfgutil.cxx
index 8646e5146cc5..5b1a9c9ced70 100644
--- a/cui/source/customize/cfgutil.cxx
+++ b/cui/source/customize/cfgutil.cxx
@@ -540,6 +540,9 @@ void CuiConfigGroupListBox::FillScriptList(const 
css::uno::Reference< css::scrip
 
             for ( Reference< browse::XBrowseNode > const & theChild : children 
)
             {
+                if (!theChild.is())
+                    continue;
+
                 bool bDisplay = true;
                 OUString uiName = theChild->getName();
                 if ( bIsRootNode )
@@ -576,6 +579,9 @@ void CuiConfigGroupListBox::FillScriptList(const 
css::uno::Reference< css::scrip
 
                         for ( const auto& rxNode : grandchildren )
                         {
+                            if (!rxNode.is())
+                                continue;
+
                             if ( rxNode->getType() == 
browse::BrowseNodeTypes::CONTAINER )
                             {
                                 bChildOnDemand = true;
@@ -875,59 +881,59 @@ void CuiConfigGroupListBox::GroupSelected()
 
         case SfxCfgKind::GROUP_SCRIPTCONTAINER:
         {
-            if (!m_xTreeView->iter_has_child(*xIter))
-            {
-                Reference< browse::XBrowseNode > rootNode(
-                    static_cast< browse::XBrowseNode* >( pInfo->pObject ) ) ;
+            Reference< browse::XBrowseNode > rootNode(
+                static_cast< browse::XBrowseNode* >( pInfo->pObject ) ) ;
+
+            try {
+                if ( rootNode->hasChildNodes() )
+                {
+                    const Sequence< Reference< browse::XBrowseNode > > 
children =
+                        rootNode->getChildNodes();
 
-                try {
-                    if ( rootNode->hasChildNodes() )
+                    for ( const Reference< browse::XBrowseNode >& childNode : 
children )
                     {
-                        const Sequence< Reference< browse::XBrowseNode > > 
children =
-                            rootNode->getChildNodes();
+                        if (!childNode.is())
+                            continue;
 
-                        for ( const Reference< browse::XBrowseNode >& 
childNode : children )
+                        if (childNode->getType() == 
browse::BrowseNodeTypes::SCRIPT)
                         {
-                            if (childNode->getType() == 
browse::BrowseNodeTypes::SCRIPT)
-                            {
-                                OUString uri, description;
+                            OUString uri, description;
 
-                                Reference < beans::XPropertySet >xPropSet( 
childNode, UNO_QUERY );
-                                if (!xPropSet.is())
-                                {
-                                    continue;
-                                }
+                            Reference < beans::XPropertySet >xPropSet( 
childNode, UNO_QUERY );
+                            if (!xPropSet.is())
+                            {
+                                continue;
+                            }
 
-                                Any value =
-                                    xPropSet->getPropertyValue(u"URI"_ustr);
-                                value >>= uri;
+                            Any value =
+                                xPropSet->getPropertyValue(u"URI"_ustr);
+                            value >>= uri;
 
-                                try
-                                {
-                                    value = 
xPropSet->getPropertyValue(u"Description"_ustr);
-                                    value >>= description;
-                                }
-                                catch (Exception &) {
-                                    // do nothing, the description will be 
empty
-                                }
+                            try
+                            {
+                                value = 
xPropSet->getPropertyValue(u"Description"_ustr);
+                                value >>= description;
+                            }
+                            catch (Exception &) {
+                                // do nothing, the description will be empty
+                            }
 
-                                OUString* pScriptURI = new OUString( uri );
+                            OUString* pScriptURI = new OUString( uri );
 
-                                OUString aImage = GetImage(childNode, 
Reference< XComponentContext >(), false);
-                                m_pFunctionListBox->aArr.push_back( 
std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::FUNCTION_SCRIPT, 0, pScriptURI 
));
-                                m_pFunctionListBox->aArr.back()->sCommand = 
uri;
-                                m_pFunctionListBox->aArr.back()->sLabel = 
childNode->getName();
-                                m_pFunctionListBox->aArr.back()->sHelpText = 
description;
+                            OUString aImage = GetImage(childNode, Reference< 
XComponentContext >(), false);
+                            m_pFunctionListBox->aArr.push_back( 
std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::FUNCTION_SCRIPT, 0, pScriptURI 
));
+                            m_pFunctionListBox->aArr.back()->sCommand = uri;
+                            m_pFunctionListBox->aArr.back()->sLabel = 
childNode->getName();
+                            m_pFunctionListBox->aArr.back()->sHelpText = 
description;
 
-                                OUString 
sId(weld::toId(m_pFunctionListBox->aArr.back().get()));
-                                m_pFunctionListBox->append(sId, 
childNode->getName(), aImage);
-                            }
+                            OUString 
sId(weld::toId(m_pFunctionListBox->aArr.back().get()));
+                            m_pFunctionListBox->append(sId, 
childNode->getName(), aImage);
                         }
                     }
                 }
-                catch (RuntimeException&) {
-                    // do nothing, the entry will not be displayed in the UI
-                }
+            }
+            catch (RuntimeException&) {
+                // do nothing, the entry will not be displayed in the UI
             }
             break;
         }
@@ -1032,23 +1038,10 @@ IMPL_LINK(CuiConfigGroupListBox, ExpandingHdl, const 
weld::TreeIter&, rIter, boo
 #if HAVE_FEATURE_SCRIPTING
 void CuiConfigGroupListBox::SelectMacro( const SfxMacroInfoItem *pItem )
 {
-    auto const rMacro = pItem->GetQualifiedName();
-    sal_Int32 nIdx {rMacro.lastIndexOf('.')};
-    const std::u16string_view aMethod( rMacro.subView(nIdx + 1) );
-    std::u16string_view aLib;
-    std::u16string_view aModule;
-    if ( nIdx>0 )
-    {
-        // string contains at least 2 tokens
-        nIdx = rMacro.lastIndexOf('.', nIdx);
-        if (nIdx != -1)
-        {
-            // string contains at least 3 tokens
-            aLib = o3tl::getToken(rMacro, 0, '.' );
-            sal_Int32 nIdx2 = nIdx + 1;
-            aModule = o3tl::getToken(rMacro, 0, '.', nIdx2 );
-        }
-    }
+    const std::u16string_view aLocation = pItem->GetLocation();
+    const std::u16string_view aLib = pItem->GetLib();
+    const std::u16string_view aModule = pItem->GetModule();
+    const std::u16string_view aMethod = pItem->GetMethod();
 
     std::unique_ptr<weld::TreeIter> xIter = m_xTreeView->make_iterator();
     if (!m_xTreeView->get_iter_first(*xIter))
@@ -1065,6 +1058,8 @@ void CuiConfigGroupListBox::SelectMacro( const 
SfxMacroInfoItem *pItem )
             {
                 do
                 {
+                    if (aLocation !=  m_xTreeView->get_text(*xLocationIter))
+                        continue;
                     m_xTreeView->expand_row(*xLocationIter);
                     std::unique_ptr<weld::TreeIter> xLibIter = 
m_xTreeView->make_iterator(xLocationIter.get());
                     if (m_xTreeView->iter_children(*xLibIter))
@@ -1074,6 +1069,34 @@ void CuiConfigGroupListBox::SelectMacro( const 
SfxMacroInfoItem *pItem )
                             OUString aEntryLib = 
m_xTreeView->get_text(*xLibIter);
                             if (aEntryLib == aLib)
                             {
+                                if (aModule.empty())
+                                {
+                                    m_xTreeView->scroll_to_row(*xLibIter);
+                                    m_xTreeView->select(*xLibIter);
+                                    GroupSelected();
+                                    weld::TreeView& rFunctionListBoxTreeView
+                                        = m_pFunctionListBox->get_widget();
+                                    std::unique_ptr<weld::TreeIter> 
xFunctionListBoxIter
+                                        = 
rFunctionListBoxTreeView.make_iterator();
+                                    if 
(!rFunctionListBoxTreeView.get_iter_first(
+                                            *xFunctionListBoxIter))
+                                        return;
+                                    do
+                                    {
+                                        OUString aEntryMethod = 
rFunctionListBoxTreeView.get_text(
+                                            *xFunctionListBoxIter);
+                                        if (aEntryMethod == aMethod)
+                                        {
+                                            
rFunctionListBoxTreeView.scroll_to_row(
+                                                *xFunctionListBoxIter);
+                                            
rFunctionListBoxTreeView.select(*xFunctionListBoxIter);
+                                            return;
+                                        }
+                                    } while (
+                                        
rFunctionListBoxTreeView.iter_next(*xFunctionListBoxIter));
+                                    return;
+                                }
+
                                 m_xTreeView->expand_row(*xLibIter);
                                 std::unique_ptr<weld::TreeIter> xModIter = 
m_xTreeView->make_iterator(xLibIter.get());
                                 if (m_xTreeView->iter_children(*xModIter))
diff --git a/cui/source/dialogs/MacroManagerDialog.cxx 
b/cui/source/dialogs/MacroManagerDialog.cxx
new file mode 100644
index 000000000000..021bcaf19751
--- /dev/null
+++ b/cui/source/dialogs/MacroManagerDialog.cxx
@@ -0,0 +1,2512 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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 <MacroManagerDialog.hxx>
+
+#include <bitmaps.hlst>
+#include <cfgutil.hxx>
+#include <dialmgr.hxx>
+#include <scriptdlg.hxx>
+#include <strings.hrc>
+#include <basctl/basctldllpublic.hxx>
+#include <basctl/sbxitem.hxx>
+#include <basctl/scriptdocument.hxx>
+#include <basic/basmgr.hxx>
+#include <comphelper/SetFlagContextHelper.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/documentinfo.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/inputdlg.hxx>
+#include <sfx2/minfitem.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <svl/itemset.hxx>
+#include <svl/stritem.hxx>
+#include <svtools/imagemgr.hxx>
+#include <svx/passwd.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/viewoptions.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/weldutils.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/document/XEmbeddedScripts.hpp>
+#include <com/sun/star/document/XScriptInvocationContext.hpp>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/script/browse/XBrowseNode.hpp>
+#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
+#include <com/sun/star/script/browse/theBrowseNodeFactory.hpp>
+#include <com/sun/star/script/browse/BrowseNodeFactoryViewTypes.hpp>
+#include <com/sun/star/script/XLibraryContainer2.hpp>
+#include <com/sun/star/script/XLibraryContainerPassword.hpp>
+#include <com/sun/star/script/XPersistentLibraryContainer.hpp>
+#include <com/sun/star/script/XInvocation.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+
+ScriptsListBox::ScriptsListBox(std::unique_ptr<weld::TreeView> xTreeView)
+    : m_xTreeView(std::move(xTreeView))
+    , m_xScratchIter(m_xTreeView->make_iterator())
+{
+    m_xTreeView->make_sorted();
+    m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 
35,
+                                  m_xTreeView->get_height_rows(9));
+    m_xTreeView->connect_query_tooltip(LINK(this, ScriptsListBox, 
QueryTooltip));
+}
+
+ScriptsListBox::~ScriptsListBox() { ClearAll(); }
+
+void ScriptsListBox::ClearAll()
+{
+    sal_uInt16 nCount = aArr.size();
+    for (sal_uInt16 i = 0; i < nCount; ++i)
+    {
+        ScriptInfo* pScriptInfo = aArr[i].get();
+        if (pScriptInfo && pScriptInfo->pBrowseNode)
+            pScriptInfo->pBrowseNode->release();
+    }
+    aArr.clear();
+    m_xTreeView->clear();
+}
+
+void ScriptsListBox::Remove(const weld::TreeIter& rEntry)
+{
+    ScriptInfo* pScriptInfo = 
weld::fromId<ScriptInfo*>(m_xTreeView->get_id(rEntry));
+    if (pScriptInfo)
+    {
+        if (pScriptInfo->pBrowseNode)
+            pScriptInfo->pBrowseNode->release();
+        for (auto it = aArr.begin(); it != aArr.end(); ++it)
+        {
+            if ((*it).get() == pScriptInfo)
+            {
+                aArr.erase(it);
+                break;
+            }
+        }
+    }
+    m_xTreeView->remove(rEntry);
+}
+
+OUString ScriptsListBox::GetDescriptionText(const OUString& rId)
+{
+    ScriptInfo* pScriptInfo = weld::fromId<ScriptInfo*>(rId);
+    if (pScriptInfo)
+    {
+        return pScriptInfo->sDescription;
+    }
+    return OUString();
+}
+
+OUString ScriptsListBox::GetSelectedScriptName()
+{
+    std::unique_ptr<weld::TreeIter> xScriptsEntryIter = 
m_xTreeView->make_iterator();
+    if (!m_xTreeView->get_selected(xScriptsEntryIter.get()))
+        return OUString();
+    return m_xTreeView->get_text(*xScriptsEntryIter);
+}
+
+IMPL_LINK(ScriptsListBox, QueryTooltip, const weld::TreeIter&, rEntryIter, 
OUString)
+{
+    return GetDescriptionText(m_xTreeView->get_id(rEntryIter));
+}
+
+ScriptContainersListBox::ScriptContainersListBox(std::unique_ptr<weld::TreeView>
 xTreeView,
+                                                 MacroManagerDialog* 
pMacroManagerDialog)
+    : m_pScriptsListBox(nullptr)
+    , m_xTreeView(std::move(xTreeView))
+    , m_pMacroManagerDialog(pMacroManagerDialog)
+{
+    m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 
35,
+                                  m_xTreeView->get_height_rows(9));
+    m_xTreeView->connect_expanding(LINK(this, ScriptContainersListBox, 
ExpandingHdl));
+    m_xTreeView->connect_query_tooltip(LINK(this, ScriptContainersListBox, 
QueryTooltip));
+}
+
+ScriptContainersListBox::~ScriptContainersListBox() { ClearAll(); }
+
+void ScriptContainersListBox::ClearAll()
+{
+    sal_uInt16 nCount = m_xTreeView->n_children();
+    for (sal_uInt16 i = 0; i < nCount; ++i)
+    {
+        ScriptContainerInfo* pScriptContainerInfo
+            = weld::fromId<ScriptContainerInfo*>(m_xTreeView->get_id(i));
+        if (pScriptContainerInfo)
+        {
+            if (pScriptContainerInfo->pBrowseNode)
+                pScriptContainerInfo->pBrowseNode->release();
+            delete pScriptContainerInfo;
+        }
+    }
+    m_xTreeView->clear();
+}
+
+void ScriptContainersListBox::Init(const 
css::uno::Reference<css::uno::XComponentContext>& xContext,
+                                   const 
css::uno::Reference<css::frame::XFrame>& xFrame)
+{
+    m_xContext = xContext;
+    m_xFrame = xFrame;
+    m_xTreeView->freeze();
+    Fill(nullptr);
+    m_xTreeView->thaw();
+    m_xTreeView->set_cursor(0);
+}
+
+void ScriptContainersListBox::Remove(const weld::TreeIter* pEntryIter, bool 
bRemoveEntryIter)
+{
+    // remove all children of pEntryIter
+    std::unique_ptr<weld::TreeIter> xIter = 
m_xTreeView->make_iterator(pEntryIter);
+    if (m_xTreeView->iter_has_child(*pEntryIter) && 
m_xTreeView->iter_children(*xIter))
+    {
+        // set xIter to the last child of pEntryIter
+        do
+        {
+            std::unique_ptr<weld::TreeIter> xChildIter = 
m_xTreeView->make_iterator(xIter.get());
+            while (m_xTreeView->iter_next_sibling(*xChildIter))
+                m_xTreeView->copy_iterator(*xChildIter, *xIter);
+        } while (m_xTreeView->iter_has_child(*xIter) && 
m_xTreeView->iter_children(*xIter));
+
+        // children must be removed from the tree in reverse order
+        std::unique_ptr<weld::TreeIter> xRemoveIter = 
m_xTreeView->make_iterator();
+        while (m_xTreeView->iter_compare(*xIter, *pEntryIter) != 0)
+        {
+            m_xTreeView->copy_iterator(*xIter, *xRemoveIter);
+            m_xTreeView->iter_previous(*xIter);
+            ScriptContainerInfo* pScriptContainerInfo
+                = 
weld::fromId<ScriptContainerInfo*>(m_xTreeView->get_id(*xRemoveIter));
+            if (pScriptContainerInfo)
+            {
+                if (pScriptContainerInfo->pBrowseNode)
+                    pScriptContainerInfo->pBrowseNode->release();
+                delete pScriptContainerInfo;
+            }
+            m_xTreeView->remove(*xRemoveIter);
+        }
+    }
+
+    // maybe remove the entry
+    if (bRemoveEntryIter)
+    {
+        ScriptContainerInfo* pScriptContainerInfo
+            = 
weld::fromId<ScriptContainerInfo*>(m_xTreeView->get_id(*pEntryIter));
+        if (pScriptContainerInfo)
+        {
+            if (pScriptContainerInfo->pBrowseNode)
+                pScriptContainerInfo->pBrowseNode->release();
+            delete pScriptContainerInfo;
+        }
+        m_xTreeView->remove(*pEntryIter);
+    }
+}
+
+// inspired by CuiConfigGroupListBox::FillScriptList
+// cui/source/customize/cfgutil.cxx
+void ScriptContainersListBox::Fill(const weld::TreeIter* pEntryIter)
+{
+    weld::WaitObject aWait(m_pMacroManagerDialog->getDialog());
+
+    css::uno::Reference<css::script::browse::XBrowseNode> xNode;
+    if (pEntryIter == nullptr)
+    {
+        ClearAll();
+        try
+        {
+            css::uno::Reference<css::script::browse::XBrowseNodeFactory> xFac
+                = css::script::browse::theBrowseNodeFactory::get(
+                    comphelper::getProcessComponentContext());
+            xNode.set(
+                
xFac->createView(css::script::browse::BrowseNodeFactoryViewTypes::MACROORGANIZER));
+        }
+        catch (const css::uno::Exception&)
+        {
+            TOOLS_WARN_EXCEPTION(
+                "cui.dialogs", "Caught some exception whilst retrieving browse 
nodes from factory");
+            // TODO exception handling
+            return;
+        }
+    }
+    else
+    {
+        ScriptContainerInfo* pScriptContainerInfoEntry
+            = 
weld::fromId<ScriptContainerInfo*>(m_xTreeView->get_id(*pEntryIter));
+
+        xNode.set(pScriptContainerInfoEntry->pBrowseNode);
+
+        Remove(pEntryIter, /*bRemoveEntryIter*/ false);
+    }
+
+    if (xNode->hasChildNodes())
+    {
+        // tdf#120362: Don't ask to enable disabled Java when filling script 
list
+        css::uno::ContextLayer 
layer(comphelper::NoEnableJavaInteractionContext());
+
+        bool bIsRootNode = false;
+
+        OUString user(u"user"_ustr);
+        OUString share(u"share"_ustr);
+        OUString uno_packages(u"uno_packages"_ustr);
+        if (xNode->getName() == "Root")
+        {
+            bIsRootNode = true;
+        }
+
+        //To mimic current starbasic behaviour we
+        //need to make sure that only the current document
+        //is displayed in the config tree. Tests below
+        //set the bDisplay flag to FALSE if the current
+        //node is a first level child of the Root and is NOT
+        //either the current document, user or share
+        //
+        // NOTE: This approach doesn't work for open documents with the same 
name, for example
+        // Untitled 1.odt and Untitled 1.ods will both be included as root 
containers.
+        OUString currentDocTitle;
+        if (css::uno::Reference<css::frame::XController> xController = 
m_xFrame->getController();
+            xController.is())
+        {
+            css::uno::Reference<css::frame::XModel> xModel = 
xController->getModel();
+            if (xModel.is())
+                currentDocTitle = 
comphelper::DocumentInfo::getDocumentTitle(xModel);
+        }
+
+        const 
css::uno::Sequence<css::uno::Reference<css::script::browse::XBrowseNode>> 
children
+            = xNode->getChildNodes();
+        for (css::uno::Reference<css::script::browse::XBrowseNode> const& 
theChild : children)
+        {
+            if (!theChild.is())
+                continue;
+
+            if (theChild->getType() == 
css::script::browse::BrowseNodeTypes::SCRIPT)
+                // we only want containers in this list box
+                continue;
+            if (theChild->getName() == uno_packages)
+                continue;
+
+            OUString uiName = theChild->getName();
+            if (bIsRootNode)
+            {
+                if (uiName == user)
+                {
+                    uiName = CuiResId(RID_CUISTR_MYMACROS);
+                }
+                else if (uiName == share)
+                {
+                    uiName = CuiResId(RID_CUISTR_PRODMACROS);
+                }
+                else if (uiName != currentDocTitle)
+                {
+                    // as noted above
+                    // NOTE: This approach doesn't work for open documents 
with the same name, for
+                    // example, Untitled 1.odt and Untitled 1.ods will both be 
included as root
+                    // containers.
+                    continue;
+                }
+            }
+
+            // We call acquire on the XBrowseNode so that it does not
+            // get autodestructed and become invalid when accessed later.
+            theChild->acquire();
+
+            bool bChildOnDemand = false;
+
+            if (theChild->hasChildNodes())
+            {
+                const 
css::uno::Sequence<css::uno::Reference<css::script::browse::XBrowseNode>>
+                    grandchildren = theChild->getChildNodes();
+                for (const auto& rxNode : grandchildren)
+                {
+                    if (!rxNode.is())
+                        continue;
+                    if (rxNode->getType() == 
css::script::browse::BrowseNodeTypes::CONTAINER)
+                    {
+                        bChildOnDemand = true;
+                        break;
+                    }
+                }
+            }
+
+            OUString aImage = CuiConfigGroupListBox::GetImage(theChild, 
m_xContext, bIsRootNode);
+            Insert(theChild, pEntryIter, uiName, aImage, bChildOnDemand);
+        }
+    }
+
+    // add Basic dialogs
+    if (pEntryIter && m_xTreeView->get_iter_depth(*pEntryIter) == 2) // library
+    {
+        // parent node of entry node is a language node
+        std::unique_ptr<weld::TreeIter> xIter = 
m_xTreeView->make_iterator(pEntryIter);
+        m_xTreeView->iter_parent(*xIter); // language
+        if (m_xTreeView->get_text(*xIter) == "Basic")
+        {
+            basctl::ScriptDocument aDocument = GetScriptDocument(pEntryIter);
+            if (!aDocument.isAlive())
+            {
+                return;
+            }
+
+            OUString aLibName = m_xTreeView->get_text(*pEntryIter);
+
+            css::uno::Reference<css::script::XLibraryContainer> 
xDlgLibContainer(
+                aDocument.getLibraryContainer(basctl::E_DIALOGS));
+
+            if (xDlgLibContainer.is() && xDlgLibContainer->hasByName(aLibName)
+                && !xDlgLibContainer->isLibraryLoaded(aLibName))
+            {
+                xDlgLibContainer->loadLibrary(aLibName);
+            }
+
+            if (!(xDlgLibContainer.is() && 
xDlgLibContainer->hasByName(aLibName)
+                  && xDlgLibContainer->isLibraryLoaded(aLibName)))
+            {
+                return;
+            }
+
+            for (const OUString& rDlgName : 
aDocument.getObjectNames(basctl::E_DIALOGS, aLibName))
+            {
+                Insert(nullptr, pEntryIter, rDlgName, RID_CUIBMP_DIALOG, 
false);
+            }
+        }
+    }
+}
+
+void ScriptContainersListBox::Insert(
+    const css::uno::Reference<css::script::browse::XBrowseNode>& xInsertNode,
+    const weld::TreeIter* pIter, const OUString& rsUiName, const OUString& 
rsImage,
+    bool bChildOnDemand, int nPos, weld::TreeIter* pRet)
+{
+    std::unique_ptr<weld::TreeIter> xNewEntryIter = 
m_xTreeView->make_iterator();
+
+    OUString sId(weld::toId(new ScriptContainerInfo(xInsertNode.get())));
+    m_xTreeView->insert(pIter, nPos, &rsUiName, &sId, nullptr, nullptr, 
bChildOnDemand,
+                        xNewEntryIter.get());
+    m_xTreeView->set_image(*xNewEntryIter, rsImage);
+
+    //  set password and linked image only for Basic libraries
+    if (m_xTreeView->get_iter_depth(*xNewEntryIter) == 2) // library
+    {
+        std::unique_ptr<weld::TreeIter> xLanguageIter
+            = m_xTreeView->make_iterator(xNewEntryIter.get());
+        m_xTreeView->iter_parent(*xLanguageIter);
+        if (m_xTreeView->get_text(*xLanguageIter) == "Basic")
+        {
+            basctl::ScriptDocument aDocument = 
GetScriptDocument(xNewEntryIter.get());
+            if (!aDocument.isAlive())
+                return;
+
+            OUString aLibName = m_xTreeView->get_text(*xNewEntryIter);
+
+            css::uno::Reference<css::script::XLibraryContainer2> 
xModLibContainer(
+                aDocument.getLibraryContainer(basctl::E_SCRIPTS), 
css::uno::UNO_QUERY);
+            if (xModLibContainer.is() && xModLibContainer->hasByName(aLibName))
+            {
+                css::uno::Reference<css::script::XLibraryContainerPassword> 
xPasswd(
+                    xModLibContainer, css::uno::UNO_QUERY);
+                if (xPasswd.is() && 
xPasswd->isLibraryPasswordProtected(aLibName))
+                {
+                    // password protected
+                    m_xTreeView->set_image(*xNewEntryIter, RID_CUIBMP_LOCKED);
+                }
+                else if (xModLibContainer->isLibraryLink(aLibName))
+                {
+                    // linked
+                    m_xTreeView->set_image(*xNewEntryIter, RID_CUIBMP_LINKED);
+                }
+            }
+        }
+    }
+    if (pRet)
+        pRet = xNewEntryIter.get();
+}
+
+// fills the scripts list box
+// inspired by code in void CommandCategoryListBox::addChildren
+// cui/source/customize/CommandCategoryListBox.cxx
+// and void CuiConfigGroupListBox::GroupSelected()
+// cui/source/customize/cfgutil.cxx
+void ScriptContainersListBox::ScriptContainerSelected()
+{
+    std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
+    if (!m_xTreeView->get_selected(xIter.get()))
+        return;
+
+    m_pScriptsListBox->freeze();
+    m_pScriptsListBox->ClearAll();
+
+    if (!m_xTreeView->iter_has_child(*xIter) && 
!m_xTreeView->get_children_on_demand(*xIter))
+    {
+        // maybe the browse node has children and those children are most 
likely script nodes
+        ScriptContainerInfo* pScriptContainerInfo
+            = weld::fromId<ScriptContainerInfo*>(m_xTreeView->get_id(*xIter));
+        css::uno::Reference<css::script::browse::XBrowseNode> xBrowseNode(
+            pScriptContainerInfo->pBrowseNode);
+        try
+        {
+            if (xBrowseNode->hasChildNodes())
+            {
+                const 
css::uno::Sequence<css::uno::Reference<css::script::browse::XBrowseNode>>
+                    children = xBrowseNode->getChildNodes();
+
+                for (const 
css::uno::Reference<css::script::browse::XBrowseNode>& childNode :
+                     children)
+                {
+                    if (!childNode.is())
+                        continue;
+
+                    if (childNode->getType() == 
css::script::browse::BrowseNodeTypes::SCRIPT)
+                    {
+                        css::uno::Reference<css::beans::XPropertySet> 
xPropSet(childNode,
+                                                                               
css::uno::UNO_QUERY);
+                        if (!xPropSet.is())
+                        {
+                            continue;
+                        }
+
+                        OUString sURI;
+                        try
+                        {
+                            css::uno::Any value = 
xPropSet->getPropertyValue(u"URI"_ustr);
+                            value >>= sURI;
+                        }
+                        catch (css::uno::Exception&)
+                        {
+                            // do nothing, the URI will be empty
+                        }
+
+                        OUString sDescription;
+                        try
+                        {
+                            css::uno::Any value = 
xPropSet->getPropertyValue(u"Description"_ustr);
+                            value >>= sDescription;
+                        }
+                        catch (css::uno::Exception&)
+                        {
+                            // do nothing, the description will be empty
+                        }
+
+                        childNode->acquire();
+
+                        m_pScriptsListBox->aArr.push_back(
+                            std::make_unique<ScriptInfo>(childNode.get(), 
sURI, sDescription));
+
+                        OUString 
sId(weld::toId(m_pScriptsListBox->aArr.back().get()));
+                        m_pScriptsListBox->append(sId, childNode->getName(), 
RID_CUIBMP_MACRO);
+                    }
+                }
+            }
+        }
+        catch (css::uno::RuntimeException&)
+        {
+            // do nothing, the entry will not be displayed in the UI
+        }
+    }
+
+    m_pScriptsListBox->thaw();
+
+    if (m_pScriptsListBox->n_children())
+        m_pScriptsListBox->select(0);
+}
+
+OUString ScriptContainersListBox::GetContainerName(const weld::TreeIter& rIter,
+                                                   const ScriptContainerType 
eScriptContainerType)
+{
+    weld::TreeView& rScriptContainersTreeView = *m_xTreeView;
+    std::unique_ptr<weld::TreeIter> xSelectedEntryIter
+        = rScriptContainersTreeView.make_iterator(&rIter);
+
+    std::unique_ptr<weld::TreeIter> xIter
+        = rScriptContainersTreeView.make_iterator(xSelectedEntryIter.get());
+
+    int nEntryDepth;
+    while ((nEntryDepth = rScriptContainersTreeView.get_iter_depth(*xIter)))
+    {
+        if ((nEntryDepth == 3 && eScriptContainerType == 
ScriptContainerType::MODULEORDIALOG)
+            || (nEntryDepth == 2 && eScriptContainerType == 
ScriptContainerType::LIBRARY)
+            || (nEntryDepth == 1 && eScriptContainerType == 
ScriptContainerType::LANGUAGE))
+            return rScriptContainersTreeView.get_text(*xIter);
+        rScriptContainersTreeView.iter_parent(*xIter);
+    }
+    if (eScriptContainerType == ScriptContainerType::LOCATION)
+        return rScriptContainersTreeView.get_text(*xIter);
+
+    return OUString();
+}
+
+OUString
+ScriptContainersListBox::GetSelectedEntryContainerName(ScriptContainerType 
eScriptContainerType)
+{
+    std::unique_ptr<weld::TreeIter> xSelectedEntryIter = 
m_xTreeView->make_iterator();
+    if (!m_xTreeView->get_selected(xSelectedEntryIter.get()))
+        return OUString(); // should never happen
+    return GetContainerName(*xSelectedEntryIter, eScriptContainerType);
+}
+
+IMPL_LINK(ScriptContainersListBox, QueryTooltip, const weld::TreeIter&, 
rEntryIter, OUString)
+{
+    // for Basic library check for linked library
+    if (m_xTreeView->get_iter_depth(rEntryIter) == 2) // library
+    {
+        // language
+        std::unique_ptr<weld::TreeIter> xLanguageIter = 
m_xTreeView->make_iterator(&rEntryIter);
+        m_xTreeView->iter_parent(*xLanguageIter);
+        if (m_xTreeView->get_text(*xLanguageIter) == "Basic")
+        {
+            basctl::ScriptDocument aDocument = GetScriptDocument(&rEntryIter);
+            if (!aDocument.isAlive())
+                return OUString();
+
+            css::uno::Reference<css::script::XLibraryContainer2> 
xModLibContainer(
+                aDocument.getLibraryContainer(basctl::E_SCRIPTS), 
css::uno::UNO_QUERY);
+            // check for linked library
+            OUString aLibName = m_xTreeView->get_text(rEntryIter);
+            if (xModLibContainer.is() && xModLibContainer->hasByName(aLibName)
+                && xModLibContainer->isLibraryLink(aLibName))
+            {
+                OUString aLinkURL = 
xModLibContainer->getLibraryLinkURL(aLibName);
+                return aLinkURL;
+            }
+        }
+    }
+    return OUString();
+}
+
+IMPL_LINK(ScriptContainersListBox, ExpandingHdl, const weld::TreeIter&, 
rEntryIter, bool)
+{
+    // for Basic library check for password protected
+    if (m_xTreeView->get_iter_depth(rEntryIter) == 2) // library
+    {
+        // language
+        std::unique_ptr<weld::TreeIter> xLanguageIter = 
m_xTreeView->make_iterator(&rEntryIter);
+        m_xTreeView->iter_parent(*xLanguageIter);
+        if (m_xTreeView->get_text(*xLanguageIter) == "Basic")
+        {
+            basctl::ScriptDocument aDocument = GetScriptDocument(&rEntryIter);
+            if (!aDocument.isAlive())
+                return false; // not expanded
+
+            OUString aLibName = m_xTreeView->get_text(rEntryIter);
+
+            // check if the library is password protected
+            css::uno::Reference<css::script::XLibraryContainer2> 
xModLibContainer(
+                aDocument.getLibraryContainer(basctl::E_SCRIPTS), 
css::uno::UNO_QUERY);
+            if (xModLibContainer.is() && xModLibContainer->hasByName(aLibName))
+            {
+                css::uno::Reference<css::script::XLibraryContainerPassword> 
xPasswd(
+                    xModLibContainer, css::uno::UNO_QUERY);
+                if (xPasswd.is() && 
xPasswd->isLibraryPasswordProtected(aLibName)
+                    && !xPasswd->isLibraryPasswordVerified(aLibName))
+                {
+                    // ensure selection before password dialog is shown
+                    m_xTreeView->select(rEntryIter);
+                    OUString sPassword;
+                    if 
(!basctl::QueryPassword(m_pMacroManagerDialog->getDialog(), xModLibContainer,
+                                               aLibName, sPassword, true, 
true))
+                    {
+                        return false; // indicates the expansion of the row is 
refused
+                    }
+                }
+            }
+        }
+    }
+
+    if (m_xTreeView->get_children_on_demand(rEntryIter))
+    {
+        Fill(&rEntryIter);
+    }
+
+    return true;
+}
+
+MacroManagerDialog::MacroManagerDialog(weld::Window* pParent,
+                                       const 
css::uno::Reference<css::frame::XFrame>& xDocFrame)
+    : GenericDialogController(pParent, u"cui/ui/macromanagerdialog.ui"_ustr,
+                              u"MacroManagerDialog"_ustr)
+    , m_xDocumentFrame(xDocFrame)
+    , m_xScriptContainersListBox(
+          new 
ScriptContainersListBox(m_xBuilder->weld_tree_view(u"scriptcontainers"_ustr), 
this))
+    , m_xScriptsListBox(new 
ScriptsListBox(m_xBuilder->weld_tree_view(u"scripts"_ustr)))
+    , 
m_xScriptContainersListBoxLabel(m_xBuilder->weld_label(u"scriptcontainerlistboxlabel"_ustr))
+    , 
m_xScriptsListBoxLabel(m_xBuilder->weld_label(u"scriptslistboxlabel"_ustr))
+    , m_xRunButton(m_xBuilder->weld_button(u"run"_ustr))
+    , m_xCloseButton(m_xBuilder->weld_button(u"close"_ustr))
+    , m_xDescriptionText(m_xBuilder->weld_text_view(u"description"_ustr))
+    , m_xDescriptionFrame(m_xBuilder->weld_frame(u"descriptionframe"_ustr))
+    , m_xNewLibraryButton(m_xBuilder->weld_button(u"newlibrary"_ustr))
+    , m_xNewModuleButton(m_xBuilder->weld_button(u"newmodule"_ustr))
+    , m_xNewDialogButton(m_xBuilder->weld_button(u"newdialog"_ustr))
+    , 
m_xLibraryModuleDialogEditButton(m_xBuilder->weld_button(u"librarymoduledialogedit"_ustr))
+    , 
m_xLibraryModuleDialogRenameButton(m_xBuilder->weld_button(u"librarymoduledialogrename"_ustr))
+    , 
m_xLibraryModuleDialogDeleteButton(m_xBuilder->weld_button(u"librarymoduledialogdelete"_ustr))
+    , 
m_xLibraryPasswordButton(m_xBuilder->weld_button(u"librarypassword"_ustr))
+    , m_xLibraryImportButton(m_xBuilder->weld_button(u"libraryimport"_ustr))
+    , m_xLibraryExportButton(m_xBuilder->weld_button(u"libraryexport"_ustr))
+    , m_xMacroEditButton(m_xBuilder->weld_button(u"macroedit"_ustr))
+    , m_xMacroDeleteButton(m_xBuilder->weld_button(u"macrodelete"_ustr))
+    , m_xMacroCreateButton(m_xBuilder->weld_button(u"macrocreate"_ustr))
+    , m_xMacroRenameButton(m_xBuilder->weld_button(u"macrorename"_ustr))
+    , m_xAssignButton(m_xBuilder->weld_button(u"assign"_ustr))
+{
+    m_aScriptsListBoxLabelBaseStr = m_xScriptsListBoxLabel->get_label();
+
+    m_xScriptContainersListBox->SetScriptsListBox(m_xScriptsListBox.get());
+    m_xScriptContainersListBox->Init(comphelper::getProcessComponentContext(), 
m_xDocumentFrame);
+
+    m_xScriptContainersListBox->connect_changed(LINK(this, MacroManagerDialog, 
SelectHdl));
+
+    m_xScriptsListBox->connect_changed(LINK(this, MacroManagerDialog, 
SelectHdl));
+    m_xScriptsListBox->connect_row_activated(
+        LINK(this, MacroManagerDialog, FunctionDoubleClickHdl));
+    m_xScriptsListBox->connect_popup_menu(LINK(this, MacroManagerDialog, 
ContextMenuHdl));
+
+    m_xAssignButton->connect_clicked(LINK(this, MacroManagerDialog, ClickHdl));
+    m_xRunButton->connect_clicked(LINK(this, MacroManagerDialog, ClickHdl));
+    m_xCloseButton->connect_clicked(LINK(this, MacroManagerDialog, ClickHdl));
+    m_xNewLibraryButton->connect_clicked(LINK(this, MacroManagerDialog, 
ClickHdl));
+    m_xNewModuleButton->connect_clicked(LINK(this, MacroManagerDialog, 
ClickHdl));
+    m_xNewDialogButton->connect_clicked(LINK(this, MacroManagerDialog, 
ClickHdl));
+    m_xLibraryModuleDialogEditButton->connect_clicked(LINK(this, 
MacroManagerDialog, ClickHdl));
+    m_xLibraryModuleDialogRenameButton->connect_clicked(LINK(this, 
MacroManagerDialog, ClickHdl));
+    m_xLibraryModuleDialogDeleteButton->connect_clicked(LINK(this, 
MacroManagerDialog, ClickHdl));
+    m_xLibraryPasswordButton->connect_clicked(LINK(this, MacroManagerDialog, 
ClickHdl));
+    m_xLibraryImportButton->connect_clicked(LINK(this, MacroManagerDialog, 
ClickHdl));
+    m_xLibraryExportButton->connect_clicked(LINK(this, MacroManagerDialog, 
ClickHdl));
+    m_xMacroCreateButton->connect_clicked(LINK(this, MacroManagerDialog, 
ClickHdl));
+    m_xMacroEditButton->connect_clicked(LINK(this, MacroManagerDialog, 
ClickHdl));
+    m_xMacroRenameButton->connect_clicked(LINK(this, MacroManagerDialog, 
ClickHdl));
+    m_xMacroDeleteButton->connect_clicked(LINK(this, MacroManagerDialog, 
ClickHdl));
+
+    StartListening(*SfxGetpApp());
+}
+
+MacroManagerDialog::~MacroManagerDialog() { EndListening(*SfxGetpApp()); }
+
+void MacroManagerDialog::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+    if (rHint.GetId() == SfxHintId::ScriptDocumentChanged)
+    {
+        weld::TreeView& rScriptContainersTreeView = 
m_xScriptContainersListBox->get_widget();
+
+        auto get_path = [&rScriptContainersTreeView](const weld::TreeIter* 
pIter) {
+            std::unique_ptr<weld::TreeIter> xIter = 
rScriptContainersTreeView.make_iterator(pIter);
+            OUString sPath = rScriptContainersTreeView.get_text(*xIter);
+            while (rScriptContainersTreeView.iter_parent(*xIter))
+                sPath = rScriptContainersTreeView.get_text(*xIter) + "|" + 
sPath;
+            return sPath;
+        };
+
+        std::unique_ptr<weld::TreeIter> xIter = 
rScriptContainersTreeView.make_iterator();
+
+        // for use to restore the script container tree scroll position
+        int nOldScrollPos = rScriptContainersTreeView.vadjustment_get_value();
+
+        // save the current path of the selection in the script containers 
list for reselection
+        // and the selected entry in the scripts list box
+        OUString sScriptContainersListBoxSelectedEntryPath;
+        OUString sScriptsListBoxSelectedEntry;
+        if (rScriptContainersTreeView.get_selected(xIter.get()))
+        {
+            sScriptContainersListBoxSelectedEntryPath = get_path(xIter.get());
+            sScriptsListBoxSelectedEntry = 
m_xScriptsListBox->GetSelectedScriptName();
+        }
+
+        // create a set containing paths for use to restore the script 
containers tree expand state
+        std::unordered_set<OUString> aExpandedSet;
+        if (!rScriptContainersTreeView.get_iter_first(*xIter)) // no entries?
+            return;
+        do
+        {
+            if (rScriptContainersTreeView.get_row_expanded(*xIter))
+                aExpandedSet.insert(get_path(xIter.get()));
+        } while (rScriptContainersTreeView.iter_next(*xIter));
+
+        // fill
+        rScriptContainersTreeView.freeze();
+        m_xScriptContainersListBox->Fill(nullptr);
+        rScriptContainersTreeView.thaw();
+
+        // restore script container tree expand state or at least try
+        if (!rScriptContainersTreeView.get_iter_first(*xIter))
+        {
+            UpdateUI();
+            return;
+        }
+        do
+        {
+            if (aExpandedSet.erase(get_path(xIter.get())))
+                rScriptContainersTreeView.expand_row(*xIter);
+        } while (aExpandedSet.size() && 
rScriptContainersTreeView.iter_next(*xIter));
+
+        // restore the script containers tree scroll position
+        rScriptContainersTreeView.vadjustment_set_value(nOldScrollPos);
+
+        // if possible select the saved scripts container list entry
+        if (sScriptContainersListBoxSelectedEntryPath.isEmpty())
+        {
+            UpdateUI();
+            return;
+        }
+        bool bFound = false;
+        while (true)
+        {
+            if (!rScriptContainersTreeView.get_iter_first(*xIter))
+            {
+                UpdateUI();
+                return;
+            }
+            do
+            {
+                if (get_path(xIter.get()) == 
sScriptContainersListBoxSelectedEntryPath)
+                {
+                    rScriptContainersTreeView.select(*xIter);
+                    bFound = true;
+                    break;
+                }
+            } while (rScriptContainersTreeView.iter_next(*xIter));
+            if (bFound)
+                break;
+            // when not found remove the last node from path and try again
+            auto i = 
sScriptContainersListBoxSelectedEntryPath.lastIndexOf('|');
+            if (i == -1)
+            {
+                // didn't find
+                UpdateUI();
+                return;
+            }
+            sScriptContainersListBoxSelectedEntryPath
+                = sScriptContainersListBoxSelectedEntryPath.copy(0, i);
+        }
+
+        // fill the scripts list box and set label
+        m_xScriptContainersListBox->ScriptContainerSelected();
+        m_xScriptsListBoxLabel->set_label(m_aScriptsListBoxLabelBaseStr + " "
+                                          + 
rScriptContainersTreeView.get_text(*xIter));
+
+        // reselect the macro in the scripts list box
+        if (!sScriptsListBoxSelectedEntry.isEmpty())
+        {
+            weld::TreeView& rScriptsTreeView = m_xScriptsListBox->get_widget();
+            xIter = rScriptsTreeView.make_iterator();
+            if (!rScriptsTreeView.get_iter_first(*xIter))
+            {
+                UpdateUI();
+                return;
+            }
+            bool bIsIterValid = true;
+            while (bIsIterValid
+                   && rScriptsTreeView.get_text(*xIter) != 
sScriptsListBoxSelectedEntry)
+                bIsIterValid = rScriptsTreeView.iter_next_sibling(*xIter);
+            if (bIsIterValid)
+            {
+                rScriptsTreeView.scroll_to_row(*xIter);
+                rScriptsTreeView.select(*xIter);
+            }
+        }
+
+        UpdateUI();
+    }
+}
+
+IMPL_LINK(MacroManagerDialog, SelectHdl, weld::TreeView&, rTreeView, void)
+{
+    if (&rTreeView == &m_xScriptContainersListBox->get_widget())
+    {
+        m_xScriptsListBoxLabel->set_label(m_aScriptsListBoxLabelBaseStr);
+        m_xScriptsListBox->ClearAll();
+
+        std::unique_ptr<weld::TreeIter> xSelectedEntryIter = 
rTreeView.make_iterator();
+        if (!rTreeView.get_selected(xSelectedEntryIter.get()))
+        {
+            UpdateUI();
+            return;
+        }
+
+        auto nSelectedEntryDepth = 
rTreeView.get_iter_depth(*xSelectedEntryIter);
+        bool bBasic = 
m_xScriptContainersListBox->GetContainerName(*xSelectedEntryIter,
+                                                                   
ScriptContainerType::LANGUAGE)
+                      == u"Basic"_ustr;
+
+        if (nSelectedEntryDepth > 1)
+        {
+            if (nSelectedEntryDepth > (!bBasic ? 1 : 2))
+            {
+                ScriptContainerInfo* pScriptContainerInfo
+                    = 
weld::fromId<ScriptContainerInfo*>(rTreeView.get_id(*xSelectedEntryIter));
+                // pBrowseNode is nullptr for Basic Dialog entries
+                if (pScriptContainerInfo->pBrowseNode)
+                {
+                    // fill the scripts list box and set the label
+                    m_xScriptContainersListBox->ScriptContainerSelected();
+                    
m_xScriptsListBoxLabel->set_label(m_aScriptsListBoxLabelBaseStr + " "
+                                                      + 
rTreeView.get_text(*xSelectedEntryIter));
+                }
+            }
+        }
+    }
+    UpdateUI();
+}
+
+// IMPL_LINK_NOARG(SvxScriptSelectorDialog, FunctionDoubleClickHdl, 
weld::TreeView&, bool)
+// cui/source/customize/cfgutil.cxx
+IMPL_LINK_NOARG(MacroManagerDialog, FunctionDoubleClickHdl, weld::TreeView&, 
bool)
+{
+    if (m_xRunButton->get_sensitive())
+        ClickHdl(*m_xRunButton);
+    return true;
+}
+
+// IMPL_LINK(SvxScriptSelectorDialog, ContextMenuHdl, const CommandEvent&, 
rCEvt, bool)
+// cui/source/customize/cfgutil.cxx
+// and
+// IMPL_LINK(MacroChooser, ContextMenuHdl, const CommandEvent&, rCEvt, bool)
+// basctl/source/basicide/macrodlg.cxx
+IMPL_LINK(MacroManagerDialog, ContextMenuHdl, const CommandEvent&, rCEvt, bool)
+{
+    weld::TreeView& xTreeView = m_xScriptsListBox->get_widget();
+    if (rCEvt.GetCommand() != CommandEventId::ContextMenu || 
!xTreeView.n_children())
+        return false;
+
+    std::unique_ptr<weld::Builder> xBuilder(
+        Application::CreateBuilder(&xTreeView, 
u"modules/BasicIDE/ui/sortmenu.ui"_ustr));
+    std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu(u"sortmenu"_ustr));
+    std::unique_ptr<weld::Menu> 
xDropMenu(xBuilder->weld_menu(u"sortsubmenu"_ustr));
+    xDropMenu->set_active(u"alphabetically"_ustr, xTreeView.get_sort_order());
+    xDropMenu->set_active(u"properorder"_ustr, !xTreeView.get_sort_order());
+
+    OUString sCommand(
+        xPopup->popup_at_rect(&xTreeView, 
tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1))));
+    if (sCommand == "alphabetically")
+    {
+        xTreeView.make_sorted();
+    }
+    else if (sCommand == "properorder")
+    {
+        xTreeView.make_unsorted();
+        m_xScriptContainersListBox->ScriptContainerSelected();
+    }
+    else if (!sCommand.isEmpty())
+    {
+        SAL_WARN("cui.dialogs", "Unknown context menu action: " << sCommand);
+    }
+
+    return true;
+}
+
+// same as OUString 
SvxScriptOrgDialog::getBoolProperty((Reference<beans::XPropertySet> const& 
xProps, OUString const& propName)
+// cui/source/dialogs/scriptdlg.cxx
+bool MacroManagerDialog::getBoolProperty(
+    css::uno::Reference<css::beans::XPropertySet> const& xProps, OUString 
const& propName)
+{
+    bool result = false;
+    try
+    {
+        xProps->getPropertyValue(propName) >>= result;
+    }
+    catch (css::uno::Exception&)
+    {
+        return result;
+    }
+    return result;
+}
+
+css::uno::Reference<css::script::browse::XBrowseNode>
+MacroManagerDialog::getBrowseNode(const weld::TreeView& rTreeView, const 
weld::TreeIter& rTreeIter)
+{
+    if (&rTreeView == m_xScriptContainersListBox->m_xTreeView.get())
+    {
+        ScriptContainerInfo* pScriptContainerInfo;
+        pScriptContainerInfo = 
weld::fromId<ScriptContainerInfo*>(rTreeView.get_id(rTreeIter));
+        if (pScriptContainerInfo)
+            return pScriptContainerInfo->pBrowseNode;
+    }
+    else
+    {
+        ScriptInfo* pScriptInfo = 
weld::fromId<ScriptInfo*>(rTreeView.get_id(rTreeIter));
+        if (pScriptInfo)
+            return pScriptInfo->pBrowseNode;
+    }
+    return nullptr;
+}
+
+void MacroManagerDialog::UpdateUI()
+{
+    OUString sDescriptionText
+        = 
ScriptsListBox::GetDescriptionText(m_xScriptsListBox->get_selected_id());
+
+    weld::TreeView& rTreeView = m_xScriptContainersListBox->get_widget();
+    std::unique_ptr<weld::TreeIter> xSelectedIter = rTreeView.make_iterator();
+    if (rTreeView.get_selected(xSelectedIter.get())
+        && rTreeView.get_iter_depth(*xSelectedIter) == 2) // library
+    {
+        if 
(m_xScriptContainersListBox->GetSelectedEntryContainerName(ScriptContainerType::LANGUAGE)
+            == "Basic")
+        {
+            basctl::ScriptDocument aDocument
+                = 
m_xScriptContainersListBox->GetScriptDocument(xSelectedIter.get());
+            if (aDocument.isAlive())
+            {
+                // if this is a Basic linked library use the link url name for 
the description string
+                css::uno::Reference<css::script::XLibraryContainer2> 
xModLibContainer(
+                    aDocument.getLibraryContainer(basctl::E_SCRIPTS), 
css::uno::UNO_QUERY);
+                OUString aLibName = rTreeView.get_text(*xSelectedIter);
+                if (xModLibContainer.is() && 
xModLibContainer->hasByName(aLibName)
+                    && xModLibContainer->isLibraryLink(aLibName))
+                {
+                    sDescriptionText = 
xModLibContainer->getLibraryLinkURL(aLibName);
+                }
+            }
+        }
+    }
+
+    m_xDescriptionText->set_text(sDescriptionText);
+    CheckButtons();
+}
+
+void MacroManagerDialog::CheckButtons()
+{
+    bool bSensitiveNewLibraryButton = false;
+    bool bSensitiveNewModuleButton = false;
+    bool bSensitiveNewDialogButton = false;
+    bool bSensitiveLibraryModuleDialogEditButton = false;
+    bool bSensitiveLibraryModuleDialogRenameButton = false;
+    bool bSensitiveLibraryModuleDialogDeleteButton = false;
+    bool bSensitiveLibraryPasswordButton = false;
+    bool bSensitiveLibraryImportButton = false;
+    bool bSensitiveLibraryExportButton = false;
+
+    bool bSensitiveMacroRunButton = false;
+    bool bSensitiveMacroCreateButton = false;
+    bool bSensitiveMacroEditButton = false;
+    bool bSensitiveMacroRenameButton = false;
+    bool bSensitiveMacroDeleteButton = false;
+
+    bool bSensitiveAssignButton = false;
+
+    weld::TreeView& rScriptContainersTreeView = 
m_xScriptContainersListBox->get_widget();
+    std::unique_ptr<weld::TreeIter> xScriptContainersSelectedIter
+        = rScriptContainersTreeView.make_iterator();
+    if 
(rScriptContainersTreeView.get_selected(xScriptContainersSelectedIter.get()))
+    {
+        if (auto nSelectedIterDepth
+            = 
rScriptContainersTreeView.get_iter_depth(*xScriptContainersSelectedIter))
+        {
+            std::unique_ptr<weld::TreeIter> xLocationContainerIter
+                = 
rScriptContainersTreeView.make_iterator(xScriptContainersSelectedIter.get());
+            while 
(rScriptContainersTreeView.get_iter_depth(*xLocationContainerIter))
+                rScriptContainersTreeView.iter_parent(*xLocationContainerIter);
+            bool bSharedLocationContainer
+                = getBrowseNode(rScriptContainersTreeView, 
*xLocationContainerIter)->getName()
+                  == u"share"_ustr;
+
+            bool bBasic = 
m_xScriptContainersListBox->GetSelectedEntryContainerName(
+                              ScriptContainerType::LANGUAGE)
+                          == u"Basic"_ustr;
+
+            if (nSelectedIterDepth == 1) // language node
+            {
+                if (!bSharedLocationContainer)
+                {
+                    if (bBasic)
+                    {
+                        bSensitiveNewLibraryButton = true;
+                        bSensitiveLibraryImportButton = true;
+                    }
+                    else
+                    {
+                        css::uno::Reference<css::script::browse::XBrowseNode> 
node = getBrowseNode(
+                            rScriptContainersTreeView, 
*xScriptContainersSelectedIter);
+                        if (node.is())
+                        {
+                            css::uno::Reference<css::beans::XPropertySet> 
xProps(
+                                node, css::uno::UNO_QUERY);
+                            if (xProps.is())
+                            {
+                                if (getBoolProperty(xProps, "Creatable"))
+                                {
+                                    bSensitiveNewLibraryButton = true;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            else if (bBasic && nSelectedIterDepth == 2) // library node
+            {
+                basctl::ScriptDocument aDocument = 
m_xScriptContainersListBox->GetScriptDocument();
+                if (!aDocument.isAlive())
+                    return;
+
+                OUString aLibName = 
m_xScriptContainersListBox->GetSelectedEntryContainerName(
+                    ScriptContainerType::LIBRARY);
+
+                css::uno::Reference<css::script::XLibraryContainerPassword> 
xPasswd(
+                    aDocument.getLibraryContainer(basctl::E_SCRIPTS), 
css::uno::UNO_QUERY);
+
+                if (xPasswd.is() && 
xPasswd->isLibraryPasswordProtected(aLibName)
+                    && !xPasswd->isLibraryPasswordVerified(aLibName))
+                {
+                    bSensitiveLibraryPasswordButton = true;
+                }
+                else if (bSharedLocationContainer)
+                {
+                    bSensitiveLibraryModuleDialogEditButton = true;
+                }
+                else
+                {
+                    // check, if library is readonly
+                    css::uno::Reference<css::script::XLibraryContainer2> 
xModLibContainer(
+                        aDocument.getLibraryContainer(basctl::E_SCRIPTS), 
css::uno::UNO_QUERY);
+
+                    bool bReadOnly = xModLibContainer.is() && 
xModLibContainer->hasByName(aLibName)
+                                     && 
xModLibContainer->isLibraryReadOnly(aLibName);
+
+                    bSensitiveNewModuleButton = !bReadOnly;
+                    bSensitiveNewDialogButton = !bReadOnly;
+                    bSensitiveLibraryModuleDialogEditButton = true;
+                    if (aLibName != u"Standard"_ustr) // need to use a ResId?
+                    {
+                        bSensitiveLibraryModuleDialogRenameButton = !bReadOnly;
+                        bSensitiveLibraryModuleDialogDeleteButton = true; 
//!bReadOnly;
+                        bSensitiveLibraryPasswordButton = !bReadOnly;
+                        // why not export for "Standard"?
+                        bSensitiveLibraryExportButton = true;
+                    }
+                }
+            }
+            else if (bBasic && nSelectedIterDepth == 3) // module/dialog node
+            {
+                if (bSharedLocationContainer)
+                {
+                    bSensitiveLibraryModuleDialogEditButton = true;
+                }
+                else
+                {
+                    basctl::ScriptDocument aDocument
+                        = m_xScriptContainersListBox->GetScriptDocument();
+                    assert(aDocument.isAlive());
+
+                    OUString aLibName = 
m_xScriptContainersListBox->GetSelectedEntryContainerName(
+                        ScriptContainerType::LIBRARY);
+
+                    css::uno::Reference<css::script::XLibraryContainer2> 
xModLibContainer(
+                        aDocument.getLibraryContainer(basctl::E_SCRIPTS), 
css::uno::UNO_QUERY);
+                    css::uno::Reference<css::script::XLibraryContainer2> 
xDlgLibContainer(
+                        aDocument.getLibraryContainer(basctl::E_DIALOGS), 
css::uno::UNO_QUERY);
+
+                    bool bReadOnly
+                        = (xModLibContainer.is() && 
xModLibContainer->hasByName(aLibName)
+                           && (xModLibContainer->isLibraryReadOnly(aLibName)
+                               || xModLibContainer->isLibraryLink(aLibName)))
+                          || (xDlgLibContainer.is() && 
xDlgLibContainer->hasByName(aLibName)
+                              && (xDlgLibContainer->isLibraryReadOnly(aLibName)
+                                  || 
xDlgLibContainer->isLibraryLink(aLibName)));
+
+                    bSensitiveLibraryModuleDialogEditButton = true;
+                    bSensitiveLibraryModuleDialogRenameButton = !bReadOnly;
+                    bSensitiveLibraryModuleDialogDeleteButton = !bReadOnly;
+                }
+            }
+
+            if (!bSharedLocationContainer && nSelectedIterDepth > 1)
+            {
+                css::uno::Reference<css::script::browse::XBrowseNode> node
+                    = getBrowseNode(rScriptContainersTreeView, 
*xScriptContainersSelectedIter);
+                if (node.is())
+                {
+                    css::uno::Reference<css::beans::XPropertySet> xProps(node, 
css::uno::UNO_QUERY);
+                    if (xProps.is())
+                    {
+                        if (getBoolProperty(xProps, "Creatable")
+                            && rScriptContainersTreeView.get_iter_depth(
+                                   *xScriptContainersSelectedIter)
+                                   == 2) // library entry
+                        {
+                            bSensitiveMacroCreateButton = true;
+                        }
+                        if (getBoolProperty(xProps, "Editable"))
+                        {
+                            bSensitiveLibraryModuleDialogEditButton = true;
+                        }
+                        if (getBoolProperty(xProps, "Deletable"))
+                        {
+                            bSensitiveLibraryModuleDialogDeleteButton = true;
+                        }
+                        if (getBoolProperty(xProps, "Renamable"))
+                        {
+                            bSensitiveLibraryModuleDialogRenameButton = true;
+                        }
+                    }
+                }
+            }
+
+            // scripts list box state dependant buttons
+            weld::TreeView& rScriptsTreeView = m_xScriptsListBox->get_widget();
+            std::unique_ptr<weld::TreeIter> xScriptsSelectedIter = 
rScriptsTreeView.make_iterator();
+            if (rScriptsTreeView.n_children()
+                && rScriptsTreeView.get_selected(xScriptsSelectedIter.get()))
+            {
+                bSensitiveAssignButton = true;
+
+                css::uno::Reference<css::script::browse::XBrowseNode> node;
+                node = getBrowseNode(rScriptsTreeView, *xScriptsSelectedIter);
+                if (node.is())
+                {
+                    bSensitiveMacroRunButton = true;
+
+                    css::uno::Reference<css::beans::XPropertySet> xProps(node, 
css::uno::UNO_QUERY);
+                    if (xProps.is())
+                    {
+                        if (getBoolProperty(xProps, "Editable"))
+                        {
+                            bSensitiveMacroEditButton = true;
+                        }
+                        if (!bSharedLocationContainer)
+                        {
+                            if (getBoolProperty(xProps, "Deletable"))
+                            {
+                                bSensitiveMacroDeleteButton = true;
+                            }
+                            if (getBoolProperty(xProps, "Renamable"))
+                            {
+                                bSensitiveMacroRenameButton = true;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    m_xNewLibraryButton->set_sensitive(bSensitiveNewLibraryButton);
+    m_xNewModuleButton->set_sensitive(bSensitiveNewModuleButton);
+    m_xNewDialogButton->set_sensitive(bSensitiveNewDialogButton);
+    
m_xLibraryModuleDialogEditButton->set_sensitive(bSensitiveLibraryModuleDialogEditButton);
+    
m_xLibraryModuleDialogRenameButton->set_sensitive(bSensitiveLibraryModuleDialogRenameButton);
+    
m_xLibraryModuleDialogDeleteButton->set_sensitive(bSensitiveLibraryModuleDialogDeleteButton);
+    m_xLibraryPasswordButton->set_sensitive(bSensitiveLibraryPasswordButton);
+    m_xLibraryImportButton->set_sensitive(bSensitiveLibraryImportButton);
+    m_xLibraryExportButton->set_sensitive(bSensitiveLibraryExportButton);
+    m_xRunButton->set_sensitive(bSensitiveMacroRunButton);
+    m_xMacroCreateButton->set_sensitive(bSensitiveMacroCreateButton);
+    m_xMacroEditButton->set_sensitive(bSensitiveMacroEditButton);
+    m_xMacroRenameButton->set_sensitive(bSensitiveMacroRenameButton);
+    m_xMacroDeleteButton->set_sensitive(bSensitiveMacroDeleteButton);
+    m_xAssignButton->set_sensitive(bSensitiveAssignButton);
+}
+
+// void createLibImpl(weld::Window* pWin, const ScriptDocument& rDocument,
+//                    weld::TreeView* pLibBox, SbTreeListBox* pBasicBox)
+// basctl/source/basicide/moduldl2.cxx
+void MacroManagerDialog::BasicScriptsCreateLibrary(const 
basctl::ScriptDocument& rDocument)
+{
+    // create a unique library name
+    OUString aLibName = CuiResId(STR_LIBRARY) + OUString::number(1);
+    for (sal_uInt32 i = 1; rDocument.hasLibrary(basctl::E_SCRIPTS, aLibName)
+                           || rDocument.hasLibrary(basctl::E_DIALOGS, 
aLibName);
+         aLibName = CuiResId(STR_LIBRARY) + OUString::number(++i))
+        ;
+
+    InputDialog aInputDlg(m_xDialog.get(), 
CuiResId(STR_INPUTDIALOG_NEWLIBRARYLABEL));
+    aInputDlg.set_title(CuiResId(STR_INPUTDIALOG_NEWLIBRARYTITLE));
+    aInputDlg.SetEntryText(aLibName);
+    aInputDlg.HideHelpBtn();
+    aInputDlg.setCheckEntry([&](OUString sNewName) {
+        if (sNewName.isEmpty() || rDocument.hasLibrary(basctl::E_SCRIPTS, 
sNewName)
+            || rDocument.hasLibrary(basctl::E_DIALOGS, sNewName) || 
sNewName.getLength() > 30
+            || !basctl::IsValidSbxName(sNewName))
+            return false;
+        return true;
+    });
+
+    if (!aInputDlg.run())
+        return;
+
+    aLibName = aInputDlg.GetEntryText();
+
+    try
+    {
+        // create library container for modules
+        rDocument.getOrCreateLibrary(basctl::E_SCRIPTS, aLibName);
+
+        // create a module
+        OUString aModName = rDocument.createObjectName(basctl::E_SCRIPTS, 
aLibName);
+        OUString sModuleCode;
+        if (!rDocument.createModule(aLibName, aModName, true, sModuleCode))
+            throw css::uno::Exception("could not create module " + aModName, 
nullptr);
+
+        // tdf#151741 - store all libraries to the file system, otherwise they
+        // cannot be renamed/moved since the SfxLibraryContainer::renameLibrary
+        // moves the folders/files on the file system
+        css::uno::Reference<css::script::XLibraryContainer2> xModLibContainer(
+            rDocument.getLibraryContainer(basctl::E_SCRIPTS), 
css::uno::UNO_QUERY);
+        css::uno::Reference<css::script::XPersistentLibraryContainer> 
xModPersLibContainer(
+            xModLibContainer, css::uno::UNO_QUERY);
+        if (xModPersLibContainer.is())
+            xModPersLibContainer->storeLibraries();
+
+        // update Basic IDE object catalog
+        SbxItem aModuleSbxItem(SID_BASICIDE_ARG_SBX, rDocument, aLibName, 
aModName,
+                               basctl::SBX_TYPE_MODULE);
+        if (SfxDispatcher* pDispatcher = basctl::GetDispatcher())
+            pDispatcher->ExecuteList(SID_BASICIDE_SBXINSERTED, 
SfxCallMode::SYNCHRON,
+                                     { &aModuleSbxItem });
+    }
+    catch (const css::uno::Exception&)
+    {
+        DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+    }
+}
+
+void MacroManagerDialog::BasicScriptsCreateModule(const 
basctl::ScriptDocument& rDocument)
+{
+    // library name is the selected tree entry
+    weld::TreeView& rTreeView = m_xScriptContainersListBox->get_widget();
+    std::unique_ptr<weld::TreeIter> xSelectedIter = rTreeView.make_iterator();
+    if (!rTreeView.get_selected(xSelectedIter.get()))
+        return; // should never happen
+
+    OUString aLibName = rTreeView.get_text(*xSelectedIter);
+
+    // create an unused module name
+    OUString aModName = CuiResId(STR_MODULE) + OUString::number(1);
+    for (sal_uInt32 i = 1; rDocument.hasModule(aLibName, aModName);
+         aModName = CuiResId(STR_MODULE) + OUString::number(++i))
+        ;
+
+    InputDialog aInputDlg(m_xDialog.get(), 
CuiResId(STR_INPUTDIALOG_NEWMODULELABEL));
+    aInputDlg.set_title(CuiResId(STR_INPUTDIALOG_NEWMODULETITLE));
+    aInputDlg.SetEntryText(aModName);
-e 
... etc. - the rest is truncated

Reply via email to