From 55e86edcb37a37123a69ce3e1eb9e20758415fb6 Mon Sep 17 00:00:00 2001 From: Jim Raykowski Date: Mon, 7 Oct 2024 10:56:34 -0800 Subject: [PATCH] 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 --- 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 | 145 +- 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 + .../uiconfig/dbrelation/menubar/menubar.xml | 2 + dbaccess/uiconfig/dbtable/menubar/menubar.xml | 2 + dbaccess/uiconfig/dbtdata/menubar/menubar.xml | 2 + .../sbibliography/menubar/menubar.xml | 2 + .../uiconfig/startmodule/menubar/menubar.xml | 2 + include/basctl/basctldllapi.h | 23 + include/basctl/basctldllpublic.hxx | 43 + .../source/inc => include/basctl}/sbxitem.hxx | 3 +- .../inc => 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 + .../openoffice/Office/UI/GenericCommands.xcu | 11 + .../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, 3834 insertions(+), 155 deletions(-) create mode 100644 cui/source/dialogs/MacroManagerDialog.cxx create mode 100644 cui/source/inc/MacroManagerDialog.hxx create mode 100644 cui/uiconfig/ui/macromanagerdialog.ui create mode 100644 include/basctl/basctldllapi.h create mode 100644 include/basctl/basctldllpublic.hxx rename {basctl/source/inc => include/basctl}/sbxitem.hxx (96%) rename {basctl/source/inc => include/basctl}/scriptdocument.hxx (99%) 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 #include #include -#include +#include #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 -#include +#include #include 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 -#include +#include #include #include 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 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& func_remove_entry, + const std::function& func_insert_entry, + const std::function& 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 & xFP = aDlg.GetFilePicker(); @@ -643,7 +672,7 @@ void LibPage::InsertLib() if (aLibNames.hasElements()) { // library import dialog - xLibDlg = std::make_shared(m_pDialog->getDialog()); + xLibDlg = std::make_shared(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 xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), + std::unique_ptr 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 xModLibContainer( + rDocument.getLibraryContainer(E_SCRIPTS), UNO_QUERY); + Reference 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 xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), - VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_REPLACESTDLIB))); + std::unique_ptr 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) + "\n" + IDEResId(RID_STR_LIBISREADONLY); - std::unique_ptr xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), - VclMessageType::Warning, VclButtonsType::Ok, aErrStr)); + std::unique_ptr 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) + "\n" +IDEResId(RID_STR_SBXNAMEALLREADYUSED); - std::unique_ptr xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), - VclMessageType::Warning, VclButtonsType::Ok, aErrStr)); + std::unique_ptr 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 xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), - VclMessageType::Warning, VclButtonsType::Ok, aErrStr)); + std::unique_ptr 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 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 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 xNewDlg(new ExportDialog(m_pDialog->getDialog())); + std::unique_ptr 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& Handler) { - Reference< script::XLibraryContainerExport > xModLibContainerExport - ( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); - Reference< script::XLibraryContainerExport > xDlgLibContainerExport - ( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + Reference xModLibContainerExport( + rScriptDocument.getLibraryContainer(E_SCRIPTS), UNO_QUERY); + Reference 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 & 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 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 #include +#include + 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& 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 +#include #include #include 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 -#include +#include #include #include #include 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 #include "doceventnotifier.hxx" -#include "scriptdocument.hxx" +#include 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 #include "ObjectCatalog.hxx" #include 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 +#include #include 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 -#include "sbxitem.hxx" +#include #include 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 +#include +#include #include #include #include @@ -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 -#include "scriptdocument.hxx" +#include #include 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 @@ + + 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() ) + try { + if ( rootNode->hasChildNodes() ) + { + const Sequence< Reference< browse::XBrowseNode > > children = + rootNode->getChildNodes(); + + 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; + + Reference < beans::XPropertySet >xPropSet( childNode, UNO_QUERY ); + if (!xPropSet.is()) { - OUString uri, description; - - Reference < beans::XPropertySet >xPropSet( childNode, UNO_QUERY ); - if (!xPropSet.is()) - { - continue; - } - - 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 - } - - OUString* pScriptURI = new OUString( uri ); - - OUString aImage = GetImage(childNode, Reference< XComponentContext >(), false); - m_pFunctionListBox->aArr.push_back( std::make_unique( 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); + continue; } + + 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 + } + + OUString* pScriptURI = new OUString( uri ); + + OUString aImage = GetImage(childNode, Reference< XComponentContext >(), false); + m_pFunctionListBox->aArr.push_back( std::make_unique( 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); } } } - 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 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 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 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 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ScriptsListBox::ScriptsListBox(std::unique_ptr 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(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(rId); + if (pScriptInfo) + { + return pScriptInfo->sDescription; + } + return OUString(); +} + +OUString ScriptsListBox::GetSelectedScriptName() +{ + std::unique_ptr 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 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(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& xContext, + const css::uno::Reference& 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 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 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 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(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(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 xNode; + if (pEntryIter == nullptr) + { + ClearAll(); + try + { + css::uno::Reference 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(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 xController = m_xFrame->getController(); + xController.is()) + { + css::uno::Reference xModel = xController->getModel(); + if (xModel.is()) + currentDocTitle = comphelper::DocumentInfo::getDocumentTitle(xModel); + } + + const css::uno::Sequence> children + = xNode->getChildNodes(); + for (css::uno::Reference 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> + 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 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 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& xInsertNode, + const weld::TreeIter* pIter, const OUString& rsUiName, const OUString& rsImage, + bool bChildOnDemand, int nPos, weld::TreeIter* pRet) +{ + std::unique_ptr 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 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 xModLibContainer( + aDocument.getLibraryContainer(basctl::E_SCRIPTS), css::uno::UNO_QUERY); + if (xModLibContainer.is() && xModLibContainer->hasByName(aLibName)) + { + css::uno::Reference 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 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(m_xTreeView->get_id(*xIter)); + css::uno::Reference xBrowseNode( + pScriptContainerInfo->pBrowseNode); + try + { + if (xBrowseNode->hasChildNodes()) + { + const css::uno::Sequence> + children = xBrowseNode->getChildNodes(); + + for (const css::uno::Reference& childNode : + children) + { + if (!childNode.is()) + continue; + + if (childNode->getType() == css::script::browse::BrowseNodeTypes::SCRIPT) + { + css::uno::Reference 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(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 xSelectedEntryIter + = rScriptContainersTreeView.make_iterator(&rIter); + + std::unique_ptr 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 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 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 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 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 xModLibContainer( + aDocument.getLibraryContainer(basctl::E_SCRIPTS), css::uno::UNO_QUERY); + if (xModLibContainer.is() && xModLibContainer->hasByName(aLibName)) + { + css::uno::Reference 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& 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 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 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 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 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(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 xBuilder( + Application::CreateBuilder(&xTreeView, u"modules/BasicIDE/ui/sortmenu.ui"_ustr)); + std::unique_ptr xPopup(xBuilder->weld_menu(u"sortmenu"_ustr)); + std::unique_ptr 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 const& xProps, OUString const& propName) +// cui/source/dialogs/scriptdlg.cxx +bool MacroManagerDialog::getBoolProperty( + css::uno::Reference const& xProps, OUString const& propName) +{ + bool result = false; + try + { + xProps->getPropertyValue(propName) >>= result; + } + catch (css::uno::Exception&) + { + return result; + } + return result; +} + +css::uno::Reference +MacroManagerDialog::getBrowseNode(const weld::TreeView& rTreeView, const weld::TreeIter& rTreeIter) +{ + if (&rTreeView == m_xScriptContainersListBox->m_xTreeView.get()) + { + ScriptContainerInfo* pScriptContainerInfo; + pScriptContainerInfo = weld::fromId(rTreeView.get_id(rTreeIter)); + if (pScriptContainerInfo) + return pScriptContainerInfo->pBrowseNode; + } + else + { + ScriptInfo* pScriptInfo = weld::fromId(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 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 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 xScriptContainersSelectedIter + = rScriptContainersTreeView.make_iterator(); + if (rScriptContainersTreeView.get_selected(xScriptContainersSelectedIter.get())) + { + if (auto nSelectedIterDepth + = rScriptContainersTreeView.get_iter_depth(*xScriptContainersSelectedIter)) + { + std::unique_ptr 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 node = getBrowseNode( + rScriptContainersTreeView, *xScriptContainersSelectedIter); + if (node.is()) + { + css::uno::Reference 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 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 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 xModLibContainer( + aDocument.getLibraryContainer(basctl::E_SCRIPTS), css::uno::UNO_QUERY); + css::uno::Reference 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 node + = getBrowseNode(rScriptContainersTreeView, *xScriptContainersSelectedIter); + if (node.is()) + { + css::uno::Reference 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 xScriptsSelectedIter = rScriptsTreeView.make_iterator(); + if (rScriptsTreeView.n_children() + && rScriptsTreeView.get_selected(xScriptsSelectedIter.get())) + { + bSensitiveAssignButton = true; + + css::uno::Reference node; + node = getBrowseNode(rScriptsTreeView, *xScriptsSelectedIter); + if (node.is()) + { + bSensitiveMacroRunButton = true; + + css::uno::Reference 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 xModLibContainer( + rDocument.getLibraryContainer(basctl::E_SCRIPTS), css::uno::UNO_QUERY); + css::uno::Reference 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 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); + aInputDlg.HideHelpBtn(); + aInputDlg.setCheckEntry([&](OUString sNewName) { + if (sNewName.isEmpty() || rDocument.hasModule(aLibName, sNewName) + || sNewName.getLength() > 30 || !basctl::IsValidSbxName(sNewName)) + return false; + return true; + }); + + if (!aInputDlg.run()) + return; + + aModName = aInputDlg.GetEntryText(); + + OUString sModuleCode; + if (!rDocument.createModule(aLibName, aModName, true /*create main sub*/, sModuleCode)) + return; + + // update Basic IDE object catalog + SbxItem aSbxItem(SID_BASICIDE_ARG_SBX, rDocument, aLibName, aModName, basctl::SBX_TYPE_MODULE); + if (SfxDispatcher* pDispatcher = basctl::GetDispatcher()) + { + pDispatcher->ExecuteList(SID_BASICIDE_SBXINSERTED, SfxCallMode::SYNCHRON, { &aSbxItem }); + } +} + +void MacroManagerDialog::BasicScriptsCreateDialog(const basctl::ScriptDocument& rDocument) +{ + // library name is the selected tree entry + weld::TreeView& rTreeView = m_xScriptContainersListBox->get_widget(); + std::unique_ptr xSelectedIter = rTreeView.make_iterator(); + if (!rTreeView.get_selected(xSelectedIter.get())) + return; // should never happen + + OUString aLibName = rTreeView.get_text(*xSelectedIter); + + // create an unused dialog name + OUString sDialogName = CuiResId(STR_DIALOG) + OUString::number(1); + for (sal_uInt32 i = 1; rDocument.hasDialog(aLibName, sDialogName); + sDialogName = CuiResId(STR_DIALOG) + OUString::number(++i)) + ; + + InputDialog aInputDlg(m_xDialog.get(), CuiResId(STR_INPUTDIALOG_NEWDIALOGLABEL)); + aInputDlg.set_title(CuiResId(STR_INPUTDIALOG_NEWDIALOGTITLE)); + aInputDlg.SetEntryText(sDialogName); + aInputDlg.HideHelpBtn(); + aInputDlg.setCheckEntry([&](OUString sNewName) { + if (sNewName.isEmpty() || rDocument.hasDialog(aLibName, sNewName) + || sNewName.getLength() > 30 || !basctl::IsValidSbxName(sNewName)) + return false; + return true; + }); + + if (!aInputDlg.run()) + return; + + sDialogName = aInputDlg.GetEntryText(); + + try + { + rDocument.getOrCreateLibrary(basctl::E_DIALOGS, aLibName); + + css::uno::Reference xISP; + if (!rDocument.createDialog(aLibName, sDialogName, xISP)) + return; + + // update Basic IDE object catalog + SbxItem aSbxItem(SID_BASICIDE_ARG_SBX, rDocument, aLibName, sDialogName, + basctl::SBX_TYPE_DIALOG); + if (SfxDispatcher* pDispatcher = basctl::GetDispatcher()) + { + pDispatcher->ExecuteList(SID_BASICIDE_SBXINSERTED, SfxCallMode::SYNCHRON, + { &aSbxItem }); + } + } + catch (const css::container::ElementExistException&) + { + std::unique_ptr xError(Application::CreateMessageDialog( + m_xDialog.get(), VclMessageType::Warning, VclButtonsType::Ok, + CuiResId(STR_SBXNAMEALLREADYUSED))); + xError->run(); + } + catch (const css::container::NoSuchElementException&) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } +} + +void MacroManagerDialog::BasicScriptsLibraryModuleDialogEdit( + const basctl::ScriptDocument& rDocument) +{ + weld::TreeView& rTreeView = m_xScriptContainersListBox->get_widget(); + std::unique_ptr xSelectedIter = rTreeView.make_iterator(); + if (!rTreeView.get_selected(xSelectedIter.get())) + return; // should never happen + + m_xDialog->hide(); + + // show the Basic IDE + SfxAllItemSet aArgs(SfxGetpApp()->GetPool()); + SfxRequest aRequest(SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs); + SfxGetpApp()->ExecuteSlot(aRequest); + + if (rTreeView.get_iter_depth(*xSelectedIter) == 2) // library + { + SfxUnoAnyItem aDocItem(SID_BASICIDE_ARG_DOCUMENT_MODEL, + css::uno::Any(rDocument.getDocumentOrNull())); + SfxStringItem aLibNameItem(SID_BASICIDE_ARG_LIBNAME, + m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::LIBRARY)); + if (SfxDispatcher* pDispatcher = basctl::GetDispatcher()) + pDispatcher->ExecuteList(SID_BASICIDE_LIBSELECTED, SfxCallMode::ASYNCHRON, + { &aDocItem, &aLibNameItem }); + } + else // module/dialog + { + ScriptContainerInfo* pScriptContainerInfo + = weld::fromId(rTreeView.get_id(*xSelectedIter)); + // pScriptContainerInfo->pBrowseNode is nullptr for Dialog entries + SbxItem aSbxItem( + SID_BASICIDE_ARG_SBX, rDocument, + m_xScriptContainersListBox->GetSelectedEntryContainerName(ScriptContainerType::LIBRARY), + m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::MODULEORDIALOG), + pScriptContainerInfo->pBrowseNode ? basctl::SBX_TYPE_MODULE : basctl::SBX_TYPE_DIALOG); + if (SfxDispatcher* pDispatcher = basctl::GetDispatcher()) + pDispatcher->ExecuteList(SID_BASICIDE_SHOWSBX, SfxCallMode::ASYNCHRON, { &aSbxItem }); + } + + // close the MacroManagerDialog + m_xDialog->response(0); +} + +IMPL_LINK(MacroManagerDialog, CheckPasswordHdl, SvxPasswordDialog*, pDlg, bool) +{ + basctl::ScriptDocument aDocument = m_xScriptContainersListBox->GetScriptDocument(); + if (!aDocument.isAlive()) + return false; + + bool bRet = false; + + css::uno::Reference xPasswd( + aDocument.getLibraryContainer(basctl::E_SCRIPTS), css::uno::UNO_QUERY); + + if (xPasswd.is()) + { + try + { + OUString aOldPassword(pDlg->GetOldPassword()); + OUString aNewPassword(pDlg->GetNewPassword()); + OUString aLibName = m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::LIBRARY); + xPasswd->changeLibraryPassword(aLibName, aOldPassword, aNewPassword); + bRet = true; + } + catch (...) + { + } + } + + return bRet; +} + +basctl::ScriptDocument ScriptContainersListBox::GetScriptDocument(const weld::TreeIter* pIter) +{ + std::unique_ptr xIter = m_xTreeView->make_iterator(pIter); + if (pIter == nullptr) + { + if (!m_xTreeView->get_selected(xIter.get())) + return basctl::ScriptDocument::getApplicationScriptDocument(); + } + + while (m_xTreeView->get_iter_depth(*xIter)) + m_xTreeView->iter_parent(*xIter); + + ScriptContainerInfo* pScriptContainerInfo + = weld::fromId(m_xTreeView->get_id(*xIter)); + if (pScriptContainerInfo && pScriptContainerInfo->pBrowseNode) + { + css::uno::Reference aRootNode; + aRootNode = pScriptContainerInfo->pBrowseNode; + if (aRootNode->getName() == u"user"_ustr || aRootNode->getName() == u"share"_ustr) + return basctl::ScriptDocument::getApplicationScriptDocument(); + return basctl::ScriptDocument::getDocumentWithURLOrCaption(aRootNode->getName()); + } + + return basctl::ScriptDocument::getApplicationScriptDocument(); +} + +IMPL_LINK(MacroManagerDialog, ClickHdl, weld::Button&, rButton, void) +{ + if (&rButton == m_xCloseButton.get()) + { + m_xDialog->response(RET_CANCEL); + return; + } + if (&rButton == m_xRunButton.get()) + { + SaveLastUsedMacro(); + m_xDialog->response(RET_OK); + return; + } + + if (m_xScriptContainersListBox->GetSelectedEntryContainerName(ScriptContainerType::LANGUAGE) + == "Basic") + { + basctl::ScriptDocument aDocument = m_xScriptContainersListBox->GetScriptDocument(); + if (!aDocument.isAlive()) + return; + + if (&rButton == m_xNewLibraryButton.get()) + { + BasicScriptsCreateLibrary(aDocument); + } + else if (&rButton == m_xNewModuleButton.get()) + { + BasicScriptsCreateModule(aDocument); + } + else if (&rButton == m_xNewDialogButton.get()) + { + BasicScriptsCreateDialog(aDocument); + } + else if (&rButton == m_xLibraryModuleDialogEditButton.get()) + { + BasicScriptsLibraryModuleDialogEdit(aDocument); + } + else if (&rButton == m_xLibraryModuleDialogRenameButton.get()) + { + BasicScriptsLibraryModuleDialogRename(aDocument); + } + else if (&rButton == m_xLibraryModuleDialogDeleteButton.get()) + { + BasicScriptsLibraryModuleDialogDelete(aDocument); + } + else if (&rButton == m_xLibraryPasswordButton.get()) + { + BasicScriptsLibraryPassword(aDocument); + } + else if (&rButton == m_xLibraryImportButton.get()) + { + auto insert_entries = [this]() { + weld::TreeView& rTreeView = m_xScriptContainersListBox->get_widget(); + std::unique_ptr xSelectedIter = rTreeView.make_iterator(); + if (!rTreeView.get_selected(xSelectedIter.get())) + return; // should never happen + m_xScriptContainersListBox->Fill(xSelectedIter.get()); + rTreeView.expand_row(*xSelectedIter); + rTreeView.select(*xSelectedIter); + }; + basctl::ImportLib(aDocument, m_xDialog.get(), {}, {}, insert_entries); + } + else if (&rButton == m_xLibraryExportButton.get()) + { + basctl::Export(aDocument, + m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::LIBRARY), + m_xDialog.get()); + } + else if (&rButton == m_xMacroEditButton.get()) + { + BasicScriptsMacroEdit(aDocument); + } + else if (&rButton == m_xMacroDeleteButton.get()) + { + // todo + // see: void MacroChooser::DeleteMacro() + return; + } + else if (&rButton == m_xAssignButton.get()) + { + SfxAllItemSet Args(SfxGetpApp()->GetPool()); + SfxAllItemSet aInternalSet(SfxGetpApp()->GetPool()); + if (m_xDocumentFrame.is()) + aInternalSet.Put(SfxUnoFrameItem(SID_FILLFRAME, m_xDocumentFrame)); + SfxRequest aRequest(SID_CONFIGACCEL, SfxCallMode::SYNCHRON, Args, aInternalSet); + + SfxMacroInfoItem aMacroInfoItem( + SID_MACROINFO, aDocument.getBasicManager(), + m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::LIBRARY), + m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::MODULEORDIALOG), + m_xScriptsListBox->GetSelectedScriptName(), OUString(), + m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::LOCATION)); + aRequest.AppendItem(aMacroInfoItem); + + SfxGetpApp()->ExecuteSlot(aRequest); + } + return; + } + + // + // button operations on Scripting Framework languages + // + if (&rButton == m_xNewLibraryButton.get()) + { + ScriptingFrameworkScriptsCreateEntry(InputDialogMode::NEWLIB); + } + else if (&rButton == m_xMacroCreateButton.get()) + { + ScriptingFrameworkScriptsCreateEntry(InputDialogMode::NEWMACRO); + } + else if (&rButton == m_xMacroEditButton.get()) + { + weld::TreeView& rTreeView = m_xScriptsListBox->get_widget(); + std::unique_ptr xSelectedIter = rTreeView.make_iterator(); + if (!rTreeView.get_selected(xSelectedIter.get())) + return; // should never happen + css::uno::Reference node + = getBrowseNode(rTreeView, *xSelectedIter); + css::uno::Reference xInv(node, css::uno::UNO_QUERY); + if (xInv.is()) + { + m_xDialog->response(RET_CANCEL); + css::uno::Sequence args(0); + css::uno::Sequence outArgs(0); + css::uno::Sequence outIndex; + try + { + // ISSUE need code to run script here + xInv->invoke(u"Editable"_ustr, args, outIndex, outArgs); + } + catch (css::uno::Exception const&) + { + TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to invoke"); + } + } + } + else if (&rButton == m_xLibraryModuleDialogDeleteButton.get()) + { + weld::TreeView& rTreeView = m_xScriptContainersListBox->get_widget(); + std::unique_ptr xSelectedIter = rTreeView.make_iterator(); + if (!rTreeView.get_selected(xSelectedIter.get())) + return; // should never happen + ScriptingFrameworkScriptsDeleteEntry(rTreeView, *xSelectedIter); + } + else if (&rButton == m_xMacroDeleteButton.get()) + { + weld::TreeView& rTreeView = m_xScriptsListBox->get_widget(); + std::unique_ptr xSelectedIter = rTreeView.make_iterator(); + if (!rTreeView.get_selected(xSelectedIter.get())) + return; // should never happen + ScriptingFrameworkScriptsDeleteEntry(rTreeView, *xSelectedIter); + } + else if (&rButton == m_xLibraryModuleDialogRenameButton.get()) + { + weld::TreeView& rTreeView = m_xScriptContainersListBox->get_widget(); + std::unique_ptr xSelectedIter = rTreeView.make_iterator(); + if (!rTreeView.get_selected(xSelectedIter.get())) + return; // should never happen + ScriptingFrameworkScriptsRenameEntry(rTreeView, *xSelectedIter); + } + else if (&rButton == m_xMacroRenameButton.get()) + { + weld::TreeView& rTreeView = m_xScriptsListBox->get_widget(); + std::unique_ptr xSelectedIter = rTreeView.make_iterator(); + if (!rTreeView.get_selected(xSelectedIter.get())) + return; // should never happen + ScriptingFrameworkScriptsRenameEntry(rTreeView, *xSelectedIter); + } + else if (&rButton == m_xAssignButton.get()) + { + SfxAllItemSet Args(SfxGetpApp()->GetPool()); + SfxAllItemSet aInternalSet(SfxGetpApp()->GetPool()); + if (m_xDocumentFrame.is()) + aInternalSet.Put(SfxUnoFrameItem(SID_FILLFRAME, m_xDocumentFrame)); + SfxRequest aRequest(SID_CONFIGACCEL, SfxCallMode::SYNCHRON, Args, aInternalSet); + + SfxMacroInfoItem aMacroInfoItem( + SID_MACROINFO, nullptr, + m_xScriptContainersListBox->GetSelectedEntryContainerName(ScriptContainerType::LIBRARY), + OUString(), m_xScriptsListBox->GetSelectedScriptName(), OUString(), + m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::LOCATION)); + aRequest.AppendItem(aMacroInfoItem); + SfxGetpApp()->ExecuteSlot(aRequest); + } +} + +bool MacroManagerDialog::IsLibraryReadOnlyOrFailedPasswordQuery( + const basctl::ScriptDocument& rDocument, weld::TreeIter* pIter) +{ + css::uno::Reference xModLibContainer( + rDocument.getLibraryContainer(basctl::E_SCRIPTS), css::uno::UNO_QUERY); + css::uno::Reference xDlgLibContainer( + rDocument.getLibraryContainer(basctl::E_DIALOGS), css::uno::UNO_QUERY); + + OUString aLibName + = m_xScriptContainersListBox->GetContainerName(*pIter, ScriptContainerType::LIBRARY); + + // check if library is readonly + if ((xModLibContainer.is() && xModLibContainer->hasByName(aLibName) + && xModLibContainer->isLibraryReadOnly(aLibName) + && !xModLibContainer->isLibraryLink(aLibName)) + || (xDlgLibContainer.is() && xDlgLibContainer->hasByName(aLibName) + && xDlgLibContainer->isLibraryReadOnly(aLibName) + && !xDlgLibContainer->isLibraryLink(aLibName))) + { + std::unique_ptr xErrorBox( + Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Warning, + VclButtonsType::Ok, CuiResId(STR_LIBISREADONLY))); + xErrorBox->run(); + return true; + } + + // password + if (xModLibContainer.is() && xModLibContainer->hasByName(aLibName) + /*&& !xModLibContainer->isLibraryLoaded(aLibName)*/) + { + bool bOK = true; + // check password + css::uno::Reference xPasswd(xModLibContainer, + css::uno::UNO_QUERY); + if (xPasswd.is() && xPasswd->isLibraryPasswordProtected(aLibName) + && !xPasswd->isLibraryPasswordVerified(aLibName)) + { + OUString sPassword; + bOK = basctl::QueryPassword(m_xDialog.get(), xModLibContainer, aLibName, sPassword, + true, true); + } + if (!bOK) + return true; + } + + return false; +} + +// adapted from LibPage inline renaming +// IMPL_LINK(LibPage, EditingEntryHdl, const weld::TreeIter&, rIter, bool) +// IMPL_LINK(LibPage, EditedEntryHdl, const IterString&, rIterString, bool) +// basctl/source/basicide/moduldl2.cxx +void MacroManagerDialog::BasicScriptsLibraryModuleDialogRename( + const basctl::ScriptDocument& rDocument) +{ + weld::TreeView& rTreeView = m_xScriptContainersListBox->get_widget(); + std::unique_ptr xSelectedIter = rTreeView.make_iterator(); + if (!rTreeView.get_selected(xSelectedIter.get())) + return; // should never happen + + if (IsLibraryReadOnlyOrFailedPasswordQuery(rDocument, xSelectedIter.get())) + return; + + OUString sOldName = rTreeView.get_text(*xSelectedIter); + + if (rTreeView.get_iter_depth(*xSelectedIter) == 2) // library + { + InputDialog aInputDlg(m_xDialog.get(), CuiResId(STR_INPUTDIALOG_RENAMELIBRARYLABEL)); + aInputDlg.HideHelpBtn(); + aInputDlg.set_title(CuiResId(STR_INPUTDIALOG_RENAMELIBRARYTITLE)); + aInputDlg.SetEntryText(sOldName); + aInputDlg.setCheckEntry([&](OUString sNewName) { + if (sNewName != sOldName + && (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; + + OUString sNewName = aInputDlg.GetEntryText(); + if (sNewName == sOldName) + return; + + bool bSuccess = true; + try + { + css::uno::Reference xModLibContainer( + rDocument.getLibraryContainer(basctl::E_SCRIPTS), css::uno::UNO_QUERY); + if (xModLibContainer.is() && xModLibContainer->hasByName(sOldName)) + xModLibContainer->renameLibrary(sOldName, sNewName); + css::uno::Reference xDlgLibContainer( + rDocument.getLibraryContainer(basctl::E_DIALOGS), css::uno::UNO_QUERY); + if (xDlgLibContainer.is() && xDlgLibContainer->hasByName(sOldName)) + xDlgLibContainer->renameLibrary(sOldName, sNewName); + } + catch (css::uno::Exception const&) + { + bSuccess = false; + TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to Rename"); + } + + if (bSuccess) + { + basctl::MarkDocumentModified(rDocument); + // rTreeView.set_text(*xSelectedIter, sNewName); + } + } + else + { + // module/dialog + ScriptContainerInfo* pScriptContainerInfo + = weld::fromId(rTreeView.get_id(*xSelectedIter)); + if (!pScriptContainerInfo) + return; // should never happen + + OUString aLibName = m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::LIBRARY); + + InputDialog aInputDlg(m_xDialog.get(), CuiResId(pScriptContainerInfo->pBrowseNode + ? STR_INPUTDIALOG_RENAMEMODULELABEL + : STR_INPUTDIALOG_RENAMEDIALOGLABEL)); + aInputDlg.HideHelpBtn(); + aInputDlg.set_title(CuiResId(pScriptContainerInfo->pBrowseNode + ? STR_INPUTDIALOG_RENAMEMODULETITLE + : STR_INPUTDIALOG_RENAMEMODULETITLE)); + aInputDlg.SetEntryText(sOldName); + aInputDlg.setCheckEntry([&](OUString sNewName) { + if (sNewName != sOldName + && (sNewName.isEmpty() || sNewName.getLength() > 30 + || !basctl::IsValidSbxName(sNewName) + || pScriptContainerInfo->pBrowseNode + ? rDocument.hasModule(aLibName, sNewName) + : rDocument.hasDialog(aLibName, sNewName))) + return false; + return true; + }); + + if (!aInputDlg.run()) + return; + + OUString sNewName = aInputDlg.GetEntryText(); + if (sNewName == sOldName) + return; + + if (pScriptContainerInfo->pBrowseNode + ? rDocument.renameModule(aLibName, sOldName, sNewName) + : rDocument.renameDialog(aLibName, sOldName, sNewName, nullptr)) + { + basctl::MarkDocumentModified(rDocument); + // rTreeView.set_text(*xSelectedIter, sNewName); + } + } +} + +void MacroManagerDialog::BasicScriptsLibraryModuleDialogDelete( + const basctl::ScriptDocument& rDocument) +{ + weld::TreeView& rTreeView = m_xScriptContainersListBox->get_widget(); + std::unique_ptr xSelectedIter = rTreeView.make_iterator(); + if (!rTreeView.get_selected(xSelectedIter.get())) + return; // should never happen + + if (IsLibraryReadOnlyOrFailedPasswordQuery(rDocument, xSelectedIter.get())) + return; + + if (rTreeView.get_iter_depth(*xSelectedIter) == 2) // library + { + // see: void LibPage::DeleteCurrent() + // basctl/source/basicide/moduldl2.cxx + OUString aLibName = rTreeView.get_text(*xSelectedIter); + + // check, if library is link + bool bIsLibraryLink = false; + css::uno::Reference xModLibContainer( + rDocument.getLibraryContainer(basctl::E_SCRIPTS), css::uno::UNO_QUERY); + css::uno::Reference xDlgLibContainer( + rDocument.getLibraryContainer(basctl::E_DIALOGS), css::uno::UNO_QUERY); + if ((xModLibContainer.is() && xModLibContainer->hasByName(aLibName) + && xModLibContainer->isLibraryLink(aLibName)) + || (xDlgLibContainer.is() && xDlgLibContainer->hasByName(aLibName) + && xDlgLibContainer->isLibraryLink(aLibName))) + { + bIsLibraryLink = true; + } + + if (!basctl::QueryDelLib(aLibName, bIsLibraryLink, m_xDialog.get())) + return; + + // inform BasicIDE + SfxUnoAnyItem aDocItem(SID_BASICIDE_ARG_DOCUMENT_MODEL, + css::uno::Any(rDocument.getDocumentOrNull())); + SfxStringItem aLibNameItem(SID_BASICIDE_ARG_LIBNAME, aLibName); + if (SfxDispatcher* pDispatcher = basctl::GetDispatcher()) + pDispatcher->ExecuteList(SID_BASICIDE_LIBREMOVED, SfxCallMode::SYNCHRON, + { &aDocItem, &aLibNameItem }); + + // remove library from module and dialog library containers + if (xModLibContainer.is() && xModLibContainer->hasByName(aLibName)) + xModLibContainer->removeLibrary(aLibName); + if (xDlgLibContainer.is() && xDlgLibContainer->hasByName(aLibName)) + xDlgLibContainer->removeLibrary(aLibName); + + basctl::MarkDocumentModified(rDocument); + } + else + { + // delete Basic module or dialog + // adapted from void ObjectPage::DeleteCurrent() basctl/source/basicide/moduldlg.cxx + ScriptContainerInfo* pScriptContainerInfo + = weld::fromId(rTreeView.get_id(*xSelectedIter)); + if (!pScriptContainerInfo) + return; // shouldn't happen + + // pBrowseNode points to nullptr for dialog entries + if (pScriptContainerInfo->pBrowseNode) + { + if (!basctl::QueryDelModule(m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::MODULEORDIALOG), + m_xDialog.get())) + return; + } + else + { + if (!basctl::QueryDelDialog(m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::MODULEORDIALOG), + m_xDialog.get())) + return; + } + + bool bSuccess = false; + if (pScriptContainerInfo->pBrowseNode) + bSuccess + = rDocument.removeModule(m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::LIBRARY), + m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::MODULEORDIALOG)); + else + bSuccess + = rDocument.removeDialog(m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::LIBRARY), + m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::MODULEORDIALOG)); + + if (bSuccess) + { + if (SfxDispatcher* pDispatcher = basctl::GetDispatcher()) + { + SbxItem aSbxItem(SID_BASICIDE_ARG_SBX, rDocument, + m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::LIBRARY), + m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::MODULEORDIALOG), + pScriptContainerInfo->pBrowseNode ? basctl::SBX_TYPE_MODULE + : basctl::SBX_TYPE_DIALOG); + pDispatcher->ExecuteList(SID_BASICIDE_SBXDELETED, SfxCallMode::SYNCHRON, + { &aSbxItem }); + } + basctl::MarkDocumentModified(rDocument); + } + } +} + +// inspired by IMPL_LINK( LibPage, ButtonHdl, weld::Button&, rButton, void ) +// else if (&rButton == m_xPasswordButton.get()) +// basctl/source/basicide/moduldl2.cxx +void MacroManagerDialog::BasicScriptsLibraryPassword(const basctl::ScriptDocument& rDocument) +{ + weld::TreeView& rTreeView = m_xScriptContainersListBox->get_widget(); + std::unique_ptr xSelectedIter = rTreeView.make_iterator(); + if (!rTreeView.get_selected(xSelectedIter.get())) + return; // should never happen + + OUString aLibName = rTreeView.get_text(*xSelectedIter); + + // load module library (if not loaded) + css::uno::Reference xModLibContainer + = rDocument.getLibraryContainer(basctl::E_SCRIPTS); + if (xModLibContainer.is() && xModLibContainer->hasByName(aLibName) + && !xModLibContainer->isLibraryLoaded(aLibName)) + { + xModLibContainer->loadLibrary(aLibName); + } + + // check if library is password protected --> this is for setting and removing password + if (xModLibContainer.is() && xModLibContainer->hasByName(aLibName)) + { + css::uno::Reference xPasswd(xModLibContainer, + css::uno::UNO_QUERY); + if (xPasswd.is()) + { + if (xPasswd->isLibraryPasswordProtected(aLibName) + && !xPasswd->isLibraryPasswordVerified(aLibName)) + { + // password not verified + OUString sPassword; + if (basctl::QueryPassword(m_xDialog.get(), xModLibContainer, aLibName, sPassword, + true, true)) + { + CheckButtons(); + } + return; + } + + // set/change password dialog + SvxPasswordDialog aDlg(m_xDialog.get(), !xPasswd->isLibraryPasswordProtected(aLibName)); + aDlg.SetCheckPasswordHdl(LINK(this, MacroManagerDialog, CheckPasswordHdl)); + + if (aDlg.run() == RET_OK) + { + if (xPasswd->isLibraryPasswordProtected(aLibName)) + rTreeView.set_image(*xSelectedIter, RID_CUIBMP_LOCKED); + else + rTreeView.set_image(*xSelectedIter, RID_CUIBMP_LIB); + basctl::MarkDocumentModified(rDocument); + } + + rTreeView.grab_focus(); + } + } +} + +void MacroManagerDialog::BasicScriptsMacroEdit(const basctl::ScriptDocument& rDocument) +{ + // hide the scripts organizer selector dialog before opening the basic ide + m_xDialog->hide(); + + // open the basic ide + SfxAllItemSet aArgs(SfxGetpApp()->GetPool()); + SfxRequest aRequest(SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs); + SfxGetpApp()->ExecuteSlot(aRequest); + + // navigate to the method + SbxItem aSbxItem( + SID_BASICIDE_ARG_SBX, rDocument, + m_xScriptContainersListBox->GetSelectedEntryContainerName(ScriptContainerType::LIBRARY), + m_xScriptContainersListBox->GetSelectedEntryContainerName( + ScriptContainerType::MODULEORDIALOG), + m_xScriptsListBox->GetSelectedScriptName(), basctl::SBX_TYPE_METHOD); + // need to use basctl::GetDispatcher() to have expected results with qt5 and x11, + // gtk3 works with SfxGetpApp()->GetDispatcher() + if (SfxDispatcher* pDispatcher = basctl::GetDispatcher()) + pDispatcher->ExecuteList(SID_BASICIDE_SHOWSBX, SfxCallMode::ASYNCHRON, { &aSbxItem }); + // alternate way to do this + // BasicManager* pBasMgr = rDocument.getBasicManager(); + // SfxMacroInfoItem aInfoItem( SID_BASICIDE_ARG_MACROINFO, pBasMgr, aLibName, aModName, aMethodName, OUString() ); + // if (SfxDispatcher* pDispatcher = basctl::GetDispatcher()) + // pDispatcher->ExecuteList(SID_BASICIDE_EDITMACRO, SfxCallMode::ASYNCHRON, { &aInfoItem }); + + // now it is safe to close the scripts organizer selector dialog + m_xDialog->response(0); +} + +// modified version of void SvxScriptOrgDialog::renameEntry(const weld::TreeIter& rEntry) +// cui/source/dialogs/scriptdlg.cxx +void MacroManagerDialog::ScriptingFrameworkScriptsRenameEntry(weld::TreeView& rTreeView, + const weld::TreeIter& rEntry) +{ + css::uno::Reference xBrowseNode + = getBrowseNode(rTreeView, rEntry); + css::uno::Reference xInv(xBrowseNode, css::uno::UNO_QUERY); + + if (xInv.is()) + { + OUString aNewName = xBrowseNode->getName(); + sal_Int32 extnPos = aNewName.lastIndexOf('.'); + if (extnPos > 0) + { + aNewName = aNewName.copy(0, extnPos); + } + + InputDialog aInputDlg(m_xDialog.get(), + xBrowseNode->getType() + == css::script::browse::BrowseNodeTypes::CONTAINER + ? CuiResId(STR_INPUTDIALOG_RENAMELIBRARYLABEL) + : CuiResId(STR_INPUTDIALOG_RENAMEMACROLABEL)); + aInputDlg.set_title(xBrowseNode->getType() + == css::script::browse::BrowseNodeTypes::CONTAINER + ? CuiResId(STR_INPUTDIALOG_RENAMELIBRARYTITLE) + : CuiResId(STR_INPUTDIALOG_RENAMEMACROTITLE)); + aInputDlg.SetEntryText(aNewName); + aInputDlg.HideHelpBtn(); + // doesn't check if the name already exists, that will be caught below by invoke + aInputDlg.setCheckEntry([](OUString sNewName) { + if (sNewName.isEmpty() || sNewName.getLength() > 30 + || !basctl::IsValidSbxName(sNewName)) + return false; + return true; + }); + + if (!aInputDlg.run()) + return; + + aNewName = aInputDlg.GetEntryText(); + + css::uno::Sequence args{ css::uno::Any(aNewName) }; + css::uno::Sequence outArgs; + css::uno::Sequence outIndex; + try + { + css::uno::Any aResult = xInv->invoke(u"Renamable"_ustr, args, outIndex, outArgs); + xBrowseNode.set(aResult, css::uno::UNO_QUERY); + } + catch (css::uno::Exception const&) + { + TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to Rename"); + } + } + if (xBrowseNode.is()) + { + if (xBrowseNode->getType() == css::script::browse::BrowseNodeTypes::CONTAINER) + { + m_xScriptContainersListBox->ScriptContainerSelected(); + } + else + { + ScriptInfo* pScriptInfo = weld::fromId(m_xScriptsListBox->get_id(rEntry)); + if (pScriptInfo) + { + css::uno::Reference xPropSet(xBrowseNode, + css::uno::UNO_QUERY); + if (xPropSet.is()) + { + 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 + } + pScriptInfo->sURL = sURI; + } + } + } + rTreeView.set_text(rEntry, xBrowseNode->getName()); + rTreeView.set_cursor(rEntry); + } + else + { + //ISSUE L10N & message from exception? + OUString aError(CuiResId(RID_CUISTR_RENAMEFAILED)); + std::unique_ptr xErrorBox(Application::CreateMessageDialog( + m_xDialog.get(), VclMessageType::Warning, VclButtonsType::Ok, aError)); + xErrorBox->set_title(CuiResId(RID_CUISTR_RENAMEFAILED_TITLE)); + xErrorBox->run(); + } +} + +// for Scripting Framework entries +// duplicate of OUString SvxScriptOrgDialog::getListOfChildren +// cui/source/dialogs/scriptdlg.cxx +OUString MacroManagerDialog::getListOfChildren( + const css::uno::Reference& node, int depth) +{ + OUStringBuffer result = "\n"; + for (int i = 0; i <= depth; i++) + { + result.append("\t"); + } + result.append(node->getName()); + + try + { + if (node->hasChildNodes()) + { + const css::uno::Sequence> children + = node->getChildNodes(); + for (const css::uno::Reference& n : children) + { + result.append(getListOfChildren(n, depth + 1)); + } + } + } + catch (css::uno::Exception&) + { + // ignore, will return an empty string + } + + return result.makeStringAndClear(); +} + +// modified verson of void SvxScriptOrgDialog::deleteEntry(const weld::TreeIter& rEntry) +// cui/source/dialogs/scriptdlg.cxx +void MacroManagerDialog::ScriptingFrameworkScriptsDeleteEntry(weld::TreeView& rTreeView, + const weld::TreeIter& rEntry) +{ + bool result = false; + css::uno::Reference node = getBrowseNode(rTreeView, rEntry); + // ISSUE L10N string & can we center list? + OUString aQuery = CuiResId(RID_CUISTR_DELQUERY) + getListOfChildren(node, 0); + std::unique_ptr xQueryBox(Application::CreateMessageDialog( + m_xDialog.get(), VclMessageType::Question, VclButtonsType::YesNo, aQuery)); + xQueryBox->set_title(CuiResId(RID_CUISTR_DELQUERY_TITLE)); + if (xQueryBox->run() == RET_NO) + { + return; + } + + css::uno::Reference xInv(node, css::uno::UNO_QUERY); + if (xInv.is()) + { + css::uno::Sequence args(0); + css::uno::Sequence outArgs(0); + css::uno::Sequence outIndex; + try + { + css::uno::Any aResult = xInv->invoke(u"Deletable"_ustr, args, outIndex, outArgs); + aResult >>= result; // or do we just assume true if no exception ? + } + catch (css::uno::Exception const&) + { + TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to delete"); + } + } + if (result) + { + if (&rTreeView == &m_xScriptContainersListBox->get_widget()) + { + m_xScriptContainersListBox->Remove(&rEntry, true); + SelectHdl(rTreeView); + } + else + { + m_xScriptsListBox->Remove(rEntry); + } + UpdateUI(); + } + else + { + //ISSUE L10N & message from exception? + std::unique_ptr xErrorBox( + Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Warning, + VclButtonsType::Ok, CuiResId(RID_CUISTR_DELFAILED))); + xErrorBox->set_title(CuiResId(RID_CUISTR_CREATEFAILED_TITLE)); + xErrorBox->run(); + } +} + +// Modified version of SvxScriptOrgDialog::CreateEntry +// cui/source/dialogs/scriptdlg.cxx +void MacroManagerDialog::ScriptingFrameworkScriptsCreateEntry(InputDialogMode eInputDialogMode) +{ + weld::TreeView& rTreeView = m_xScriptContainersListBox->get_widget(); + std::unique_ptr xSelectedIter = rTreeView.make_iterator(); + if (!rTreeView.get_selected(xSelectedIter.get())) + return; // should never happen + + css::uno::Reference aChildNode; + css::uno::Reference xBrowseNode + = getBrowseNode(rTreeView, *xSelectedIter); + css::uno::Reference xInv(xBrowseNode, css::uno::UNO_QUERY); + + // Currently, invocation is not implemented for python, only beanshell, javascript, and java. + if (xInv.is()) + { + OUString aNewName; + OUString aNewStdName; + if (eInputDialogMode == InputDialogMode::NEWLIB) + { + aNewStdName = CuiResId(STR_LIBRARY); + } + else + { + aNewStdName = CuiResId(STR_MACRO); + } + + bool bValid = false; + sal_Int32 i = 1; + + css::uno::Sequence> childNodes; + // no children => ok to create Parcel1 or Script1 without checking ? + try + { + if (!xBrowseNode->hasChildNodes()) + { + aNewName = aNewStdName + OUString::number(i); + bValid = true; + } + else + { + childNodes = xBrowseNode->getChildNodes(); + } + } + catch (css::uno::Exception&) + { + // ignore, will continue on with empty sequence + } + + OUString extn; + while (!bValid) + { + aNewName = aNewStdName + OUString::number(i); + bool bFound = false; + if (childNodes.hasElements()) + { + OUString nodeName = childNodes[0]->getName(); + sal_Int32 extnPos = nodeName.lastIndexOf('.'); + if (extnPos > 0) + extn = nodeName.copy(extnPos); + } + for (const css::uno::Reference& n : childNodes) + { + if (Concat2View(aNewName + extn) == n->getName()) + { + bFound = true; + break; + } + } + if (bFound) + { + i++; + } + else + { + bValid = true; + } + } + + InputDialog aInputDlg(m_xDialog.get(), eInputDialogMode == InputDialogMode::NEWLIB + ? CuiResId(STR_INPUTDIALOG_NEWLIBRARYLABEL) + : CuiResId(STR_INPUTDIALOG_NEWMACROLABEL)); + aInputDlg.set_title(eInputDialogMode == InputDialogMode::NEWLIB + ? CuiResId(STR_INPUTDIALOG_NEWLIBRARYTITLE) + : CuiResId(STR_INPUTDIALOG_NEWMACROTITLE)); + aInputDlg.SetEntryText(aNewName); + aInputDlg.HideHelpBtn(); + + // setCheckEntry doesn't check if the name already exists. It is checked after the dialog + // in the Creatable invocation call - this could be improved by including a check for + // existing name + aInputDlg.setCheckEntry([](OUString sNewName) { + if (sNewName.isEmpty() || sNewName.getLength() > 30 + || !basctl::IsValidSbxName(sNewName)) + return false; + return true; + }); + + do + { + if (aInputDlg.run()) + { + OUString aUserSuppliedName = aInputDlg.GetEntryText(); + bValid = true; + for (const css::uno::Reference& n : childNodes) + { + if (Concat2View(aUserSuppliedName + extn) == n->getName()) + { + bValid = false; + OUString aError = CuiResId(RID_CUISTR_CREATEFAILED) + + CuiResId(RID_CUISTR_CREATEFAILEDDUP); + + std::unique_ptr xErrorBox( + Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, + VclButtonsType::Ok, aError)); + xErrorBox->set_title(CuiResId(RID_CUISTR_CREATEFAILED_TITLE)); + xErrorBox->run(); + aInputDlg.SetEntryText(aNewName); + break; + } + } + if (bValid) + aNewName = aUserSuppliedName; + } + else + { + // user hit cancel + return; + } + } while (!bValid); + + // open up parent node (which ensures it's loaded) + rTreeView.expand_row(*xSelectedIter); + + css::uno::Sequence args{ css::uno::Any(aNewName) }; + css::uno::Sequence outArgs; + css::uno::Sequence outIndex; + try + { + css::uno::Any aResult = xInv->invoke(u"Creatable"_ustr, args, outIndex, outArgs); + aChildNode.set(aResult, css::uno::UNO_QUERY); + } + catch (css::uno::Exception const&) + { + TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to Create"); + } + } + if (aChildNode.is()) + { + if (rTreeView.get_iter_depth(*xSelectedIter) == 1) // language node + { + m_xScriptContainersListBox->Fill(xSelectedIter.get()); + rTreeView.expand_row(*xSelectedIter); + rTreeView.select(*xSelectedIter); + } + else + { + m_xScriptContainersListBox->ScriptContainerSelected(); + } + UpdateUI(); + } + else + { + //ISSUE L10N & message from exception? + OUString aError(CuiResId(RID_CUISTR_CREATEFAILED)); + std::unique_ptr xErrorBox(Application::CreateMessageDialog( + m_xDialog.get(), VclMessageType::Warning, VclButtonsType::Ok, aError)); + xErrorBox->set_title(CuiResId(RID_CUISTR_CREATEFAILED_TITLE)); + xErrorBox->run(); + } +} + +// called from OUString AbstractMacroManagerDialog_Impl::GetScriptURL() const +// cui/source/factory/dlgfact.cxx +OUString MacroManagerDialog::GetScriptURL() const +{ + OUString result; + std::unique_ptr xIter = m_xScriptsListBox->make_iterator(); + if (m_xScriptsListBox->get_selected(xIter.get())) + { + ScriptInfo* pScriptInfo = weld::fromId(m_xScriptsListBox->get_id(*xIter)); + if (pScriptInfo) + result = pScriptInfo->sURL; + } + return result; +} + +constexpr OUString MACRO_MANAGER_CONFIGNAME = u"MacroManagerDialog"_ustr; +constexpr OUString LAST_RUN_MACRO_INFO = u"LastRunMacro"_ustr; + +// adapted from SvxScriptSelectorDialog::SaveLastUsedMacro() +// cui/source/customize/cfgutil.cxx +void MacroManagerDialog::SaveLastUsedMacro() +{ + // Gets the current selection in the dialog as a series of selected entries + OUString sMacroInfo = m_xScriptsListBox->GetSelectedScriptName(); + + weld::TreeView& rScriptContainersTreeView = m_xScriptContainersListBox->get_widget(); + std::unique_ptr xIter = rScriptContainersTreeView.make_iterator(); + + if (!rScriptContainersTreeView.get_selected(xIter.get())) + return; + + do + { + sMacroInfo = rScriptContainersTreeView.get_text(*xIter) + "|" + sMacroInfo; + } while (rScriptContainersTreeView.iter_parent(*xIter)); + + SvtViewOptions(EViewType::Dialog, MACRO_MANAGER_CONFIGNAME) + .SetUserItem(LAST_RUN_MACRO_INFO, css::uno::Any(sMacroInfo)); +} + +// adapted from SvxScriptSelectorDialog::LoadLastUsedMacro() +// cui/source/customize/cfgutil.cxx +void MacroManagerDialog::LoadLastUsedMacro() +{ + SvtViewOptions aDlgOpt(EViewType::Dialog, MACRO_MANAGER_CONFIGNAME); + if (!aDlgOpt.Exists()) + return; + + OUString sMacroInfo; + aDlgOpt.GetUserItem(LAST_RUN_MACRO_INFO) >>= sMacroInfo; + if (sMacroInfo.isEmpty()) + return; + + // Counts how many entries exist in the macro info string + sal_Int16 nInfoParts = 0; + sal_Int16 nLastIndex = sMacroInfo.indexOf('|'); + if (nLastIndex > -1) + { + nInfoParts = 1; + while (nLastIndex != -1) + { + nInfoParts++; + nLastIndex = sMacroInfo.indexOf('|', nLastIndex + 1); + } + } + + weld::TreeView& rScriptContainersTreeView = m_xScriptContainersListBox->get_widget(); + std::unique_ptr xIter = rScriptContainersTreeView.make_iterator(); + + if (!rScriptContainersTreeView.get_iter_first(*xIter)) + return; + + // Expand the nodes in the script containers tree + OUString sNodeToExpand; + bool bIsIterValid; + sal_Int16 nOpenedNodes = 0; + for (sal_Int16 i = 0; i < nInfoParts - 1; i++) + { + sNodeToExpand = sMacroInfo.getToken(i, '|'); + bIsIterValid = true; + while (bIsIterValid && rScriptContainersTreeView.get_text(*xIter) != sNodeToExpand) + bIsIterValid = rScriptContainersTreeView.iter_next_sibling(*xIter); + + if (bIsIterValid) + { + rScriptContainersTreeView.expand_row(*xIter); + nOpenedNodes++; + } + if (rScriptContainersTreeView.iter_has_child(*xIter)) + (void)rScriptContainersTreeView.iter_children(*xIter); + else if (nOpenedNodes < nInfoParts - 1) + // If the number of levels in the tree is smaller than the + // number of parts in the macro info string, then return + return; + } + rScriptContainersTreeView.select(*xIter); + rScriptContainersTreeView.scroll_to_row(*xIter); + + // fill the scripts list box and set the label + m_xScriptContainersListBox->ScriptContainerSelected(); + m_xScriptsListBoxLabel->set_label(m_aScriptsListBoxLabelBaseStr + " " + + rScriptContainersTreeView.get_text(*xIter)); + + // Select the macro in the scripts tree + weld::TreeView& rScriptsTreeView = m_xScriptsListBox->get_widget(); + xIter = rScriptsTreeView.make_iterator(); + if (rScriptsTreeView.get_iter_first(*xIter)) + { + OUString sMacroName = sMacroInfo.getToken(nInfoParts - 1, '|'); + bIsIterValid = true; + while (bIsIterValid && rScriptsTreeView.get_text(*xIter) != sMacroName) + bIsIterValid = rScriptsTreeView.iter_next_sibling(*xIter); + if (bIsIterValid) + { + rScriptsTreeView.scroll_to_row(*xIter); + rScriptsTreeView.select(*xIter); + } + } + + UpdateUI(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/cui/source/factory/dlgfact.cxx b/cui/source/factory/dlgfact.cxx index 4e8a2dab3c5a..2018878eaefa 100644 --- a/cui/source/factory/dlgfact.cxx +++ b/cui/source/factory/dlgfact.cxx @@ -94,6 +94,8 @@ #include #include +#include + using namespace ::com::sun::star; using namespace ::com::sun::star::frame; using namespace ::com::sun::star::container; @@ -134,6 +136,7 @@ IMPL_ABSTDLG_CLASS_ASYNC(AbstractPasswordToOpenModifyDialog,weld::DialogControll IMPL_ABSTDLG_CLASS_ASYNC(AbstractQrCodeGenDialog,QrCodeGenDialog) IMPL_ABSTDLG_CLASS_ASYNC(AbstractPasteDialog,SfxDialogController) IMPL_ABSTDLG_CLASS_ASYNC(AbstractScriptSelectorDialog,SfxDialogController) +IMPL_ABSTDLG_CLASS_ASYNC(AbstractMacroManagerDialog,SfxDialogController) IMPL_ABSTDLG_CLASS_ASYNC(AbstractSpellDialog,SfxDialogController) IMPL_ABSTDLG_CLASS_ASYNC(AbstractSvxAreaTabDialog,SfxTabDialogController) IMPL_ABSTDLG_CLASS_ASYNC(AbstractSvxCaptionDialog,SfxTabDialogController) @@ -996,6 +999,18 @@ void AbstractScriptSelectorDialog_Impl::SetRunLabel() m_xDlg->SetRunLabel(); } +VclPtr +AbstractDialogFactory_Impl::CreateMacroManagerDialog(weld::Window* pParent, + const Reference& rxFrame) +{ + return VclPtr::Create( + std::make_shared(pParent, rxFrame)); +} + +OUString AbstractMacroManagerDialog_Impl::GetScriptURL() const { return m_xDlg->GetScriptURL(); } + +void AbstractMacroManagerDialog_Impl::LoadLastUsedMacro() const { m_xDlg->LoadLastUsedMacro(); } + VclPtr AbstractDialogFactory_Impl::CreateSvxScriptOrgDialog(weld::Window* pParent, const OUString& rLanguage) { diff --git a/cui/source/factory/dlgfact.hxx b/cui/source/factory/dlgfact.hxx index b1c82104c7a0..793cf193af09 100644 --- a/cui/source/factory/dlgfact.hxx +++ b/cui/source/factory/dlgfact.hxx @@ -60,6 +60,8 @@ #include #include +#include + #define DECL_ABSTDLG_CLASS_(Class,Base,Dialog,StdPtr) \ class Class##_Impl final : public Base \ { \ @@ -206,6 +208,13 @@ DECL_ABSTDLG_CLASS_ASYNC(AbstractScriptSelectorDialog,SvxScriptSelectorDialog) virtual void SetRunLabel() override; }; + +// AbstractMacroManagerDialog_Impl +DECL_ABSTDLG_CLASS_ASYNC(AbstractMacroManagerDialog,MacroManagerDialog) + virtual OUString GetScriptURL() const override; + virtual void LoadLastUsedMacro() const override; +}; + // AbstractGalleryIdDialog_Impl DECL_ABSTDLG_CLASS(AbstractGalleryIdDialog,GalleryIdDialog) virtual sal_uInt32 GetId() const override; @@ -575,6 +584,10 @@ public: virtual VclPtr CreateScriptSelectorDialog(weld::Window* pParent, const css::uno::Reference< css::frame::XFrame >& rxFrame) override; + virtual VclPtr CreateMacroManagerDialog(weld::Window* pParent, + const css::uno::Reference< css::frame::XFrame >& rxFrame) override; + + virtual void ShowAsyncScriptErrorDialog(weld::Window* pParent, const css::uno::Any& rException) override; virtual VclPtr CreateSvxMacroAssignDlg( diff --git a/cui/source/inc/MacroManagerDialog.hxx b/cui/source/inc/MacroManagerDialog.hxx new file mode 100644 index 000000000000..64854d6980a6 --- /dev/null +++ b/cui/source/inc/MacroManagerDialog.hxx @@ -0,0 +1,255 @@ +/* -*- 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/. + */ + +#pragma once + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +struct ScriptContainerInfo +{ + css::script::browse::XBrowseNode* pBrowseNode; + + ScriptContainerInfo(css::script::browse::XBrowseNode* pObj) + : pBrowseNode(pObj) + { + } +}; + +struct ScriptInfo +{ + css::script::browse::XBrowseNode* pBrowseNode; + OUString sURL; + OUString sDescription; + + ScriptInfo(css::script::browse::XBrowseNode* pObj, const OUString& rsUrl, + const OUString& rsDesc) + : pBrowseNode(pObj) + , sURL(rsUrl) + , sDescription(rsDesc) + { + } +}; + +typedef std::vector> ScriptInfoArr; + +// inspired by class CuiConfigFunctionListBox +// cui/source/inc/cfgutil.hxx +class ScriptsListBox +{ + friend class ScriptContainersListBox; // for access to aArr + + ScriptInfoArr aArr; + + std::unique_ptr m_xTreeView; + std::unique_ptr m_xScratchIter; + + DECL_LINK(QueryTooltip, const weld::TreeIter& rIter, OUString); + +public: + ScriptsListBox(std::unique_ptr xTreeView); + ~ScriptsListBox(); + + void ClearAll(); + static OUString GetDescriptionText(const OUString& rId); + OUString GetSelectedScriptName(); + + void connect_changed(const Link& rLink) + { + m_xTreeView->connect_changed(rLink); + } + void connect_popup_menu(const Link& rLink) + { + m_xTreeView->connect_popup_menu(rLink); + } + void connect_row_activated(const Link& rLink) + { + m_xTreeView->connect_row_activated(rLink); + } + void freeze() { m_xTreeView->freeze(); } + void thaw() { m_xTreeView->thaw(); } + void append(const OUString& rId, const OUString& rStr, const OUString& rImage, + const weld::TreeIter* pParent = nullptr) + { + m_xTreeView->insert(pParent, -1, &rStr, &rId, nullptr, nullptr, false, + m_xScratchIter.get()); + m_xTreeView->set_image(*m_xScratchIter, rImage); + } + int n_children() const { return m_xTreeView->n_children(); } + std::unique_ptr make_iterator(const weld::TreeIter* pOrig = nullptr) const + { + return m_xTreeView->make_iterator(pOrig); + } + OUString get_id(const weld::TreeIter& rIter) const { return m_xTreeView->get_id(rIter); } + bool get_selected(weld::TreeIter* pIter) const { return m_xTreeView->get_selected(pIter); } + OUString get_selected_id() const + { + if (!m_xTreeView->get_selected(m_xScratchIter.get())) + return OUString(); + return m_xTreeView->get_id(*m_xScratchIter); + } + void select(int pos) { m_xTreeView->select(pos); } + weld::TreeView& get_widget() { return *m_xTreeView; } + + void Remove(const weld::TreeIter& rEntry); +}; + +enum class ScriptContainerType +{ + LOCATION, + LANGUAGE, + LIBRARY, + MODULEORDIALOG +}; + +class MacroManagerDialog; + +// locations, libraries, modules, and dialogs +class ScriptContainersListBox +{ + friend class MacroManagerDialog; + + ScriptsListBox* m_pScriptsListBox; + + css::uno::Reference m_xContext; + css::uno::Reference m_xFrame; + + std::unique_ptr m_xTreeView; + + void Remove(const weld::TreeIter* pEntryIter, bool bRemoveEntryIter); + void Fill(const weld::TreeIter* pEntryIter); + basctl::ScriptDocument GetScriptDocument(const weld::TreeIter* pIter = nullptr); + + DECL_LINK(ExpandingHdl, const weld::TreeIter&, bool); + DECL_LINK(QueryTooltip, const weld::TreeIter& rIter, OUString); + + // for weld::WaitObject which seems not to always behave as expected without the + // dialog window as a parent + MacroManagerDialog* m_pMacroManagerDialog; + +public: + ScriptContainersListBox(std::unique_ptr xTreeView, + MacroManagerDialog* pMacroManagerDialog); + ~ScriptContainersListBox(); + + void connect_changed(const Link& rLink) + { + m_xTreeView->connect_changed(rLink); + } + void set_size_request(int nWidth, int nHeight) + { + m_xTreeView->set_size_request(nWidth, nHeight); + } + weld::TreeView& get_widget() { return *m_xTreeView; } + void ClearAll(); + + void Init(const css::uno::Reference& xContext, + const css::uno::Reference& xFrame); + void SetScriptsListBox(ScriptsListBox* pBox) { m_pScriptsListBox = pBox; } + void ScriptContainerSelected(); + + void Insert(const css::uno::Reference& xInsertNode, + const weld::TreeIter* pParentEntry, const OUString& rsUiName, + const OUString& rsImage, bool bChildOnDemand = false, int nPos = -1, + weld::TreeIter* pRet = nullptr); + + OUString GetContainerName(const weld::TreeIter& rIter, + const ScriptContainerType eScriptContainerType); + OUString GetSelectedEntryContainerName(ScriptContainerType eScriptContainerType); +}; + +enum class InputDialogMode; + +class MacroManagerDialog : public weld::GenericDialogController, public SfxListener +{ + OUString m_aScriptsListBoxLabelBaseStr; + + // For forwarding to Assign dialog + css::uno::Reference m_xDocumentFrame; + + std::unique_ptr m_xDialogDescription; + std::unique_ptr m_xScriptContainersListBox; + std::unique_ptr m_xScriptsListBox; + std::unique_ptr m_xScriptContainersListBoxLabel; + std::unique_ptr m_xScriptsListBoxLabel; + std::unique_ptr m_xRunButton; + std::unique_ptr m_xCloseButton; + std::unique_ptr m_xDescriptionText; + std::unique_ptr m_xDescriptionFrame; + std::unique_ptr m_xNewLibraryButton; + std::unique_ptr m_xNewModuleButton; + std::unique_ptr m_xNewDialogButton; + std::unique_ptr m_xLibraryModuleDialogEditButton; + std::unique_ptr m_xLibraryModuleDialogRenameButton; + std::unique_ptr m_xLibraryModuleDialogDeleteButton; + std::unique_ptr m_xLibraryPasswordButton; + std::unique_ptr m_xLibraryImportButton; + std::unique_ptr m_xLibraryExportButton; + std::unique_ptr m_xMacroEditButton; + std::unique_ptr m_xMacroDeleteButton; + std::unique_ptr m_xMacroCreateButton; + std::unique_ptr m_xMacroRenameButton; + std::unique_ptr m_xAssignButton; + + DECL_LINK(ClickHdl, weld::Button&, void); + DECL_LINK(SelectHdl, weld::TreeView&, void); + DECL_LINK(FunctionDoubleClickHdl, weld::TreeView&, bool); + DECL_LINK(ContextMenuHdl, const CommandEvent&, bool); + DECL_LINK(CheckPasswordHdl, SvxPasswordDialog*, bool); + + void BasicScriptsCreateLibrary(const basctl::ScriptDocument& rDocument); + void BasicScriptsCreateModule(const basctl::ScriptDocument& rDocument); + void BasicScriptsCreateDialog(const basctl::ScriptDocument& rDocument); + void BasicScriptsLibraryModuleDialogEdit(const basctl::ScriptDocument& rDocument); + void BasicScriptsLibraryModuleDialogRename(const basctl::ScriptDocument& rDocument); + void BasicScriptsLibraryModuleDialogDelete(const basctl::ScriptDocument& rDocument); + void BasicScriptsLibraryPassword(const basctl::ScriptDocument& rDocument); + void BasicScriptsMacroEdit(const basctl::ScriptDocument& rDocument); + bool IsLibraryReadOnlyOrFailedPasswordQuery(const basctl::ScriptDocument& rDocument, + weld::TreeIter* pIter); + + void ScriptingFrameworkScriptsCreateEntry(InputDialogMode eInputDialogMode); + void ScriptingFrameworkScriptsRenameEntry(weld::TreeView& rTreeView, + const weld::TreeIter& rEntry); + void ScriptingFrameworkScriptsDeleteEntry(weld::TreeView& rTreeView, + const weld::TreeIter& rEntry); + static bool getBoolProperty(css::uno::Reference const& xProps, + OUString const& propName); + OUString getListOfChildren(const css::uno::Reference& node, + int depth); + + css::uno::Reference + getBrowseNode(const weld::TreeView& rTreeView, const weld::TreeIter& rTreeIter); + + void UpdateUI(); + void CheckButtons(); + + virtual void Notify(SfxBroadcaster&, const SfxHint& rHint) override; + +public: + MacroManagerDialog(weld::Window* pParent, + const css::uno::Reference& xFrame); + virtual ~MacroManagerDialog() override; + + OUString GetScriptURL() const; + + void SaveLastUsedMacro(); + void LoadLastUsedMacro(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/cui/source/inc/cfgutil.hxx b/cui/source/inc/cfgutil.hxx index 96bf9fb65067..ce409c98e72d 100644 --- a/cui/source/inc/cfgutil.hxx +++ b/cui/source/inc/cfgutil.hxx @@ -195,11 +195,6 @@ class CuiConfigGroupListBox std::unique_ptr m_xTreeView; std::unique_ptr m_xScratchIter; - static OUString GetImage( - const css::uno::Reference< css::script::browse::XBrowseNode >& node, - css::uno::Reference< css::uno::XComponentContext > const & xCtx, - bool bIsRootNode); - static css::uno::Reference< css::uno::XInterface > getDocumentModel( css::uno::Reference< css::uno::XComponentContext > const & xCtx, std::u16string_view docName); @@ -232,6 +227,11 @@ public: void SelectMacro(const SfxMacroInfoItem*); #endif void SetStylesInfo(SfxStylesInfo_Impl* pStyles); + + static OUString GetImage( + const css::uno::Reference< css::script::browse::XBrowseNode >& node, + css::uno::Reference< css::uno::XComponentContext > const & xCtx, + bool bIsRootNode); }; class SvxScriptSelectorDialog : public weld::GenericDialogController diff --git a/cui/uiconfig/ui/macromanagerdialog.ui b/cui/uiconfig/ui/macromanagerdialog.ui new file mode 100644 index 000000000000..d215c18eb4a8 --- /dev/null +++ b/cui/uiconfig/ui/macromanagerdialog.ui @@ -0,0 +1,564 @@ + + + + + + + + + + + + + + + + + + + + + + + + False + 6 + Macro Manager + True + 0 + 0 + dialog + + + False + vertical + 12 + + + False + end + + + Close + True + True + True + True + True + + + False + True + 2 + + + + + _Help + True + True + True + True + + + False + True + 4 + True + + + + + False + True + end + 0 + + + + + True + False + vertical + 12 + + + True + False + 6 + 6 + 6 + 6 + 6 + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + + + True + True + True + True + in + + + True + True + True + True + liststore1 + False + 1 + True + + + + + + 6 + + + + 0 + + + + + + 1 + + + + + + + + + True + True + 0 + + + + + True + False + vertical + start + + + New Library... + True + False + True + True + + + Creates a new library. + + + + + False + True + 0 + + + + + New Module... + True + False + True + True + + + False + True + 1 + + + + + New Dialog... + True + False + True + True + + + False + True + 2 + + + + + Edit + True + False + True + True + + + False + True + 3 + + + + + Rename... + True + False + True + True + + + False + True + 4 + + + + + Delete... + True + False + True + True + + + False + True + 5 + + + + + Password... + True + False + True + True + + + Assigns or edits the password for the selected library. + + + + + False + True + 6 + + + + + Import... + True + False + True + True + + + Locate the Basic library that you want to add to the current list, and then click Open. + + + + + False + True + 7 + + + + + Export... + True + False + True + True + + + False + True + 8 + + + + + False + True + 2 + + + + + + + True + False + 6 + Libraries/Modules/Dialogs + + + + + + + + False + True + 0 + + + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + + + True + True + True + True + in + + + True + True + True + liststore2 + False + 0 + False + + + + + + + + + 0 + + + + + + + + + True + True + 0 + + + + + True + False + vertical + start + + + Run + True + False + True + True + + + False + True + 0 + + + + + Assign... + True + False + True + True + + + False + True + 1 + + + + + Create... + True + False + True + True + + + True + True + 2 + + + + + Edit + True + False + True + True + + + False + True + 3 + + + + + Rename... + True + False + True + True + + + False + True + 4 + + + + + Delete... + True + False + True + True + + + False + True + 5 + + + + + False + True + 2 + + + + + + + True + False + 6 + Existing macros in: + + + + + + + + False + True + 1 + + + + + True + True + 2 + + + + + True + False + 6 + 6 + 6 + 6 + 0 + none + + + 100 + True + True + + + True + False + False + word + False + + + + + + + True + False + 6 + _Description + True + + + + + + + + False + True + 3 + + + + + True + True + 1 + + + + + + close + help + + + diff --git a/dbaccess/uiconfig/dbapp/menubar/menubar.xml b/dbaccess/uiconfig/dbapp/menubar/menubar.xml index 29e65762524c..924db564a2f6 100644 --- a/dbaccess/uiconfig/dbapp/menubar/menubar.xml +++ b/dbaccess/uiconfig/dbapp/menubar/menubar.xml @@ -120,6 +120,8 @@ + + diff --git a/dbaccess/uiconfig/dbquery/menubar/menubar.xml b/dbaccess/uiconfig/dbquery/menubar/menubar.xml index 762a5533de74..5eb22274306d 100644 --- a/dbaccess/uiconfig/dbquery/menubar/menubar.xml +++ b/dbaccess/uiconfig/dbquery/menubar/menubar.xml @@ -75,6 +75,8 @@ + + diff --git a/dbaccess/uiconfig/dbrelation/menubar/menubar.xml b/dbaccess/uiconfig/dbrelation/menubar/menubar.xml index 0c2a73ec31d5..a88bb7abf0c7 100644 --- a/dbaccess/uiconfig/dbrelation/menubar/menubar.xml +++ b/dbaccess/uiconfig/dbrelation/menubar/menubar.xml @@ -58,6 +58,8 @@ + + diff --git a/dbaccess/uiconfig/dbtable/menubar/menubar.xml b/dbaccess/uiconfig/dbtable/menubar/menubar.xml index 80511e8ea4d6..5ccbf5d5f84a 100644 --- a/dbaccess/uiconfig/dbtable/menubar/menubar.xml +++ b/dbaccess/uiconfig/dbtable/menubar/menubar.xml @@ -59,6 +59,8 @@ + + diff --git a/dbaccess/uiconfig/dbtdata/menubar/menubar.xml b/dbaccess/uiconfig/dbtdata/menubar/menubar.xml index e787d60d7355..6313b55fc5f7 100644 --- a/dbaccess/uiconfig/dbtdata/menubar/menubar.xml +++ b/dbaccess/uiconfig/dbtdata/menubar/menubar.xml @@ -84,6 +84,8 @@ + + diff --git a/extensions/uiconfig/sbibliography/menubar/menubar.xml b/extensions/uiconfig/sbibliography/menubar/menubar.xml index 9b449072ac32..3851ceb21aa4 100644 --- a/extensions/uiconfig/sbibliography/menubar/menubar.xml +++ b/extensions/uiconfig/sbibliography/menubar/menubar.xml @@ -32,6 +32,8 @@ + + diff --git a/framework/uiconfig/startmodule/menubar/menubar.xml b/framework/uiconfig/startmodule/menubar/menubar.xml index 72f0354a79df..097154cc3483 100644 --- a/framework/uiconfig/startmodule/menubar/menubar.xml +++ b/framework/uiconfig/startmodule/menubar/menubar.xml @@ -45,6 +45,8 @@ + + diff --git a/include/basctl/basctldllapi.h b/include/basctl/basctldllapi.h new file mode 100644 index 000000000000..9cc166361d1c --- /dev/null +++ b/include/basctl/basctldllapi.h @@ -0,0 +1,23 @@ +/* -*- 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/. + */ + +#pragma once + +#include +#include + +#if defined BASCTL_DLLIMPLEMENTATION +#define BASCTL_DLLPUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define BASCTL_DLLPUBLIC SAL_DLLPUBLIC_IMPORT +#endif + +#define BASCTL_DLLPRIVATE SAL_DLLPRIVATE + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/include/basctl/basctldllpublic.hxx b/include/basctl/basctldllpublic.hxx new file mode 100644 index 000000000000..13adf9d7cc3c --- /dev/null +++ b/include/basctl/basctldllpublic.hxx @@ -0,0 +1,43 @@ +/* -*- 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/. + */ + +#pragma once + +#include + +#include "basctldllapi.h" +#include "scriptdocument.hxx" +#include +#include + +namespace basctl +{ +BASCTL_DLLPUBLIC bool IsValidSbxName(std::u16string_view rName); +BASCTL_DLLPUBLIC SAL_RET_MAYBENULL SfxDispatcher* GetDispatcher(); +BASCTL_DLLPUBLIC void MarkDocumentModified(const ScriptDocument& rDocument); + +BASCTL_DLLPUBLIC bool QueryDelDialog(std::u16string_view rName, weld::Widget* pParent); +BASCTL_DLLPUBLIC bool QueryDelModule(std::u16string_view rName, weld::Widget* pParent); +BASCTL_DLLPUBLIC bool QueryDelLib(std::u16string_view rName, bool bRef, weld::Widget* pParent); +BASCTL_DLLPUBLIC bool +QueryPassword(weld::Widget* pDialogParent, + const css::uno::Reference& xLibContainer, + const OUString& rLibName, OUString& rPassword, bool bRepeat = false, + bool bNewTitle = false); + +BASCTL_DLLPUBLIC void ImportLib(const ScriptDocument& rDocument, weld::Dialog* pDialog, + const std::function& func_remove_entry, + const std::function& func_insert_entry, + const std::function& func_insert_entries); + +BASCTL_DLLPUBLIC void Export(const ScriptDocument& rDocument, const OUString& aLibName, + weld::Dialog* pDialog); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/basctl/source/inc/sbxitem.hxx b/include/basctl/sbxitem.hxx similarity index 96% rename from basctl/source/inc/sbxitem.hxx rename to include/basctl/sbxitem.hxx index a21e792742ca..23244fe2e42f 100644 --- a/basctl/source/inc/sbxitem.hxx +++ b/include/basctl/sbxitem.hxx @@ -18,6 +18,7 @@ */ #pragma once +#include "basctldllapi.h" #include "scriptdocument.hxx" #include @@ -34,7 +35,7 @@ enum SbxItemType SBX_TYPE_METHOD }; -class SbxItem : public SfxPoolItem +class BASCTL_DLLPUBLIC SbxItem : public SfxPoolItem { const ScriptDocument m_aDocument; const OUString m_aLibName; diff --git a/basctl/source/inc/scriptdocument.hxx b/include/basctl/scriptdocument.hxx similarity index 99% rename from basctl/source/inc/scriptdocument.hxx rename to include/basctl/scriptdocument.hxx index d52dcb6c8c5f..645ca1ab055f 100644 --- a/basctl/source/inc/scriptdocument.hxx +++ b/include/basctl/scriptdocument.hxx @@ -19,6 +19,8 @@ #pragma once +#include "basctldllapi.h" + #include #include #include @@ -61,7 +63,7 @@ namespace basctl /** encapsulates a document which contains Basic scripts and dialogs */ - class ScriptDocument + class BASCTL_DLLPUBLIC ScriptDocument { private: class Impl; diff --git a/include/sfx2/minfitem.hxx b/include/sfx2/minfitem.hxx index c89705726e20..bbf4744afd62 100644 --- a/include/sfx2/minfitem.hxx +++ b/include/sfx2/minfitem.hxx @@ -36,6 +36,7 @@ class SFX2_DLLPUBLIC SfxMacroInfoItem final : public SfxPoolItem OUString aModuleName; OUString aMethodName; OUString aCommentText; + OUString aLocationName; public: static SfxPoolItem* CreateDefault(); @@ -44,7 +45,8 @@ public: OUString aLibName, OUString aModuleName, OUString aMethodName, - OUString aComment); + OUString aComment, + OUString aLocation = OUString()); virtual SfxMacroInfoItem* Clone( SfxItemPool *pPool = nullptr ) const override; virtual bool operator==( const SfxPoolItem& ) const override; @@ -63,6 +65,7 @@ public: const BasicManager* GetBasicManager() const { return pBasicManager; } OUString GetQualifiedName() const; + const OUString& GetLocation() const { return aLocationName; } }; #endif diff --git a/include/sfx2/sfxdlg.hxx b/include/sfx2/sfxdlg.hxx index 31bd0c3108ad..d5cf73b667bf 100644 --- a/include/sfx2/sfxdlg.hxx +++ b/include/sfx2/sfxdlg.hxx @@ -112,6 +112,16 @@ public: virtual void SetRunLabel() = 0; }; +class AbstractMacroManagerDialog : virtual public VclAbstractDialog +{ +protected: + virtual ~AbstractMacroManagerDialog() override = default; + +public: + virtual OUString GetScriptURL() const = 0; + virtual void LoadLastUsedMacro() const = 0; +}; + namespace com::sun::star::frame { class XFrame; } class SFX2_DLLPUBLIC SfxAbstractDialogFactory : virtual public VclAbstractDialogFactory @@ -140,6 +150,11 @@ public: virtual VclPtr CreateScriptSelectorDialog(weld::Window* pParent, const css::uno::Reference< css::frame::XFrame >& rxFrame) = 0; + virtual VclPtr + CreateMacroManagerDialog(weld::Window* pParent, + const css::uno::Reference& rxFrame) + = 0; + virtual void ShowAsyncScriptErrorDialog( weld::Window* pParent, const css::uno::Any& rException ) = 0; virtual VclPtr CreateOptionsDialog( diff --git a/include/sfx2/sfxsids.hrc b/include/sfx2/sfxsids.hrc index 6dbd397f8922..c71ddca61559 100644 --- a/include/sfx2/sfxsids.hrc +++ b/include/sfx2/sfxsids.hrc @@ -300,6 +300,7 @@ class SvxZoomItem; #define SID_OPTIONS_PAGEID TypedWhichId(SID_SFX_START + 1747) #define SID_GPGSIGN TypedWhichId(SID_SFX_START + 1748) #define FN_INVERT_BACKGROUND (SID_SFX_START + 1749) +#define SID_MACROMANAGER (SID_SFX_START + 1750) // SID_SFX_free_END (SID_SFX_START + 3999) #define SID_OPEN_NEW_VIEW TypedWhichId(SID_SFX_START + 520) diff --git a/include/svl/hint.hxx b/include/svl/hint.hxx index 894bdeec6786..a1c4ea43ae2f 100644 --- a/include/svl/hint.hxx +++ b/include/svl/hint.hxx @@ -84,6 +84,8 @@ enum class SfxHintId { // basctl BasCtlDlgEd, + ScriptDocumentChanged, + // reportdesign ReportDesignDlgEd, @@ -266,6 +268,7 @@ inline std::basic_ostream & operator <<( case SfxHintId::BasicInfoWanted: return stream << "BasicInfoWanted"; case SfxHintId::BasicStart: return stream << "BasicStart"; case SfxHintId::BasicStop: return stream << "BasicStop"; + case SfxHintId::ScriptDocumentChanged: return stream << "ScriptDocumentChanged"; case SfxHintId::FmDesignModeChanged: return stream << "FmDesignModeChanged"; case SfxHintId::EditSourceParasMoved: return stream << "EditSourceParasMoved"; case SfxHintId::EditSourceSelectionChanged: return stream << "EditSourceSelectionChanged"; diff --git a/include/svx/passwd.hxx b/include/svx/passwd.hxx index c6342df0d3c8..0b4a4922a109 100644 --- a/include/svx/passwd.hxx +++ b/include/svx/passwd.hxx @@ -23,7 +23,7 @@ #include #include -class UNLESS_MERGELIBS(SVX_DLLPUBLIC) SvxPasswordDialog final : public SfxDialogController +class UNLESS_MERGELIBS_MORE(SVX_DLLPUBLIC) SvxPasswordDialog final : public SfxDialogController { private: OUString m_aOldPasswdErrStr; diff --git a/include/svx/svxdlg.hxx b/include/svx/svxdlg.hxx index a2ef0c03a47e..90951647ee45 100644 --- a/include/svx/svxdlg.hxx +++ b/include/svx/svxdlg.hxx @@ -430,6 +430,9 @@ public: virtual VclPtr CreateScriptSelectorDialog(weld::Window* pParent, const css::uno::Reference< css::frame::XFrame >& rxFrame) override = 0; + virtual VclPtr CreateMacroManagerDialog(weld::Window* pParent, + const css::uno::Reference< css::frame::XFrame >& rxFrame) override = 0; + virtual void ShowAsyncScriptErrorDialog(weld::Window* pParent, const css::uno::Any& rException) override = 0; virtual VclPtr CreateSvxMacroAssignDlg( diff --git a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu index 5c92e5147718..254ed0d77c2c 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu @@ -5531,6 +5531,17 @@ bit 3 (0x8): #define UICOMMANDDESCRIPTION_PROPERTIES_TOGGLEBUTTON 8 1 + + + Macro Manager... + + + 1 + + + true + + Gallery diff --git a/reportdesign/uiconfig/dbreport/menubar/menubar.xml b/reportdesign/uiconfig/dbreport/menubar/menubar.xml index e95054ed7889..fa2fcf02ba40 100644 --- a/reportdesign/uiconfig/dbreport/menubar/menubar.xml +++ b/reportdesign/uiconfig/dbreport/menubar/menubar.xml @@ -249,6 +249,8 @@ + + diff --git a/sc/uiconfig/scalc/menubar/menubar.xml b/sc/uiconfig/scalc/menubar/menubar.xml index 61ea6c74b286..6563defbafd7 100644 --- a/sc/uiconfig/scalc/menubar/menubar.xml +++ b/sc/uiconfig/scalc/menubar/menubar.xml @@ -720,6 +720,8 @@ + + diff --git a/sd/uiconfig/sdraw/menubar/menubar.xml b/sd/uiconfig/sdraw/menubar/menubar.xml index 1865877146e3..183c595917c0 100644 --- a/sd/uiconfig/sdraw/menubar/menubar.xml +++ b/sd/uiconfig/sdraw/menubar/menubar.xml @@ -595,6 +595,8 @@ + + diff --git a/sd/uiconfig/simpress/menubar/menubar.xml b/sd/uiconfig/simpress/menubar/menubar.xml index ec88c1e06e09..07f0456335aa 100644 --- a/sd/uiconfig/simpress/menubar/menubar.xml +++ b/sd/uiconfig/simpress/menubar/menubar.xml @@ -637,6 +637,8 @@ + + diff --git a/sfx2/sdi/appslots.sdi b/sfx2/sdi/appslots.sdi index 9d8063487637..47af19347cf4 100644 --- a/sfx2/sdi/appslots.sdi +++ b/sfx2/sdi/appslots.sdi @@ -289,6 +289,11 @@ shell SfxApplication [ ExecMethod = OfaExec_Impl; ] + SID_MACROMANAGER + [ + ExecMethod = OfaExec_Impl; + StateMethod = OfaState_Impl; + ] SID_INET_DLG // status(final) [ ExecMethod = OfaExec_Impl; diff --git a/sfx2/sdi/sfx.sdi b/sfx2/sdi/sfx.sdi index 3e7ebf9046be..aa09ee044235 100644 --- a/sfx2/sdi/sfx.sdi +++ b/sfx2/sdi/sfx.sdi @@ -2427,6 +2427,23 @@ SfxVoidItem RunMacro SID_RUNMACRO GroupId = SfxGroupId::Macro; ] +SfxVoidItem MacroManager SID_MACROMANAGER +() +[ + AutoUpdate = FALSE, + FastCall = TRUE, + ReadOnlyDoc = TRUE, + Toggle = FALSE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + + AccelConfig = TRUE, + MenuConfig = TRUE, + ToolBoxConfig = TRUE, + GroupId = SfxGroupId::Macro; +] + SfxVoidItem GotoLine SID_GOTOLINE [ diff --git a/sfx2/source/appl/appserv.cxx b/sfx2/source/appl/appserv.cxx index cc65220c8fb5..fdc4a8e0b3ee 100644 --- a/sfx2/source/appl/appserv.cxx +++ b/sfx2/source/appl/appserv.cxx @@ -1894,6 +1894,56 @@ void SfxApplication::OfaExec_Impl( SfxRequest& rReq ) rReq.Done(); } break; + + case SID_MACROMANAGER: + { + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + + Reference xFrame(GetRequestFrame(rReq)); + if (!xFrame.is()) + { + if (const SfxViewFrame* pViewFrame = SfxViewFrame::Current()) + xFrame = pViewFrame->GetFrame().GetFrameInterface(); + } + + VclPtr pDlg( + pFact->CreateMacroManagerDialog(lcl_getDialogParent(xFrame), xFrame)); + OSL_ENSURE(pDlg, "SfxApplication::OfaExec_Impl(SID_MACROMANAGER): no dialog!"); + if (pDlg) + { + pDlg->StartExecuteAsync( + [pDlg, xFrame](sal_Int32 nDialogResult) + { + if (!nDialogResult) + { + pDlg->disposeOnce(); + return; + } + + Sequence args; + Sequence outIndex; + Sequence outArgs; + Any ret; + + Reference xScriptContext; + + Reference xController; + if (xFrame.is()) + xController = xFrame->getController(); + if (xController.is()) + xScriptContext = xController->getModel(); + if (!xScriptContext.is()) + xScriptContext = xController; + + SfxObjectShell::CallXScript(xScriptContext, pDlg->GetScriptURL(), args, ret, + outIndex, outArgs); + pDlg->disposeOnce(); + }); + pDlg->LoadLastUsedMacro(); + } + rReq.Done(); + } + break; #endif // HAVE_FEATURE_SCRIPTING case SID_OFFICE_CHECK_PLZ: @@ -2015,6 +2065,7 @@ void SfxApplication::OfaState_Impl(SfxItemSet &rSet) rSet.DisableItem(SID_MACROORGANIZER); rSet.DisableItem(SID_SCRIPTORGANIZER); rSet.DisableItem(SID_BASICIDE_APPEAR); + rSet.DisableItem(SID_MACROMANAGER); } } diff --git a/sfx2/source/control/minfitem.cxx b/sfx2/source/control/minfitem.cxx index c4d0136590c9..7b5b2d62bc2a 100644 --- a/sfx2/source/control/minfitem.cxx +++ b/sfx2/source/control/minfitem.cxx @@ -33,13 +33,15 @@ SfxMacroInfoItem::SfxMacroInfoItem( OUString _aLibName, OUString _aModuleName, OUString _aMethodName, - OUString _aComment) : + OUString _aComment, + OUString _aLocationName) : SfxPoolItem(nWhichId, SfxItemType::SfxMacroInfoItemType), pBasicManager(pMgr), aLibName(std::move(_aLibName)), aModuleName(std::move(_aModuleName)), aMethodName(std::move(_aMethodName)), - aCommentText(std::move(_aComment)) + aCommentText(std::move(_aComment)), + aLocationName(std::move(_aLocationName)) { } diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist index e521a5ccb359..cf05e4de8eb8 100644 --- a/solenv/clang-format/excludelist +++ b/solenv/clang-format/excludelist @@ -237,8 +237,6 @@ basctl/source/inc/docsignature.hxx basctl/source/inc/localizationmgr.hxx basctl/source/inc/managelang.hxx basctl/source/inc/propbrw.hxx -basctl/source/inc/sbxitem.hxx -basctl/source/inc/scriptdocument.hxx basegfx/source/color/bcolormodifier.cxx basegfx/source/color/bcolortools.cxx basegfx/source/curve/b2dbeziertools.cxx @@ -4740,6 +4738,8 @@ include/avmedia/mediaitem.hxx include/avmedia/mediaplayer.hxx include/avmedia/mediatoolbox.hxx include/avmedia/mediawindow.hxx +include/basctl/sbxitem.hxx +include/basctl/scriptdocument.hxx include/basegfx/color/bcolor.hxx include/basegfx/color/bcolormodifier.hxx include/basegfx/curve/b2dbeziertools.hxx diff --git a/starmath/uiconfig/smath/menubar/menubar.xml b/starmath/uiconfig/smath/menubar/menubar.xml index 74b478aaf3b0..2c5aca7361bf 100644 --- a/starmath/uiconfig/smath/menubar/menubar.xml +++ b/starmath/uiconfig/smath/menubar/menubar.xml @@ -129,6 +129,8 @@ + + diff --git a/sw/uiconfig/sglobal/menubar/menubar.xml b/sw/uiconfig/sglobal/menubar/menubar.xml index dd3eb8c6bd12..04ea613b39fd 100644 --- a/sw/uiconfig/sglobal/menubar/menubar.xml +++ b/sw/uiconfig/sglobal/menubar/menubar.xml @@ -760,6 +760,8 @@ + + diff --git a/sw/uiconfig/sweb/menubar/menubar.xml b/sw/uiconfig/sweb/menubar/menubar.xml index 00c5cefefe15..d8379e4db851 100644 --- a/sw/uiconfig/sweb/menubar/menubar.xml +++ b/sw/uiconfig/sweb/menubar/menubar.xml @@ -624,6 +624,8 @@ + + diff --git a/sw/uiconfig/swform/menubar/menubar.xml b/sw/uiconfig/swform/menubar/menubar.xml index 6da6a923e662..c64bf29ce9c0 100644 --- a/sw/uiconfig/swform/menubar/menubar.xml +++ b/sw/uiconfig/swform/menubar/menubar.xml @@ -704,6 +704,8 @@ + + diff --git a/sw/uiconfig/swreport/menubar/menubar.xml b/sw/uiconfig/swreport/menubar/menubar.xml index 57b49e6b9d90..7fb861d383ae 100644 --- a/sw/uiconfig/swreport/menubar/menubar.xml +++ b/sw/uiconfig/swreport/menubar/menubar.xml @@ -658,6 +658,8 @@ + + diff --git a/sw/uiconfig/swriter/menubar/menubar.xml b/sw/uiconfig/swriter/menubar/menubar.xml index 04b9fb4e2c91..a277c2c061b2 100644 --- a/sw/uiconfig/swriter/menubar/menubar.xml +++ b/sw/uiconfig/swriter/menubar/menubar.xml @@ -802,6 +802,8 @@ + + diff --git a/sw/uiconfig/swxform/menubar/menubar.xml b/sw/uiconfig/swxform/menubar/menubar.xml index 393fbf4aec4a..0ee99fadebbc 100644 --- a/sw/uiconfig/swxform/menubar/menubar.xml +++ b/sw/uiconfig/swxform/menubar/menubar.xml @@ -750,6 +750,8 @@ + +