summaryrefslogtreecommitdiffstats
path: root/basctl/source/basicide
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /basctl/source/basicide
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--basctl/source/basicide/IDEComboBox.cxx529
-rw-r--r--basctl/source/basicide/ObjectCatalog.cxx85
-rw-r--r--basctl/source/basicide/basdoc.cxx90
-rw-r--r--basctl/source/basicide/basdoc.hxx67
-rw-r--r--basctl/source/basicide/basicmod.hxx37
-rw-r--r--basctl/source/basicide/basicrenderable.cxx221
-rw-r--r--basctl/source/basicide/basicrenderable.hxx66
-rw-r--r--basctl/source/basicide/baside2.cxx1603
-rw-r--r--basctl/source/basicide/baside2.hxx514
-rw-r--r--basctl/source/basicide/baside2b.cxx2922
-rw-r--r--basctl/source/basicide/baside3.cxx1383
-rw-r--r--basctl/source/basicide/basidectrlr.cxx113
-rw-r--r--basctl/source/basicide/basides1.cxx1407
-rw-r--r--basctl/source/basicide/basides2.cxx242
-rw-r--r--basctl/source/basicide/basides3.cxx150
-rw-r--r--basctl/source/basicide/basidesh.cxx952
-rw-r--r--basctl/source/basicide/basobj2.cxx440
-rw-r--r--basctl/source/basicide/basobj3.cxx466
-rw-r--r--basctl/source/basicide/bastype2.cxx864
-rw-r--r--basctl/source/basicide/bastype3.cxx440
-rw-r--r--basctl/source/basicide/bastypes.cxx781
-rw-r--r--basctl/source/basicide/breakpoint.cxx158
-rw-r--r--basctl/source/basicide/breakpoint.hxx79
-rw-r--r--basctl/source/basicide/brkdlg.cxx235
-rw-r--r--basctl/source/basicide/brkdlg.hxx57
-rw-r--r--basctl/source/basicide/doceventnotifier.cxx244
-rw-r--r--basctl/source/basicide/docsignature.cxx75
-rw-r--r--basctl/source/basicide/documentenumeration.cxx169
-rw-r--r--basctl/source/basicide/documentenumeration.hxx90
-rw-r--r--basctl/source/basicide/iderdll.cxx206
-rw-r--r--basctl/source/basicide/iderdll2.hxx67
-rw-r--r--basctl/source/basicide/layout.cxx430
-rw-r--r--basctl/source/basicide/linenumberwindow.cxx126
-rw-r--r--basctl/source/basicide/linenumberwindow.hxx46
-rw-r--r--basctl/source/basicide/localizationmgr.cxx1129
-rw-r--r--basctl/source/basicide/macrodlg.cxx883
-rw-r--r--basctl/source/basicide/macrodlg.hxx108
-rw-r--r--basctl/source/basicide/moduldl2.cxx1357
-rw-r--r--basctl/source/basicide/moduldlg.cxx1033
-rw-r--r--basctl/source/basicide/moduldlg.hxx222
-rw-r--r--basctl/source/basicide/sbxitem.cxx76
-rw-r--r--basctl/source/basicide/scriptdocument.cxx1505
-rw-r--r--basctl/source/basicide/textwindowpeer.cxx71
-rw-r--r--basctl/source/basicide/textwindowpeer.hxx37
-rw-r--r--basctl/source/basicide/uiobject.cxx51
-rw-r--r--basctl/source/basicide/uiobject.hxx35
-rw-r--r--basctl/source/basicide/unomodel.cxx132
-rw-r--r--basctl/source/basicide/unomodel.hxx60
48 files changed, 22053 insertions, 0 deletions
diff --git a/basctl/source/basicide/IDEComboBox.cxx b/basctl/source/basicide/IDEComboBox.cxx
new file mode 100644
index 000000000..423e5c5d1
--- /dev/null
+++ b/basctl/source/basicide/IDEComboBox.cxx
@@ -0,0 +1,529 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <strings.hrc>
+#include <basidesh.hxx>
+#include <basobj.hxx>
+#include <IDEComboBox.hxx>
+#include <iderdll.hxx>
+#include <iderid.hxx>
+#include <localizationmgr.hxx>
+#include <managelang.hxx>
+
+#include <sfx2/dispatch.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <svtools/langtab.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/event.hxx>
+
+namespace basctl
+{
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+/*! Macro for implementation two methods for LibBoxControl Class
+ *
+ * @code
+ * SfxToolBoxControl* LibBoxControl::CreateImpl(sal_uInt16 nSlotId, sal_uInt16 nId, ToolBox& rTbx)
+ * {
+ * return new LibBoxControl(nSlotId, nId, rTbx);
+ * }
+ *
+ * void LibBoxControl::RegisterControl(sal_uInt16 nSlotId, SfxModule* pMod)
+ * {
+ * SfxToolBoxControl::RegisterToolBoxControl(
+ * pMod, SfxTbxCtrlFactory(* LibBoxControl::CreateImpl, typeid(nItemClass), nSlotId));
+ * }
+ * @endcode
+ * @see Macro SFX_DECL_TOOLBOX_CONTROL
+ */
+SFX_IMPL_TOOLBOX_CONTROL(LibBoxControl, SfxStringItem);
+
+LibBoxControl::LibBoxControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx)
+ : SfxToolBoxControl(nSlotId, nId, rTbx)
+{
+}
+
+void LibBoxControl::StateChangedAtToolBoxControl(sal_uInt16, SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ LibBox* pBox = static_cast<LibBox*>(GetToolBox().GetItemWindow(GetId()));
+
+ DBG_ASSERT(pBox, "Box not found");
+ if (!pBox)
+ return;
+
+ if (eState != SfxItemState::DEFAULT)
+ pBox->set_sensitive(false);
+ else
+ {
+ pBox->set_sensitive(true);
+ pBox->Update(dynamic_cast<SfxStringItem const*>(pState));
+ }
+}
+
+VclPtr<InterimItemWindow> LibBoxControl::CreateItemWindow(vcl::Window* pParent)
+{
+ return VclPtr<LibBox>::Create(pParent);
+}
+
+DocListenerBox::DocListenerBox(vcl::Window* pParent)
+ : InterimItemWindow(pParent, "modules/BasicIDE/ui/combobox.ui", "ComboBox")
+ , m_xWidget(m_xBuilder->weld_combo_box("combobox"))
+ , maNotifier(*this)
+{
+ InitControlBase(m_xWidget.get());
+
+ m_xWidget->connect_changed(LINK(this, DocListenerBox, SelectHdl));
+ m_xWidget->connect_key_press(LINK(this, DocListenerBox, KeyInputHdl));
+}
+
+void DocListenerBox::set_sensitive(bool bSensitive)
+{
+ Enable(bSensitive);
+ m_xWidget->set_sensitive(bSensitive);
+}
+
+IMPL_LINK(DocListenerBox, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return HandleKeyInput(rKEvt);
+}
+
+bool DocListenerBox::HandleKeyInput(const KeyEvent& rKEvt) { return ChildKeyInput(rKEvt); }
+
+IMPL_LINK_NOARG(DocListenerBox, SelectHdl, weld::ComboBox&, void) { Select(); }
+
+DocListenerBox::~DocListenerBox() { disposeOnce(); }
+
+void DocListenerBox::dispose()
+{
+ maNotifier.dispose();
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
+}
+
+/// Only calls FillBox(). Parameter is not used.
+void DocListenerBox::onDocumentCreated(const ScriptDocument& /*_rDoc*/) { FillBox(); }
+
+/// Only calls FillBox(). Parameter is not used.
+void DocListenerBox::onDocumentOpened(const ScriptDocument& /*_rDoc*/) { FillBox(); }
+
+/// Only calls FillBox(). Parameter is not used.
+void DocListenerBox::onDocumentSaveAsDone(const ScriptDocument& /*_rDoc*/) { FillBox(); }
+
+/// Only calls FillBox(). Parameter is not used.
+void DocListenerBox::onDocumentClosed(const ScriptDocument& /*_rDoc*/) { FillBox(); }
+
+/// Not interested in. Do nothing.
+void DocListenerBox::onDocumentSave(const ScriptDocument& /*_rDoc*/) {}
+
+/// Not interested in. Do nothing.
+void DocListenerBox::onDocumentSaveDone(const ScriptDocument& /*_rDoc*/) {}
+
+/// Not interested in. Do nothing.
+void DocListenerBox::onDocumentSaveAs(const ScriptDocument& /*_rDoc*/) {}
+
+/// Not interested in. Do nothing.
+void DocListenerBox::onDocumentTitleChanged(const ScriptDocument& /*_rDoc*/) {}
+
+/// Not interested in. Do nothing.
+void DocListenerBox::onDocumentModeChanged(const ScriptDocument& /*_rDoc*/) {}
+
+LibBox::LibBox(vcl::Window* pParent)
+ : DocListenerBox(pParent)
+{
+ FillBox();
+ mbIgnoreSelect = true; // do not yet transfer select of 0
+ mbFillBox = true;
+ m_xWidget->set_active(0);
+ maCurrentText = m_xWidget->get_text(0);
+ mbIgnoreSelect = false;
+
+ m_xWidget->connect_focus_in(LINK(this, LibBox, FocusInHdl));
+ m_xWidget->connect_focus_out(LINK(this, LibBox, FocusOutHdl));
+
+ SetSizePixel(m_xWidget->get_preferred_size());
+}
+
+LibBox::~LibBox() { disposeOnce(); }
+
+void LibBox::dispose()
+{
+ ClearBox();
+ DocListenerBox::dispose();
+}
+
+void LibBox::Update(const SfxStringItem* pItem)
+{
+ // if ( !pItem || !pItem->GetValue().Len() )
+ FillBox();
+
+ if (pItem)
+ {
+ maCurrentText = pItem->GetValue();
+ if (maCurrentText.isEmpty())
+ maCurrentText = IDEResId(RID_STR_ALL);
+ }
+
+ if (m_xWidget->get_active_text() != maCurrentText)
+ m_xWidget->set_active_text(maCurrentText);
+}
+
+void LibBox::ReleaseFocus()
+{
+ SfxViewShell* pCurSh = SfxViewShell::Current();
+ DBG_ASSERT(pCurSh, "Current ViewShell not found!");
+
+ if (!pCurSh)
+ return;
+
+ vcl::Window* pShellWin = pCurSh->GetWindow();
+ if (pShellWin)
+ {
+ pShellWin->GrabFocus();
+ return;
+ }
+
+ weld::Window* pWin = Application::GetDefDialogParent();
+ if (!pWin)
+ return;
+ pWin->grab_focus();
+}
+
+void LibBox::FillBox()
+{
+ m_xWidget->freeze();
+ mbIgnoreSelect = true;
+
+ maCurrentText = m_xWidget->get_active_text();
+
+ ClearBox();
+
+ // create list box entries
+ LibEntry* pEntry = new LibEntry(ScriptDocument::getApplicationScriptDocument(),
+ LIBRARY_LOCATION_UNKNOWN, OUString());
+ OUString sId(weld::toId(pEntry));
+ m_xWidget->append(sId, IDEResId(RID_STR_ALL));
+
+ InsertEntries(ScriptDocument::getApplicationScriptDocument(), LIBRARY_LOCATION_USER);
+ InsertEntries(ScriptDocument::getApplicationScriptDocument(), LIBRARY_LOCATION_SHARE);
+
+ ScriptDocuments aDocuments(
+ ScriptDocument::getAllScriptDocuments(ScriptDocument::DocumentsSorted));
+ for (auto const& doc : aDocuments)
+ {
+ InsertEntries(doc, LIBRARY_LOCATION_DOCUMENT);
+ }
+
+ m_xWidget->thaw();
+
+ int nIndex = m_xWidget->find_text(maCurrentText);
+ if (nIndex != -1)
+ m_xWidget->set_active(nIndex);
+ else
+ m_xWidget->set_active(0);
+ maCurrentText = m_xWidget->get_active_text();
+ mbIgnoreSelect = false;
+}
+
+void LibBox::InsertEntries(const ScriptDocument& rDocument, LibraryLocation eLocation)
+{
+ // get a sorted list of library names
+ Sequence<OUString> aLibNames = rDocument.getLibraryNames();
+ sal_Int32 nLibCount = aLibNames.getLength();
+ const OUString* pLibNames = aLibNames.getConstArray();
+
+ for (sal_Int32 i = 0; i < nLibCount; ++i)
+ {
+ OUString aLibName = pLibNames[i];
+ if (eLocation == rDocument.getLibraryLocation(aLibName))
+ {
+ OUString aName(rDocument.getTitle(eLocation));
+ OUString aEntryText(CreateMgrAndLibStr(aName, aLibName));
+ LibEntry* pEntry = new LibEntry(rDocument, eLocation, aLibName);
+ m_xWidget->append(weld::toId(pEntry), aEntryText);
+ }
+ }
+}
+
+bool LibBox::HandleKeyInput(const KeyEvent& rKEvt)
+{
+ bool bDone = false;
+
+ sal_uInt16 nKeyCode = rKEvt.GetKeyCode().GetCode();
+ switch (nKeyCode)
+ {
+ case KEY_RETURN:
+ {
+ NotifyIDE();
+ bDone = true;
+ }
+ break;
+ case KEY_ESCAPE:
+ {
+ m_xWidget->set_active_text(maCurrentText);
+ ReleaseFocus();
+ bDone = true;
+ }
+ break;
+ }
+
+ return bDone || DocListenerBox::HandleKeyInput(rKEvt);
+}
+
+IMPL_LINK_NOARG(LibBox, FocusInHdl, weld::Widget&, void)
+{
+ if (mbFillBox)
+ {
+ FillBox();
+ mbFillBox = false;
+ }
+}
+
+IMPL_LINK_NOARG(LibBox, FocusOutHdl, weld::Widget&, void)
+{
+ // comboboxes can be comprised of multiple widgets, ensure all have lost focus
+ if (m_xWidget && !m_xWidget->has_focus())
+ mbFillBox = true;
+}
+
+void LibBox::Select()
+{
+ if (m_xWidget->changed_by_direct_pick())
+ {
+ if (!mbIgnoreSelect)
+ NotifyIDE();
+ else
+ m_xWidget->set_active_text(maCurrentText); // (Select after Escape)
+ }
+}
+
+void LibBox::NotifyIDE()
+{
+ LibEntry* pEntry = weld::fromId<LibEntry*>(m_xWidget->get_active_id());
+ if (pEntry)
+ {
+ const ScriptDocument& aDocument(pEntry->GetDocument());
+ SfxUnoAnyItem aDocumentItem(SID_BASICIDE_ARG_DOCUMENT_MODEL,
+ uno::Any(aDocument.getDocumentOrNull()));
+ const OUString& aLibName = pEntry->GetLibName();
+ SfxStringItem aLibNameItem(SID_BASICIDE_ARG_LIBNAME, aLibName);
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ pDispatcher->ExecuteList(SID_BASICIDE_LIBSELECTED, SfxCallMode::SYNCHRON,
+ { &aDocumentItem, &aLibNameItem });
+ }
+ ReleaseFocus();
+}
+
+void LibBox::ClearBox()
+{
+ sal_Int32 nCount = m_xWidget->get_count();
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ LibEntry* pEntry = weld::fromId<LibEntry*>(m_xWidget->get_id(i));
+ delete pEntry;
+ }
+ m_xWidget->clear();
+}
+
+// class LanguageBoxControl ----------------------------------------------
+
+/*! Macro for implementation two methods for LanguageBoxControl Class
+ *
+ * @code
+ * SfxToolBoxControl* LanguageBoxControl::CreateImpl(sal_uInt16 nSlotId, sal_uInt16 nId, ToolBox& rTbx)
+ * {
+ * return new LanguageBoxControl(nSlotId, nId, rTbx);
+ * }
+ *
+ * void LanguageBoxControl::RegisterControl(sal_uInt16 nSlotId, SfxModule* pMod)
+ * {
+ * SfxToolBoxControl::RegisterToolBoxControl(
+ * pMod, SfxTbxCtrlFactory(* LanguageBoxControl::CreateImpl, typeid(nItemClass), nSlotId));
+ * }
+ * @endcode
+ * @see Macro SFX_DECL_TOOLBOX_CONTROL
+ */
+SFX_IMPL_TOOLBOX_CONTROL(LanguageBoxControl, SfxStringItem);
+
+LanguageBoxControl::LanguageBoxControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx)
+ : SfxToolBoxControl(nSlotId, nId, rTbx)
+{
+}
+
+void LanguageBoxControl::StateChangedAtToolBoxControl(sal_uInt16, SfxItemState eState,
+ const SfxPoolItem* pItem)
+{
+ if (LanguageBox* pBox = static_cast<LanguageBox*>(GetToolBox().GetItemWindow(GetId())))
+ {
+ if (eState != SfxItemState::DEFAULT)
+ pBox->set_sensitive(false);
+ else
+ {
+ pBox->set_sensitive(true);
+ pBox->Update(dynamic_cast<SfxStringItem const*>(pItem));
+ }
+ }
+}
+
+VclPtr<InterimItemWindow> LanguageBoxControl::CreateItemWindow(vcl::Window* pParent)
+{
+ return VclPtr<LanguageBox>::Create(pParent);
+}
+
+// class basctl::LanguageBox -----------------------------------------------
+LanguageBox::LanguageBox(vcl::Window* pParent)
+ : DocListenerBox(pParent)
+ , msNotLocalizedStr(IDEResId(RID_STR_TRANSLATION_NOTLOCALIZED))
+ , msDefaultLanguageStr(IDEResId(RID_STR_TRANSLATION_DEFAULT))
+ , mbIgnoreSelect(false)
+{
+ FillBox();
+
+ SetSizePixel(m_xWidget->get_preferred_size());
+}
+
+LanguageBox::~LanguageBox() { disposeOnce(); }
+
+void LanguageBox::dispose()
+{
+ ClearBox();
+ DocListenerBox::dispose();
+}
+
+void LanguageBox::FillBox()
+{
+ m_xWidget->freeze();
+ mbIgnoreSelect = true;
+ msCurrentText = m_xWidget->get_active_text();
+ ClearBox();
+
+ sal_Int32 nSelPos = -1;
+
+ std::shared_ptr<LocalizationMgr> pCurMgr(GetShell()->GetCurLocalizationMgr());
+ if (pCurMgr->isLibraryLocalized())
+ {
+ set_sensitive(true);
+ Locale aDefaultLocale = pCurMgr->getStringResourceManager()->getDefaultLocale();
+ Locale aCurrentLocale = pCurMgr->getStringResourceManager()->getCurrentLocale();
+ Sequence<Locale> aLocaleSeq = pCurMgr->getStringResourceManager()->getLocales();
+ const Locale* pLocale = aLocaleSeq.getConstArray();
+ sal_Int32 i, nCount = aLocaleSeq.getLength();
+ for (i = 0; i < nCount; ++i)
+ {
+ bool bIsDefault = localesAreEqual(aDefaultLocale, pLocale[i]);
+ bool bIsCurrent = localesAreEqual(aCurrentLocale, pLocale[i]);
+ LanguageType eLangType = LanguageTag::convertToLanguageType(pLocale[i]);
+ OUString sLanguage = SvtLanguageTable::GetLanguageString(eLangType);
+ if (bIsDefault)
+ {
+ sLanguage += " " + msDefaultLanguageStr;
+ }
+ LanguageEntry* pEntry = new LanguageEntry(pLocale[i], bIsDefault);
+ OUString sId(weld::toId(pEntry));
+ m_xWidget->append(sId, sLanguage);
+
+ if (bIsCurrent)
+ nSelPos = i;
+ }
+
+ if (nSelPos != -1)
+ msCurrentText = m_xWidget->get_text(nSelPos);
+ }
+ else
+ {
+ m_xWidget->append_text(msNotLocalizedStr);
+ nSelPos = 0;
+ set_sensitive(false);
+ }
+
+ m_xWidget->thaw();
+ m_xWidget->set_active(nSelPos);
+ mbIgnoreSelect = false;
+}
+
+void LanguageBox::ClearBox()
+{
+ sal_Int32 nCount = m_xWidget->get_count();
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ LanguageEntry* pEntry = weld::fromId<LanguageEntry*>(m_xWidget->get_id(i));
+ delete pEntry;
+ }
+ m_xWidget->clear();
+}
+
+void LanguageBox::SetLanguage()
+{
+ LanguageEntry* pEntry = weld::fromId<LanguageEntry*>(m_xWidget->get_active_id());
+ if (pEntry)
+ GetShell()->GetCurLocalizationMgr()->handleSetCurrentLocale(pEntry->m_aLocale);
+}
+
+void LanguageBox::Select()
+{
+ if (!mbIgnoreSelect)
+ SetLanguage();
+ else
+ m_xWidget->set_active_text(msCurrentText); // Select after Escape
+}
+
+bool LanguageBox::HandleKeyInput(const KeyEvent& rKEvt)
+{
+ bool bDone = false;
+
+ sal_uInt16 nKeyCode = rKEvt.GetKeyCode().GetCode();
+ switch (nKeyCode)
+ {
+ case KEY_RETURN:
+ {
+ SetLanguage();
+ bDone = true;
+ }
+ break;
+ case KEY_ESCAPE:
+ {
+ m_xWidget->set_active_text(msCurrentText);
+ bDone = true;
+ }
+ break;
+ }
+
+ return bDone || DocListenerBox::HandleKeyInput(rKEvt);
+}
+
+void LanguageBox::Update(const SfxStringItem* pItem)
+{
+ FillBox();
+
+ if (pItem && !pItem->GetValue().isEmpty())
+ {
+ msCurrentText = pItem->GetValue();
+ if (m_xWidget->get_active_text() != msCurrentText)
+ m_xWidget->set_active_text(msCurrentText);
+ }
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/ObjectCatalog.cxx b/basctl/source/basicide/ObjectCatalog.cxx
new file mode 100644
index 000000000..13069ed46
--- /dev/null
+++ b/basctl/source/basicide/ObjectCatalog.cxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <strings.hrc>
+#include <iderid.hxx>
+
+#include <ObjectCatalog.hxx>
+#include <helpids.h>
+
+#include <vcl/taskpanelist.hxx>
+
+namespace basctl
+{
+ObjectCatalog::ObjectCatalog(vcl::Window* pParent)
+ : DockingWindow(pParent, "modules/BasicIDE/ui/dockingorganizer.ui", "DockingOrganizer")
+{
+ m_xTitle = m_xBuilder->weld_label("title");
+ m_xTree.reset(new SbTreeListBox(m_xBuilder->weld_tree_view("libraries"), GetFrameWeld()));
+
+ SetHelpId("basctl:FloatingWindow:RID_BASICIDE_OBJCAT");
+ SetText(IDEResId(RID_BASICIDE_OBJCAT));
+
+ // title
+ m_xTitle->set_label(IDEResId(RID_BASICIDE_OBJCAT));
+
+ // tree list
+ weld::TreeView& rWidget = m_xTree->get_widget();
+
+ rWidget.set_help_id(HID_BASICIDE_OBJECTCAT);
+ m_xTree->ScanAllEntries();
+ rWidget.grab_focus();
+
+ // make object catalog keyboard accessible
+ GetParent()->GetSystemWindow()->GetTaskPaneList()->AddWindow(this);
+}
+
+ObjectCatalog::~ObjectCatalog() { disposeOnce(); }
+
+void ObjectCatalog::dispose()
+{
+ GetParent()->GetSystemWindow()->GetTaskPaneList()->RemoveWindow(this);
+ m_xTitle.reset();
+ m_xTree.reset();
+ DockingWindow::dispose();
+}
+
+// ToggleFloatingMode() -- called by DockingWindow when IsFloatingMode() changes
+void ObjectCatalog::ToggleFloatingMode()
+{
+ // base class version
+ DockingWindow::ToggleFloatingMode();
+
+ bool const bFloating = IsFloatingMode();
+ // tdf#152154: m_xTitle will be null during disposing
+ if (m_xTitle)
+ m_xTitle->set_visible(!bFloating);
+}
+
+void ObjectCatalog::SetCurrentEntry(BaseWindow* pCurWin)
+{
+ EntryDescriptor aDescriptor;
+ if (pCurWin)
+ aDescriptor = pCurWin->CreateEntryDescriptor();
+ m_xTree->SetCurrentEntry(aDescriptor);
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/basdoc.cxx b/basctl/source/basicide/basdoc.cxx
new file mode 100644
index 000000000..83a3f1781
--- /dev/null
+++ b/basctl/source/basicide/basdoc.cxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sfx2/app.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/objface.hxx>
+
+#include "unomodel.hxx"
+
+#include "basdoc.hxx"
+#define ShellClass_basctl_DocShell
+#include <basslots.hxx>
+#include <sfx2/sfxmodelfactory.hxx>
+#include <svl/itemset.hxx>
+#include <svx/svxids.hrc>
+#include <tools/globname.hxx>
+#include <tools/debug.hxx>
+
+namespace basctl
+{
+
+
+SFX_IMPL_OBJECTFACTORY( DocShell, SvGlobalName(), "sbasic" )
+
+SFX_IMPL_SUPERCLASS_INTERFACE(basctl_DocShell, SfxObjectShell)
+
+void basctl_DocShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterStatusBar(StatusBarId::BasicIdeStatusBar);
+}
+
+DocShell::DocShell()
+ :SfxObjectShell( SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS | SfxModelFlags::DISABLE_DOCUMENT_RECOVERY )
+{
+ SetPool( &SfxGetpApp()->GetPool() );
+ SetBaseModel( new SIDEModel(this) );
+}
+
+DocShell::~DocShell()
+{
+ pPrinter.disposeAndClear();
+}
+
+SfxPrinter* DocShell::GetPrinter( bool bCreate )
+{
+ if ( !pPrinter && bCreate )
+ pPrinter.disposeAndReset(VclPtr<SfxPrinter>::Create(std::make_unique<SfxItemSetFixed
+ <SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN>>(GetPool())
+ ));
+
+ return pPrinter.get();
+}
+
+void DocShell::SetPrinter( SfxPrinter* pPr )
+{
+ if (pPr != pPrinter.get())
+ {
+ pPrinter.disposeAndReset(pPr);
+ }
+}
+
+void DocShell::FillClass( SvGlobalName*, SotClipboardFormatId*, OUString*, sal_Int32, bool bTemplate) const
+{
+ DBG_ASSERT( !bTemplate, "No template for Basic" );
+}
+
+void DocShell::Draw( OutputDevice *, const JobSetup &, sal_uInt16 )
+{}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/basdoc.hxx b/basctl/source/basicide/basdoc.hxx
new file mode 100644
index 000000000..d5b3aabcf
--- /dev/null
+++ b/basctl/source/basicide/basdoc.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/docfac.hxx>
+#include <svx/ifaceids.hxx>
+#include <vcl/vclptr.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/objsh.hxx>
+
+namespace basctl
+{
+
+class DocShell: public SfxObjectShell
+{
+ ScopedVclPtr<SfxPrinter> pPrinter;
+
+protected:
+ virtual void Draw( OutputDevice *, const JobSetup & rSetup,
+ sal_uInt16 nAspect ) override;
+ virtual void FillClass( SvGlobalName * pClassName,
+ SotClipboardFormatId * pFormat,
+ OUString * pFullTypeName,
+ sal_Int32 nVersion,
+ bool bTemplate = false ) const override;
+
+public:
+
+ SFX_DECL_OBJECTFACTORY();
+ SFX_DECL_INTERFACE( SVX_INTERFACE_BASIDE_DOCSH )
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ DocShell();
+ virtual ~DocShell() override;
+
+ SfxPrinter* GetPrinter( bool bCreate );
+ void SetPrinter( SfxPrinter* pPrinter );
+};
+
+} // namespace basctl
+
+// This typedef helps baside.sdi,
+// because I don't know how to use nested names in it.
+typedef basctl::DocShell basctl_DocShell;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/basicmod.hxx b/basctl/source/basicide/basicmod.hxx
new file mode 100644
index 000000000..7a0175183
--- /dev/null
+++ b/basctl/source/basicide/basicmod.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/module.hxx>
+
+namespace basctl
+{
+class Module : public SfxModule
+{
+public:
+ Module(const OString& rResName, SfxObjectFactory* pObjFact)
+ : SfxModule(rResName, { pObjFact })
+ {
+ }
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/basicrenderable.cxx b/basctl/source/basicide/basicrenderable.cxx
new file mode 100644
index 000000000..79e381399
--- /dev/null
+++ b/basctl/source/basicide/basicrenderable.cxx
@@ -0,0 +1,221 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "basicrenderable.hxx"
+#include <bastypes.hxx>
+#include <iderid.hxx>
+#include <strings.hrc>
+
+#include <toolkit/awt/vclxdevice.hxx>
+#include <tools/multisel.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/propertysequence.hxx>
+
+namespace basctl
+{
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+
+Renderable::Renderable (BaseWindow* pWin)
+: cppu::WeakComponentImplHelper< css::view::XRenderable >( maMutex )
+, mpWindow( pWin )
+{
+ m_aUIProperties.resize( 4 );
+
+ // show Subgroup for print range
+ vcl::PrinterOptionsHelper::UIControlOptions aPrintRangeOpt;
+ aPrintRangeOpt.maGroupHint = "PrintRange" ;
+ aPrintRangeOpt.mbInternalOnly = true;
+
+ m_aUIProperties[0].Value = setSubgroupControlOpt("printrange",
+ IDEResId( RID_STR_PRINTDLG_PAGES ), OUString(), aPrintRangeOpt);
+
+ // create a choice for the range to print
+ OUString aPrintContentName( "PrintContent" );
+ const Sequence<OUString> aChoices{IDEResId(RID_STR_PRINTDLG_PRINTALLPAGES),
+ IDEResId(RID_STR_PRINTDLG_PRINTPAGES)};
+ const Sequence<OUString> aHelpIds{".HelpID:vcl:PrintDialog:PrintContent:RadioButton:0",
+ ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:1"};
+ const Sequence<OUString> aWidgetIds{"rbAllPages",
+ "rbRangePages"};
+ m_aUIProperties[1].Value = setChoiceRadiosControlOpt(aWidgetIds, OUString(),
+ aHelpIds, aPrintContentName,
+ aChoices, 0);
+
+ // create an Edit dependent on "Pages" selected
+ vcl::PrinterOptionsHelper::UIControlOptions aPageRangeOpt(aPrintContentName, 1, true);
+ m_aUIProperties[2].Value = setEditControlOpt("pagerange", OUString(),
+ OUString(), "PageRange",
+ OUString(), aPageRangeOpt);
+
+ vcl::PrinterOptionsHelper::UIControlOptions aEvenOddOpt(aPrintContentName, 0, true);
+ m_aUIProperties[3].Value = setChoiceListControlOpt("evenoddbox",
+ OUString(),
+ uno::Sequence<OUString>(),
+ "EvenOdd",
+ uno::Sequence<OUString>(),
+ 0,
+ uno::Sequence< sal_Bool >(),
+ aEvenOddOpt);
+}
+
+Renderable::~Renderable()
+{
+}
+
+VclPtr< Printer > Renderable::getPrinter() const
+{
+ VclPtr< Printer > pPrinter;
+ Any aValue( getValue( "RenderDevice" ) );
+ Reference<awt::XDevice> xRenderDevice;
+
+ if( aValue >>= xRenderDevice )
+ {
+ VCLXDevice* pDevice = comphelper::getFromUnoTunnel<VCLXDevice>(xRenderDevice);
+ VclPtr< OutputDevice > pOut = pDevice ? pDevice->GetOutputDevice() : VclPtr< OutputDevice >();
+ pPrinter = dynamic_cast<Printer*>(pOut.get());
+ }
+ return pPrinter;
+}
+
+bool Renderable::isPrintOddPages() const
+{
+ sal_Int64 nContent = getIntValue( "PrintContent", -1 );
+ return nContent != 2;
+}
+
+bool Renderable::isPrintEvenPages() const
+{
+ sal_Int64 nContent = getIntValue( "PrintContent", -1 );
+ return nContent != 3;
+}
+
+sal_Int32 SAL_CALL Renderable::getRendererCount (
+ const Any&, const Sequence<beans::PropertyValue >& i_xOptions
+ )
+{
+ processProperties( i_xOptions );
+
+ maValidPages.clear();
+
+ sal_Int32 nCount = 0;
+ if( mpWindow )
+ {
+ VclPtr<Printer> pPrinter = getPrinter();
+ if (!pPrinter)
+ throw lang::IllegalArgumentException("no printer", static_cast<cppu::OWeakObject*>(this), -1);
+
+ nCount = mpWindow->countPages( pPrinter );
+
+ for (sal_Int32 nPage = 1; nPage <= nCount; nPage++)
+ {
+ if ( (isPrintEvenPages() && isOnEvenPage( nPage ))
+ || (isPrintOddPages() && !isOnEvenPage( nPage )) )
+ {
+ maValidPages.push_back( nPage-1 );
+ }
+ }
+
+ sal_Int64 nContent = getIntValue( "PrintContent", -1 );
+ sal_Int64 nEOContent = getIntValue ("EvenOdd", -1);
+ if( nContent == 1 )
+ {
+ OUString aPageRange( getStringValue( "PageRange" ) );
+ if( !aPageRange.isEmpty() )
+ {
+ StringRangeEnumerator aRangeEnum( aPageRange, 0, nCount-1 );
+ sal_Int32 nSelCount = aRangeEnum.size();
+ if( nSelCount >= 0 )
+ nCount = nSelCount;
+ }
+ }
+ else if ( nEOContent == 1 || nEOContent == 2 ) // even/odd pages
+ return static_cast<sal_Int32>( maValidPages.size() );
+ }
+
+ return nCount;
+}
+
+Sequence<beans::PropertyValue> SAL_CALL Renderable::getRenderer (
+ sal_Int32, const Any&, const Sequence<beans::PropertyValue>& i_xOptions
+ )
+{
+ processProperties( i_xOptions );
+
+ Sequence< beans::PropertyValue > aVals;
+ // insert page size here
+ VclPtr<Printer> pPrinter = getPrinter();
+ // no renderdevice is legal; the first call is to get our print ui options
+ if( pPrinter )
+ {
+ Size aPageSize( pPrinter->PixelToLogic( pPrinter->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM ) ) );
+
+ awt::Size aSize;
+ aSize.Width = aPageSize.Width();
+ aSize.Height = aPageSize.Height();
+ aVals = ::comphelper::InitPropertySequence({
+ { "PageSize", Any(aSize) }
+ });
+ }
+
+ appendPrintUIOptions( aVals );
+
+ return aVals;
+}
+
+void SAL_CALL Renderable::render (
+ sal_Int32 nRenderer, const Any&,
+ const Sequence<beans::PropertyValue>& i_xOptions
+ )
+{
+ processProperties( i_xOptions );
+
+ if( !mpWindow )
+ return;
+
+ VclPtr<Printer> pPrinter = getPrinter();
+ if (!pPrinter)
+ throw lang::IllegalArgumentException("no printer", static_cast<cppu::OWeakObject*>(this), -1);
+
+ sal_Int64 nContent = getIntValue( "PrintContent", -1 );
+ if( nContent == 1 )
+ {
+ OUString aPageRange( getStringValue( "PageRange" ) );
+ if( !aPageRange.isEmpty() )
+ {
+ sal_Int32 nPageCount = mpWindow->countPages( pPrinter );
+ StringRangeEnumerator aRangeEnum( aPageRange, 0, nPageCount-1 );
+ StringRangeEnumerator::Iterator it = aRangeEnum.begin();
+ for( ; it != aRangeEnum.end() && nRenderer; --nRenderer )
+ ++it;
+
+ sal_Int32 nPage = ( it != aRangeEnum.end() ) ? *it : nRenderer;
+ mpWindow->printPage( nPage, pPrinter );
+ }
+ else
+ mpWindow->printPage( nRenderer, pPrinter );
+ }
+ else
+ mpWindow->printPage( maValidPages.at( nRenderer ), pPrinter );
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/basicrenderable.hxx b/basctl/source/basicide/basicrenderable.hxx
new file mode 100644
index 000000000..638749c64
--- /dev/null
+++ b/basctl/source/basicide/basicrenderable.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/view/XRenderable.hpp>
+#include <cppuhelper/compbase.hxx>
+
+#include <vcl/print.hxx>
+
+namespace basctl
+{
+
+class BaseWindow;
+
+class Renderable :
+ public cppu::WeakComponentImplHelper< css::view::XRenderable >,
+ public vcl::PrinterOptionsHelper
+{
+ VclPtr<BaseWindow> mpWindow;
+ osl::Mutex maMutex;
+ std::vector<sal_Int32> maValidPages;
+
+ VclPtr<Printer> getPrinter() const;
+ bool isPrintOddPages() const;
+ bool isPrintEvenPages() const;
+ static bool isOnEvenPage( sal_Int32 nPage ) { return nPage % 2 == 0; };
+public:
+ explicit Renderable (BaseWindow*);
+ virtual ~Renderable() override;
+
+ // XRenderable
+ virtual sal_Int32 SAL_CALL getRendererCount (
+ const css::uno::Any& aSelection,
+ const css::uno::Sequence<css::beans::PropertyValue >& xOptions) override;
+
+ virtual css::uno::Sequence<css::beans::PropertyValue> SAL_CALL getRenderer (
+ sal_Int32 nRenderer,
+ const css::uno::Any& rSelection,
+ const css::uno::Sequence<css::beans::PropertyValue>& rxOptions) override;
+
+ virtual void SAL_CALL render (
+ sal_Int32 nRenderer,
+ const css::uno::Any& rSelection,
+ const css::uno::Sequence<css::beans::PropertyValue>& rxOptions) override;
+
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/baside2.cxx b/basctl/source/basicide/baside2.cxx
new file mode 100644
index 000000000..f73c70ef7
--- /dev/null
+++ b/basctl/source/basicide/baside2.cxx
@@ -0,0 +1,1603 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "baside2.hxx"
+#include <baside3.hxx>
+#include <basobj.hxx>
+#include <basidesh.hxx>
+#include "brkdlg.hxx"
+#include <iderdll.hxx>
+#include <iderid.hxx>
+#include "moduldlg.hxx"
+#include <docsignature.hxx>
+#include <officecfg/Office/BasicIDE.hxx>
+
+#include <helpids.h>
+#include <strings.hrc>
+
+#include <basic/basmgr.hxx>
+#include <basic/basrdll.hxx>
+#include <basic/sbmeth.hxx>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/script/ModuleType.hpp>
+#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
+#include <comphelper/SetFlagContextHelper.hxx>
+#include <comphelper/string.hxx>
+#include <svl/srchdefs.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sot/exchange.hxx>
+#include <svl/eitem.hxx>
+#include <svl/srchitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/visitem.hxx>
+#include <svl/whiter.hxx>
+#include <svx/svxids.hrc>
+#include <tools/debug.hxx>
+#include <utility>
+#include <vcl/locktoplevels.hxx>
+#include <vcl/errinf.hxx>
+#include <vcl/event.hxx>
+#include <vcl/print.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/textview.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/xtextedt.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <cassert>
+#include <osl/diagnose.h>
+#include <officecfg/Office/Common.hxx>
+
+namespace basctl
+{
+
+namespace
+{
+
+namespace Print
+{
+ tools::Long const nLeftMargin = 1700;
+ tools::Long const nRightMargin = 900;
+ tools::Long const nTopMargin = 2000;
+ tools::Long const nBottomMargin = 1000;
+ tools::Long const nBorder = 300;
+}
+
+short const ValidWindow = 0x1234;
+
+// What (who) are OW and MTF? Compare to baside3.cxx where an
+// identically named variable, used in the same way, has the value
+// "*.*" on Windows, "*" otherwise. Is that what should be done here,
+// too?
+
+#if defined(OW) || defined(MTF)
+char const FilterMask_All[] = "*";
+#else
+constexpr OUStringLiteral FilterMask_All = u"*.*";
+#endif
+
+} // end anonymous namespace
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace utl;
+using namespace comphelper;
+
+namespace
+{
+
+void lcl_PrintHeader( Printer* pPrinter, sal_uInt16 nPages, sal_uInt16 nCurPage, const OUString& rTitle, bool bOutput )
+{
+ Size const aSz = pPrinter->GetOutputSize();
+
+ const Color aOldLineColor( pPrinter->GetLineColor() );
+ const Color aOldFillColor( pPrinter->GetFillColor() );
+ const vcl::Font aOldFont( pPrinter->GetFont() );
+
+ pPrinter->SetLineColor( COL_BLACK );
+ pPrinter->SetFillColor();
+
+ vcl::Font aFont( aOldFont );
+ aFont.SetWeight( WEIGHT_BOLD );
+ aFont.SetAlignment( ALIGN_BOTTOM );
+ pPrinter->SetFont( aFont );
+
+ tools::Long nFontHeight = pPrinter->GetTextHeight();
+
+ // 1st Border => line, 2+3 Border = free space
+ tools::Long nYTop = Print::nTopMargin - 3*Print::nBorder - nFontHeight;
+
+ tools::Long nXLeft = Print::nLeftMargin - Print::nBorder;
+ tools::Long nXRight = aSz.Width() - Print::nRightMargin + Print::nBorder;
+
+ if( bOutput )
+ pPrinter->DrawRect(tools::Rectangle(
+ Point(nXLeft, nYTop),
+ Size(nXRight - nXLeft, aSz.Height() - nYTop - Print::nBottomMargin + Print::nBorder)
+ ));
+
+
+ tools::Long nY = Print::nTopMargin - 2*Print::nBorder;
+ Point aPos(Print::nLeftMargin, nY);
+ if( bOutput )
+ pPrinter->DrawText( aPos, rTitle );
+ if ( nPages != 1 )
+ {
+ aFont.SetWeight( WEIGHT_NORMAL );
+ pPrinter->SetFont( aFont );
+ aPos.AdjustX(pPrinter->GetTextWidth( rTitle ) );
+
+ if( bOutput )
+ {
+ OUString aPageStr = " [" + IDEResId(RID_STR_PAGE) + " " + OUString::number( nCurPage ) + "]";
+ pPrinter->DrawText( aPos, aPageStr );
+ }
+ }
+
+ nY = Print::nTopMargin - Print::nBorder;
+
+ if( bOutput )
+ pPrinter->DrawLine( Point( nXLeft, nY ), Point( nXRight, nY ) );
+
+ pPrinter->SetFont( aOldFont );
+ pPrinter->SetFillColor( aOldFillColor );
+ pPrinter->SetLineColor( aOldLineColor );
+}
+
+void lcl_ConvertTabsToSpaces( OUString& rLine )
+{
+ if ( rLine.isEmpty() )
+ return;
+
+ OUStringBuffer aResult( rLine );
+ sal_Int32 nPos = 0;
+ sal_Int32 nMax = aResult.getLength();
+ while ( nPos < nMax )
+ {
+ if ( aResult[nPos] == '\t' )
+ {
+ // not 4 Blanks, but at 4 TabPos:
+ OUStringBuffer aBlanker;
+ string::padToLength(aBlanker, ( 4 - ( nPos % 4 ) ), ' ');
+ aResult.remove( nPos, 1 );
+ aResult.insert( nPos, aBlanker.makeStringAndClear() );
+ nMax = aResult.getLength();
+ }
+ ++nPos;
+ }
+ rLine = aResult.makeStringAndClear();
+}
+
+} // namespace
+
+ModulWindow::ModulWindow (ModulWindowLayout* pParent, ScriptDocument const& rDocument,
+ const OUString& aLibName, const OUString& aName, OUString aModule)
+ : BaseWindow(pParent, rDocument, aLibName, aName)
+ , m_rLayout(*pParent)
+ , m_nValid(ValidWindow)
+ , m_aXEditorWindow(VclPtr<ComplexEditorWindow>::Create(this))
+ , m_aModule(std::move(aModule))
+{
+ m_aXEditorWindow->Show();
+ SetBackground();
+}
+
+SbModuleRef const & ModulWindow::XModule()
+{
+ // ModuleWindows can now be created as a result of the
+ // modules getting created via the api. This is a result of an
+ // elementInserted event from the BasicLibrary container.
+ // However the SbModule is also created from a different listener to
+ // the same event ( in basmgr ) Therefore it is possible when we look
+ // for m_xModule it may not yet be available, here we keep trying to access
+ // the module until such time as it exists
+
+ if ( !m_xModule.is() )
+ {
+ BasicManager* pBasMgr = GetDocument().getBasicManager();
+ if ( pBasMgr )
+ {
+ StarBASIC* pBasic = pBasMgr->GetLib( GetLibName() );
+ if ( pBasic )
+ {
+ m_xBasic = pBasic;
+ m_xModule = pBasic->FindModule( GetName() );
+ }
+ }
+ }
+ return m_xModule;
+}
+
+ModulWindow::~ModulWindow()
+{
+ disposeOnce();
+}
+
+void ModulWindow::dispose()
+{
+ m_nValid = 0;
+ StarBASIC::Stop();
+ m_aXEditorWindow.disposeAndClear();
+ BaseWindow::dispose();
+}
+
+
+void ModulWindow::GetFocus()
+{
+ if (m_nValid != ValidWindow)
+ return;
+ m_aXEditorWindow->GetEdtWindow().GrabFocus();
+ // don't call basic calls because focus is somewhere else...
+}
+
+void ModulWindow::DoInit()
+{
+ if (GetVScrollBar())
+ GetVScrollBar()->Hide();
+ GetHScrollBar()->Show();
+ GetEditorWindow().InitScrollBars();
+}
+
+void ModulWindow::Paint(vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle&)
+{
+}
+
+void ModulWindow::Resize()
+{
+ m_aXEditorWindow->SetPosSizePixel( Point( 0, 0 ), GetOutputSizePixel() );
+}
+
+void ModulWindow::CheckCompileBasic()
+{
+ if ( !XModule().is() )
+ return;
+
+ // never compile while running!
+ bool const bRunning = StarBASIC::IsRunning();
+ bool const bModified = ( !m_xModule->IsCompiled() ||
+ ( GetEditEngine() && GetEditEngine()->IsModified() ) );
+
+ if ( bRunning || !bModified )
+ return;
+
+ bool bDone = false;
+
+ GetShell()->GetViewFrame()->GetWindow().EnterWait();
+
+ AssertValidEditEngine();
+ GetEditorWindow().SetSourceInBasic();
+
+ bool bWasModified = GetBasic()->IsModified();
+
+ {
+ // tdf#106529: only use strict compilation mode when compiling from the IDE
+ css::uno::ContextLayer layer(comphelper::NewFlagContext("BasicStrict"));
+ bDone = m_xModule->Compile();
+ }
+ if ( !bWasModified )
+ GetBasic()->SetModified(false);
+
+ if ( bDone )
+ {
+ GetBreakPoints().SetBreakPointsInBasic( m_xModule.get() );
+ }
+
+ GetShell()->GetViewFrame()->GetWindow().LeaveWait();
+
+ m_aStatus.bError = !bDone;
+ m_aStatus.bIsRunning = false;
+}
+
+void ModulWindow::BasicExecute()
+{
+ // #116444# check security settings before macro execution
+ ScriptDocument aDocument( GetDocument() );
+ bool bMacrosDisabled = officecfg::Office::Common::Security::Scripting::DisableMacrosExecution::get();
+ if (bMacrosDisabled || (aDocument.isDocument() && !aDocument.allowMacros()))
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(
+ Application::CreateMessageDialog(GetFrameWeld(), VclMessageType::Warning,
+ VclButtonsType::Ok, IDEResId(RID_STR_CANNOTRUNMACRO)));
+ xBox->run();
+ return;
+ }
+
+ CheckCompileBasic();
+
+ if ( !XModule().is() || !m_xModule->IsCompiled() || m_aStatus.bError )
+ return;
+
+ if ( GetBreakPoints().size() )
+ m_aStatus.nBasicFlags = m_aStatus.nBasicFlags | BasicDebugFlags::Break;
+
+ if ( !m_aStatus.bIsRunning )
+ {
+ DBG_ASSERT( m_xModule.is(), "No Module!" );
+ AddStatus( BASWIN_RUNNINGBASIC );
+ sal_uInt16 nStart, nEnd;
+ TextSelection aSel = GetEditView()->GetSelection();
+ // Init cursor to top
+ const sal_uInt32 nCurMethodStart = aSel.GetStart().GetPara() + 1;
+ SbMethod* pMethod = nullptr;
+ // first Macro, else blind "Main" (ExtSearch?)
+ for (sal_uInt32 nMacro = 0; nMacro < m_xModule->GetMethods()->Count(); nMacro++)
+ {
+ SbMethod* pM = static_cast<SbMethod*>(m_xModule->GetMethods()->Get(nMacro));
+ assert(pM && "Method?");
+ pM->GetLineRange( nStart, nEnd );
+ if ( nCurMethodStart >= nStart && nCurMethodStart <= nEnd )
+ {
+ // matched a method to the cursor position
+ pMethod = pM;
+ break;
+ }
+ }
+ if ( !pMethod )
+ {
+ // If not in a method then prompt the user
+ ChooseMacro(GetFrameWeld(), uno::Reference<frame::XModel>());
+ return;
+ }
+ pMethod->SetDebugFlags(m_aStatus.nBasicFlags);
+ BasicDLL::SetDebugMode(true);
+ RunMethod(pMethod);
+ BasicDLL::SetDebugMode(false);
+ // if cancelled during Interactive=false
+ BasicDLL::EnableBreak(true);
+ ClearStatus( BASWIN_RUNNINGBASIC );
+ }
+ else
+ m_aStatus.bIsRunning = false; // cancel of Reschedule()
+}
+
+void ModulWindow::CompileBasic()
+{
+ CheckCompileBasic();
+
+ XModule().is() && m_xModule->IsCompiled();
+}
+
+void ModulWindow::BasicRun()
+{
+ m_aStatus.nBasicFlags = BasicDebugFlags::NONE;
+ BasicExecute();
+}
+
+void ModulWindow::BasicStepOver()
+{
+ m_aStatus.nBasicFlags = BasicDebugFlags::StepInto | BasicDebugFlags::StepOver;
+ BasicExecute();
+}
+
+
+void ModulWindow::BasicStepInto()
+{
+ m_aStatus.nBasicFlags = BasicDebugFlags::StepInto;
+ BasicExecute();
+}
+
+void ModulWindow::BasicStepOut()
+{
+ m_aStatus.nBasicFlags = BasicDebugFlags::StepOut;
+ BasicExecute();
+}
+
+
+void ModulWindow::BasicStop()
+{
+ StarBASIC::Stop();
+ m_aStatus.bIsRunning = false;
+}
+
+void ModulWindow::LoadBasic()
+{
+ sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
+ FileDialogFlags::NONE, this->GetFrameWeld());
+ aDlg.SetContext(sfx2::FileDialogHelper::BasicImportSource);
+ Reference<XFilePicker3> xFP = aDlg.GetFilePicker();
+
+ xFP->appendFilter( "BASIC" , "*.bas" );
+ xFP->appendFilter( IDEResId(RID_STR_FILTER_ALLFILES), FilterMask_All );
+ xFP->setCurrentFilter( "BASIC" );
+
+ if( aDlg.Execute() != ERRCODE_NONE )
+ return;
+
+ Sequence< OUString > aPaths = xFP->getSelectedFiles();
+ SfxMedium aMedium( aPaths[0], StreamMode::READ | StreamMode::SHARE_DENYWRITE | StreamMode::NOCREATE );
+ SvStream* pStream = aMedium.GetInStream();
+ if ( pStream )
+ {
+ AssertValidEditEngine();
+ sal_uInt32 nLines = CalcLineCount( *pStream );
+ // nLines*4: ReadText/Formatting/Highlighting/Formatting
+ GetEditorWindow().CreateProgress( IDEResId(RID_STR_GENERATESOURCE), nLines*4 );
+ GetEditEngine()->SetUpdateMode( false );
+ // tdf#139196 - import macros using either default or utf-8 text encoding
+ pStream->StartReadingUnicodeText(RTL_TEXTENCODING_UTF8);
+ if (pStream->Tell() == 3)
+ pStream->SetStreamCharSet(RTL_TEXTENCODING_UTF8);
+ GetEditView()->Read( *pStream );
+ GetEditEngine()->SetUpdateMode( true );
+ GetEditorWindow().PaintImmediately();
+ GetEditorWindow().ForceSyntaxTimeout();
+ GetEditorWindow().DestroyProgress();
+ ErrCode nError = aMedium.GetError();
+ if ( nError )
+ ErrorHandler::HandleError( nError );
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_COULDNTREAD)));
+ xBox->run();
+ }
+}
+
+
+void ModulWindow::SaveBasicSource()
+{
+ sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD,
+ FileDialogFlags::NONE, this->GetFrameWeld());
+ aDlg.SetContext(sfx2::FileDialogHelper::BasicExportSource);
+ const Reference<XFilePicker3>& xFP = aDlg.GetFilePicker();
+
+ Reference< XFilePickerControlAccess > xFPControl(xFP, UNO_QUERY);
+ xFPControl->enableControl(ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, false);
+ Any aValue;
+ aValue <<= true;
+ xFPControl->setValue(ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0, aValue);
+
+ xFP->appendFilter( "BASIC", "*.bas" );
+ xFP->appendFilter( IDEResId(RID_STR_FILTER_ALLFILES), FilterMask_All );
+ xFP->setCurrentFilter( "BASIC" );
+
+ if( aDlg.Execute() != ERRCODE_NONE )
+ return;
+
+ Sequence< OUString > aPaths = xFP->getSelectedFiles();
+ SfxMedium aMedium( aPaths[0], StreamMode::WRITE | StreamMode::SHARE_DENYWRITE | StreamMode::TRUNC );
+ SvStream* pStream = aMedium.GetOutStream();
+ if ( pStream )
+ {
+ EnterWait();
+ AssertValidEditEngine();
+ // tdf#139196 - export macros using utf-8 including BOM
+ pStream->SetStreamCharSet(RTL_TEXTENCODING_UTF8);
+ pStream->WriteUChar(0xEF).WriteUChar(0xBB).WriteUChar(0xBF);
+ GetEditEngine()->Write( *pStream );
+ aMedium.Commit();
+ LeaveWait();
+ ErrCode nError = aMedium.GetError();
+ if ( nError )
+ ErrorHandler::HandleError( nError );
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_COULDNTWRITE)));
+ xErrorBox->run();
+ }
+}
+
+void ModulWindow::ImportDialog()
+{
+ const ScriptDocument& rDocument = GetDocument();
+ OUString aLibName = GetLibName();
+ implImportDialog(GetFrameWeld(), rDocument, aLibName);
+}
+
+void ModulWindow::ToggleBreakPoint( sal_uInt16 nLine )
+{
+ DBG_ASSERT( XModule().is(), "No Module!" );
+
+ if ( !XModule().is() )
+ return;
+
+ CheckCompileBasic();
+ if ( m_aStatus.bError )
+ {
+ return;
+ }
+
+ BreakPoint* pBrk = GetBreakPoints().FindBreakPoint( nLine );
+ if ( pBrk ) // remove
+ {
+ m_xModule->ClearBP( nLine );
+ GetBreakPoints().remove( pBrk );
+ }
+ else // create one
+ {
+ if ( m_xModule->SetBP( nLine ))
+ {
+ GetBreakPoints().InsertSorted( BreakPoint( nLine ) );
+ if ( StarBASIC::IsRunning() )
+ {
+ for (sal_uInt32 nMethod = 0; nMethod < m_xModule->GetMethods()->Count(); nMethod++)
+ {
+ SbMethod* pMethod
+ = static_cast<SbMethod*>(m_xModule->GetMethods()->Get(nMethod));
+ assert(pMethod && "Method not found! (NULL)");
+ pMethod->SetDebugFlags( pMethod->GetDebugFlags() | BasicDebugFlags::Break );
+ }
+ }
+ }
+ }
+}
+
+void ModulWindow::UpdateBreakPoint( const BreakPoint& rBrk )
+{
+ DBG_ASSERT( XModule().is(), "No Module!" );
+
+ if ( XModule().is() )
+ {
+ CheckCompileBasic();
+
+ if ( rBrk.bEnabled )
+ m_xModule->SetBP( rBrk.nLine );
+ else
+ m_xModule->ClearBP( rBrk.nLine );
+ }
+}
+
+
+void ModulWindow::BasicToggleBreakPoint()
+{
+ AssertValidEditEngine();
+
+ TextSelection aSel = GetEditView()->GetSelection();
+ aSel.GetStart().GetPara()++; // Basic lines start at 1!
+ aSel.GetEnd().GetPara()++;
+
+ for ( sal_uInt32 nLine = aSel.GetStart().GetPara(); nLine <= aSel.GetEnd().GetPara(); ++nLine )
+ {
+ ToggleBreakPoint( nLine );
+ }
+
+ m_aXEditorWindow->GetBrkWindow().Invalidate();
+}
+
+
+void ModulWindow::BasicToggleBreakPointEnabled()
+{
+ AssertValidEditEngine();
+
+ TextView* pView = GetEditView();
+ if ( !pView )
+ return;
+
+ TextSelection aSel = pView->GetSelection();
+ BreakPointList& rList = GetBreakPoints();
+
+ for ( sal_uInt32 nLine = ++aSel.GetStart().GetPara(), nEnd = ++aSel.GetEnd().GetPara(); nLine <= nEnd; ++nLine )
+ {
+ BreakPoint* pBrk = rList.FindBreakPoint( nLine );
+ if ( pBrk )
+ {
+ pBrk->bEnabled = !pBrk->bEnabled;
+ UpdateBreakPoint( *pBrk );
+ }
+ }
+
+ GetBreakPointWindow().Invalidate();
+}
+
+void ModulWindow::ManageBreakPoints()
+{
+ BreakPointWindow& rBrkWin = GetBreakPointWindow();
+ BreakPointDialog aBrkDlg(rBrkWin.GetFrameWeld(), GetBreakPoints());
+ aBrkDlg.run();
+ rBrkWin.Invalidate();
+}
+
+void ModulWindow::BasicErrorHdl( StarBASIC const * pBasic )
+{
+ GetShell()->GetViewFrame()->ToTop();
+
+ // Return value: BOOL
+ // FALSE: cancel
+ // TRUE: go on...
+ sal_uInt16 nErrorLine = StarBASIC::GetLine() - 1;
+ sal_uInt16 nErrCol1 = StarBASIC::GetCol1();
+ sal_uInt16 nErrCol2 = StarBASIC::GetCol2();
+ if ( nErrCol2 != 0xFFFF )
+ nErrCol2++;
+
+ AssertValidEditEngine();
+ GetEditView()->SetSelection( TextSelection( TextPaM( nErrorLine, nErrCol1 ), TextPaM( nErrorLine, nErrCol2 ) ) );
+
+ // if other basic, the IDE should try to display the correct module
+ bool const bMarkError = pBasic == GetBasic();
+ if ( bMarkError )
+ m_aXEditorWindow->GetBrkWindow().SetMarkerPos(nErrorLine, true);
+
+ // #i47002#
+ Reference< awt::XWindow > xWindow = VCLUnoHelper::GetInterface( this );
+
+ // tdf#118572 make a currently running dialog, regardless of what its modal
+ // to, insensitive to user input until after this error dialog goes away.
+ TopLevelWindowLocker aBusy;
+ aBusy.incBusy(nullptr);
+
+ ErrorHandler::HandleError(StarBASIC::GetErrorCode(), GetFrameWeld());
+
+ aBusy.decBusy();
+
+ // #i47002#
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ if ( !pWindow )
+ return;
+
+ if ( bMarkError )
+ m_aXEditorWindow->GetBrkWindow().SetNoMarker();
+ return;
+}
+
+BasicDebugFlags ModulWindow::BasicBreakHdl()
+{
+ // Return value: sal_uInt16 => see SB-Debug-Flags
+ sal_uInt16 nErrorLine = StarBASIC::GetLine();
+
+
+ BreakPoint* pBrk = GetBreakPoints().FindBreakPoint( nErrorLine );
+ if ( pBrk )
+ {
+ pBrk->nHitCount++;
+ if ( pBrk->nHitCount <= pBrk->nStopAfter && GetBasic()->IsBreak() )
+ return m_aStatus.nBasicFlags; // go on...
+ }
+
+ nErrorLine--; // EditEngine starts at 0, Basic at 1
+
+ AssertValidEditEngine();
+ GetEditView()->SetSelection( TextSelection( TextPaM( nErrorLine, 0 ), TextPaM( nErrorLine, 0 ) ) );
+ m_aXEditorWindow->GetBrkWindow().SetMarkerPos( nErrorLine );
+
+ m_rLayout.UpdateDebug(false);
+
+ m_aStatus.bIsInReschedule = true;
+ m_aStatus.bIsRunning = true;
+
+ AddStatus( BASWIN_INRESCHEDULE );
+
+ InvalidateDebuggerSlots();
+
+ while( m_aStatus.bIsRunning && !Application::IsQuit())
+ Application::Yield();
+
+ m_aStatus.bIsInReschedule = false;
+ m_aXEditorWindow->GetBrkWindow().SetNoMarker();
+
+ ClearStatus( BASWIN_INRESCHEDULE );
+
+ return m_aStatus.nBasicFlags;
+}
+
+void ModulWindow::BasicAddWatch()
+{
+ AssertValidEditEngine();
+ bool bAdd = true;
+ if ( !GetEditView()->HasSelection() )
+ {
+ // tdf#57307 - expand selection to include connector punctuations
+ TextSelection aSel;
+ OUString aWord = GetEditEngine()->GetWord( GetEditView()->GetSelection().GetEnd(), &aSel.GetStart(), &aSel.GetEnd() );
+ if ( !aWord.isEmpty() )
+ GetEditView()->SetSelection( aSel );
+ else
+ bAdd = false;
+ }
+ if ( bAdd )
+ {
+ TextSelection aSel = GetEditView()->GetSelection();
+ if ( aSel.GetStart().GetPara() == aSel.GetEnd().GetPara() ) // single line selection
+ m_rLayout.BasicAddWatch(GetEditView()->GetSelected());
+ }
+}
+
+
+void ModulWindow::EditMacro( const OUString& rMacroName )
+{
+ DBG_ASSERT( XModule().is(), "No Module!" );
+
+ if ( !XModule().is() )
+ return;
+
+ CheckCompileBasic();
+
+ if ( m_aStatus.bError )
+ return;
+
+ sal_uInt16 nStart, nEnd;
+ SbMethod* pMethod = static_cast<SbMethod*>(m_xModule->Find( rMacroName, SbxClassType::Method ));
+ if ( !pMethod )
+ return;
+
+ pMethod->GetLineRange( nStart, nEnd );
+ if ( nStart )
+ {
+ nStart--;
+ nEnd--;
+ }
+ TextSelection aSel( TextPaM( nStart, 0 ), TextPaM( nStart, 0 ) );
+ AssertValidEditEngine();
+ TextView * pView = GetEditView();
+ // scroll if applicable so that first line is at the top
+ tools::Long nVisHeight = GetOutputSizePixel().Height();
+ if ( pView->GetTextEngine()->GetTextHeight() > nVisHeight )
+ {
+ tools::Long nMaxY = pView->GetTextEngine()->GetTextHeight() - nVisHeight;
+ tools::Long nOldStartY = pView->GetStartDocPos().Y();
+ tools::Long nNewStartY = static_cast<tools::Long>(nStart) * pView->GetTextEngine()->GetCharHeight();
+ nNewStartY = std::min( nNewStartY, nMaxY );
+ pView->Scroll( 0, -(nNewStartY-nOldStartY) );
+ pView->ShowCursor( false );
+ GetEditVScrollBar().SetThumbPos( pView->GetStartDocPos().Y() );
+ }
+ pView->SetSelection( aSel );
+ pView->ShowCursor();
+ pView->GetWindow()->GrabFocus();
+}
+
+void ModulWindow::StoreData()
+{
+ // StoreData is called when the BasicManager is destroyed or
+ // this window is closed.
+ // => interrupts undesired!
+ GetEditorWindow().SetSourceInBasic();
+}
+
+bool ModulWindow::AllowUndo()
+{
+ return GetEditorWindow().CanModify();
+}
+
+void ModulWindow::UpdateData()
+{
+ DBG_ASSERT( XModule().is(), "No Module!" );
+ // UpdateData is called when the source has changed from outside
+ // => interrupts undesired!
+
+ if ( !XModule().is() )
+ return;
+
+ SetModule( m_xModule->GetSource32() );
+
+ if ( GetEditView() )
+ {
+ TextSelection aSel = GetEditView()->GetSelection();
+ setTextEngineText(*GetEditEngine(), m_xModule->GetSource32());
+ GetEditView()->SetSelection( aSel );
+ GetEditEngine()->SetModified( false );
+ MarkDocumentModified( GetDocument() );
+ }
+}
+
+sal_Int32 ModulWindow::countPages( Printer* pPrinter )
+{
+ return FormatAndPrint( pPrinter, -1 );
+}
+
+void ModulWindow::printPage( sal_Int32 nPage, Printer* pPrinter )
+{
+ FormatAndPrint( pPrinter, nPage );
+}
+
+/* implementation note: this is totally inefficient for the XRenderable interface
+ usage since the whole "document" will be format for every page. Should this ever
+ become a problem we should
+ - format only once for every new printer
+ - keep an index list for each page which is the starting paragraph
+*/
+sal_Int32 ModulWindow::FormatAndPrint( Printer* pPrinter, sal_Int32 nPrintPage )
+{
+ AssertValidEditEngine();
+
+ MapMode eOldMapMode( pPrinter->GetMapMode() );
+ vcl::Font aOldFont( pPrinter->GetFont() );
+
+ vcl::Font aFont( GetEditEngine()->GetFont() );
+ aFont.SetAlignment( ALIGN_BOTTOM );
+ aFont.SetTransparent( true );
+ aFont.SetFontSize( Size( 0, 360 ) );
+ pPrinter->SetFont( aFont );
+ pPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
+
+ OUString aTitle( CreateQualifiedName() );
+
+ sal_Int32 nLineHeight = pPrinter->GetTextHeight();
+ if(nLineHeight == 0)
+ {
+ nLineHeight = 1;
+ }
+
+ Size aPaperSz = pPrinter->GetOutputSize();
+ aPaperSz.AdjustWidth( -(Print::nLeftMargin + Print::nRightMargin) );
+ aPaperSz.AdjustHeight( -(Print::nTopMargin + Print::nBottomMargin) );
+
+ // nLinepPage is not correct if there's a line break
+ sal_Int32 nLinespPage = aPaperSz.Height()/nLineHeight;
+ tools::Long nXTextWidth = pPrinter->approximate_digit_width();
+
+ sal_Int32 nCharspLine = aPaperSz.Width() / std::max<tools::Long>(nXTextWidth, 1);
+ const sal_uInt32 nParas = GetEditEngine()->GetParagraphCount();
+
+ sal_Int32 nPages = nParas/nLinespPage+1;
+ sal_Int32 nCurPage = 1;
+
+ lcl_PrintHeader( pPrinter, nPages, nCurPage, aTitle, nPrintPage == 0 );
+ Point aPos( Print::nLeftMargin, Print::nTopMargin );
+ for ( sal_uInt32 nPara = 0; nPara < nParas; ++nPara )
+ {
+ OUString aLine( GetEditEngine()->GetText( nPara ) );
+ lcl_ConvertTabsToSpaces( aLine );
+ sal_Int32 nLines = aLine.getLength()/nCharspLine+1;
+ for (sal_Int32 nLine = 0; nLine < nLines; ++nLine)
+ {
+ sal_Int32 nBeginIndex = nLine*nCharspLine;
+ sal_Int32 nCopyCount = std::min<sal_Int32>(nCharspLine, aLine.getLength()-nBeginIndex);
+ OUString aTmpLine = aLine.copy(nBeginIndex, nCopyCount);
+ aPos.AdjustY(nLineHeight );
+ if ( aPos.Y() > ( aPaperSz.Height() + Print::nTopMargin ) )
+ {
+ nCurPage++;
+ lcl_PrintHeader( pPrinter, nPages, nCurPage, aTitle, nCurPage-1 == nPrintPage );
+ aPos = Point(Print::nLeftMargin, Print::nTopMargin + nLineHeight);
+ }
+ if( nCurPage-1 == nPrintPage )
+ pPrinter->DrawText( aPos, aTmpLine );
+ }
+ aPos.AdjustY(10 ); // nParaSpace
+ }
+
+ pPrinter->SetFont( aOldFont );
+ pPrinter->SetMapMode( eOldMapMode );
+
+ return nCurPage;
+}
+
+void ModulWindow::ExecuteCommand (SfxRequest& rReq)
+{
+ AssertValidEditEngine();
+ switch (rReq.GetSlot())
+ {
+ case SID_DELETE:
+ {
+ if (!IsReadOnly())
+ {
+ KeyEvent aFakeDelete(0, KEY_DELETE);
+ (void)GetEditView()->KeyInput(aFakeDelete);
+ }
+ break;
+ }
+ case SID_SELECTALL:
+ {
+ TextSelection aSel( TextPaM( 0, 0 ), TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ) );
+ TextView * pView = GetEditView();
+ pView->SetSelection( aSel );
+ pView->GetWindow()->GrabFocus();
+ break;
+ }
+ case SID_BASICRUN:
+ {
+ BasicRun();
+ }
+ break;
+ case SID_BASICCOMPILE:
+ {
+ CompileBasic();
+ }
+ break;
+ case SID_BASICSTEPOVER:
+ {
+ BasicStepOver();
+ }
+ break;
+ case SID_BASICSTEPINTO:
+ {
+ BasicStepInto();
+ }
+ break;
+ case SID_BASICSTEPOUT:
+ {
+ BasicStepOut();
+ }
+ break;
+ case SID_BASICLOAD:
+ {
+ LoadBasic();
+ }
+ break;
+ case SID_BASICSAVEAS:
+ {
+ SaveBasicSource();
+ }
+ break;
+ case SID_IMPORT_DIALOG:
+ {
+ ImportDialog();
+ }
+ break;
+ case SID_BASICIDE_MATCHGROUP:
+ {
+ GetEditView()->MatchGroup();
+ }
+ break;
+ case SID_BASICIDE_TOGGLEBRKPNT:
+ {
+ BasicToggleBreakPoint();
+ }
+ break;
+ case SID_BASICIDE_MANAGEBRKPNTS:
+ {
+ ManageBreakPoints();
+ }
+ break;
+ case SID_BASICIDE_TOGGLEBRKPNTENABLED:
+ {
+ BasicToggleBreakPointEnabled();
+ }
+ break;
+ case SID_BASICIDE_ADDWATCH:
+ {
+ BasicAddWatch();
+ }
+ break;
+ case SID_BASICIDE_REMOVEWATCH:
+ {
+ m_rLayout.BasicRemoveWatch();
+ }
+ break;
+ case SID_CUT:
+ {
+ if ( !IsReadOnly() )
+ {
+ GetEditView()->Cut();
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+ }
+ }
+ break;
+ case SID_COPY:
+ {
+ GetEditView()->Copy();
+ }
+ break;
+ case SID_PASTE:
+ {
+ if ( !IsReadOnly() )
+ {
+ GetEditView()->Paste();
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+ }
+ }
+ break;
+ case SID_BASICIDE_BRKPNTSCHANGED:
+ {
+ GetBreakPointWindow().Invalidate();
+ }
+ break;
+ case SID_SHOWLINES:
+ {
+ const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(rReq.GetSlot());
+ bool bLineNumbers = pItem && pItem->GetValue();
+ m_aXEditorWindow->SetLineNumberDisplay(bLineNumbers);
+
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::BasicIDE::EditorSettings::LineNumbering::set(bLineNumbers, batch);
+ batch->commit();
+ }
+ break;
+ case SID_BASICIDE_DELETECURRENT:
+ {
+ if (QueryDelModule(m_aName, GetFrameWeld()))
+ {
+ // tdf#134551 don't delete the window if last module is removed until this block
+ // is complete
+ VclPtr<ModulWindow> xKeepRef(this);
+ if (m_aDocument.removeModule(m_aLibName, m_aName))
+ MarkDocumentModified(m_aDocument);
+ }
+ }
+ break;
+ case FID_SEARCH_OFF:
+ GrabFocus();
+ break;
+ case SID_GOTOLINE:
+ {
+ GotoLineDialog aGotoDlg(GetFrameWeld());
+ if (aGotoDlg.run() == RET_OK)
+ {
+ if (sal_Int32 const nLine = aGotoDlg.GetLineNumber())
+ {
+ TextSelection const aSel(TextPaM(nLine - 1, 0), TextPaM(nLine - 1, 0));
+ GetEditView()->SetSelection(aSel);
+ }
+ }
+ break;
+ }
+ }
+}
+
+void ModulWindow::ExecuteGlobal (SfxRequest& rReq)
+{
+ switch (rReq.GetSlot())
+ {
+ case SID_SIGNATURE:
+ {
+ DocumentSignature aSignature(m_aDocument);
+ if (aSignature.supportsSignatures())
+ {
+ aSignature.signScriptingContent(rReq.GetFrameWeld());
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate(SID_SIGNATURE);
+ }
+ }
+ break;
+ }
+}
+
+void ModulWindow::GetState( SfxItemSet &rSet )
+{
+ SfxWhichIter aIter(rSet);
+ for ( sal_uInt16 nWh = aIter.FirstWhich(); nWh != 0; nWh = aIter.NextWhich() )
+ {
+ switch ( nWh )
+ {
+ case SID_CUT:
+ {
+ if ( !GetEditView() || !GetEditView()->HasSelection() )
+ rSet.DisableItem( nWh );
+
+ if ( IsReadOnly() )
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_COPY:
+ {
+ if ( !GetEditView() || !GetEditView()->HasSelection() )
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_PASTE:
+ {
+ if ( !IsPasteAllowed() )
+ rSet.DisableItem( nWh );
+
+ if ( IsReadOnly() )
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_BASICIDE_STAT_POS:
+ {
+ TextView* pView = GetEditView();
+ if ( pView )
+ {
+ TextSelection aSel = pView->GetSelection();
+ OUString aPos = IDEResId( RID_STR_LINE ) +
+ " " +
+ OUString::number(aSel.GetEnd().GetPara()+1) +
+ ", " +
+ IDEResId( RID_STR_COLUMN ) +
+ " " +
+ OUString::number(aSel.GetEnd().GetIndex()+1);
+ SfxStringItem aItem( SID_BASICIDE_STAT_POS, aPos );
+ rSet.Put( aItem );
+ }
+ }
+ break;
+ case SID_BASICIDE_STAT_TITLE:
+ {
+ // search for current procedure name (Sub or Function)
+ TextView* pView = GetEditView();
+ if ( pView )
+ {
+ OUString sProcName;
+
+ TextSelection aSel = pView->GetSelection();
+
+ sal_uInt32 i = aSel.GetStart().GetPara();
+ do
+ {
+ OUString aCurrLine = GetEditEngine()->GetText( i );
+ OUString sProcType;
+ if (GetEditorWindow().GetProcedureName(aCurrLine, sProcType, sProcName))
+ break;
+ } while (i--);
+
+ OUString aTitle = CreateQualifiedName();
+ if (!sProcName.isEmpty())
+ aTitle += "." + sProcName;
+
+ SfxStringItem aTitleItem( SID_BASICIDE_STAT_TITLE, aTitle );
+ rSet.Put( aTitleItem );
+ }
+ }
+ break;
+ case SID_ATTR_INSERT:
+ {
+ TextView* pView = GetEditView();
+ if ( pView )
+ {
+ SfxBoolItem aItem( SID_ATTR_INSERT, pView->IsInsertMode() );
+ rSet.Put( aItem );
+ }
+ }
+ break;
+ case SID_SHOWLINES:
+ {
+ bool bLineNumbers = ::officecfg::Office::BasicIDE::EditorSettings::LineNumbering::get();
+ rSet.Put(SfxBoolItem(nWh, bLineNumbers));
+ break;
+ }
+ case SID_SELECTALL:
+ {
+ if ( !GetEditView() )
+ rSet.DisableItem( nWh );
+ }
+ break;
+ }
+ }
+}
+
+void ModulWindow::DoScroll( ScrollBar* pCurScrollBar )
+{
+ if ( ( pCurScrollBar == GetHScrollBar() ) && GetEditView() )
+ {
+ // don't scroll with the value but rather use the Thumb-Pos for the VisArea:
+ tools::Long nDiff = GetEditView()->GetStartDocPos().X() - pCurScrollBar->GetThumbPos();
+ GetEditView()->Scroll( nDiff, 0 );
+ GetEditView()->ShowCursor( false );
+ pCurScrollBar->SetThumbPos( GetEditView()->GetStartDocPos().X() );
+
+ }
+}
+
+bool ModulWindow::IsModified()
+{
+ return GetEditEngine() && GetEditEngine()->IsModified();
+}
+
+OUString ModulWindow::GetSbModuleName()
+{
+ OUString aModuleName;
+ if ( XModule().is() )
+ aModuleName = m_xModule->GetName();
+ return aModuleName;
+}
+
+OUString ModulWindow::GetTitle()
+{
+ return GetSbModuleName();
+}
+
+void ModulWindow::ShowCursor( bool bOn )
+{
+ if ( GetEditEngine() )
+ {
+ TextView* pView = GetEditEngine()->GetActiveView();
+ if ( pView )
+ {
+ if ( bOn )
+ pView->ShowCursor();
+ else
+ pView->HideCursor();
+ }
+ }
+}
+
+void ModulWindow::AssertValidEditEngine()
+{
+ if ( !GetEditEngine() )
+ GetEditorWindow().CreateEditEngine();
+}
+
+void ModulWindow::Activating ()
+{
+ bool bLineNumbers = ::officecfg::Office::BasicIDE::EditorSettings::LineNumbering::get();
+ m_aXEditorWindow->SetLineNumberDisplay(bLineNumbers);
+ Show();
+}
+
+void ModulWindow::Deactivating()
+{
+ Hide();
+}
+
+sal_uInt16 ModulWindow::StartSearchAndReplace( const SvxSearchItem& rSearchItem, bool bFromStart )
+{
+ if (IsSuspended())
+ return 0;
+
+ // one could also relinquish syntaxhighlighting/formatting instead of the stupid replace-everything...
+ AssertValidEditEngine();
+ TextView* pView = GetEditView();
+ TextSelection aSel;
+ if ( bFromStart )
+ {
+ aSel = pView->GetSelection();
+ if ( !rSearchItem.GetBackward() )
+ pView->SetSelection( TextSelection() );
+ else
+ pView->SetSelection( TextSelection( TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ), TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ) ) );
+ }
+
+ bool const bForward = !rSearchItem.GetBackward();
+ sal_uInt16 nFound = 0;
+ if ( ( rSearchItem.GetCommand() == SvxSearchCmd::FIND ) ||
+ ( rSearchItem.GetCommand() == SvxSearchCmd::FIND_ALL ) )
+ {
+ nFound = pView->Search( rSearchItem.GetSearchOptions() , bForward ) ? 1 : 0;
+ }
+ else if ( ( rSearchItem.GetCommand() == SvxSearchCmd::REPLACE ) ||
+ ( rSearchItem.GetCommand() == SvxSearchCmd::REPLACE_ALL ) )
+ {
+ if ( !IsReadOnly() )
+ {
+ bool const bAll = rSearchItem.GetCommand() == SvxSearchCmd::REPLACE_ALL;
+ nFound = pView->Replace( rSearchItem.GetSearchOptions() , bAll , bForward );
+ }
+ }
+
+ if ( bFromStart && !nFound )
+ pView->SetSelection( aSel );
+
+ return nFound;
+}
+
+SfxUndoManager* ModulWindow::GetUndoManager()
+{
+ if ( GetEditEngine() )
+ return &GetEditEngine()->GetUndoManager();
+ return nullptr;
+}
+
+SearchOptionFlags ModulWindow::GetSearchOptions()
+{
+ SearchOptionFlags nOptions = SearchOptionFlags::SEARCH |
+ SearchOptionFlags::WHOLE_WORDS |
+ SearchOptionFlags::BACKWARDS |
+ SearchOptionFlags::REG_EXP |
+ SearchOptionFlags::EXACT |
+ SearchOptionFlags::SELECTION |
+ SearchOptionFlags::SIMILARITY;
+
+ if ( !IsReadOnly() )
+ {
+ nOptions |= SearchOptionFlags::REPLACE;
+ nOptions |= SearchOptionFlags::REPLACE_ALL;
+ }
+
+ return nOptions;
+}
+
+void ModulWindow::BasicStarted()
+{
+ if ( !XModule().is() )
+ return;
+
+ m_aStatus.bIsRunning = true;
+ BreakPointList& rList = GetBreakPoints();
+ if ( rList.size() )
+ {
+ rList.ResetHitCount();
+ rList.SetBreakPointsInBasic( m_xModule.get() );
+ for (sal_uInt32 nMethod = 0; nMethod < m_xModule->GetMethods()->Count(); nMethod++)
+ {
+ SbMethod* pMethod = static_cast<SbMethod*>(m_xModule->GetMethods()->Get(nMethod));
+ assert(pMethod && "Method not found! (NULL)");
+ pMethod->SetDebugFlags( pMethod->GetDebugFlags() | BasicDebugFlags::Break );
+ }
+ }
+}
+
+void ModulWindow::BasicStopped()
+{
+ m_aStatus.bIsRunning = false;
+ GetBreakPointWindow().SetNoMarker();
+}
+
+EntryDescriptor ModulWindow::CreateEntryDescriptor()
+{
+ ScriptDocument aDocument( GetDocument() );
+ OUString aLibName( GetLibName() );
+ LibraryLocation eLocation = aDocument.getLibraryLocation( aLibName );
+ OUString aModName( GetName() );
+ OUString aLibSubName;
+ if( m_xBasic.is() && aDocument.isInVBAMode() && XModule().is() )
+ {
+ switch( m_xModule->GetModuleType() )
+ {
+ case script::ModuleType::DOCUMENT:
+ {
+ aLibSubName = IDEResId( RID_STR_DOCUMENT_OBJECTS );
+ uno::Reference< container::XNameContainer > xLib = aDocument.getOrCreateLibrary( E_SCRIPTS, aLibName );
+ if( xLib.is() )
+ {
+ OUString sObjName;
+ ModuleInfoHelper::getObjectName( xLib, aModName, sObjName );
+ if( !sObjName.isEmpty() )
+ {
+ aModName += " (" + sObjName + ")";
+ }
+ }
+ break;
+ }
+ case script::ModuleType::FORM:
+ aLibSubName = IDEResId( RID_STR_USERFORMS );
+ break;
+ case script::ModuleType::NORMAL:
+ aLibSubName = IDEResId( RID_STR_NORMAL_MODULES );
+ break;
+ case script::ModuleType::CLASS:
+ aLibSubName = IDEResId( RID_STR_CLASS_MODULES );
+ break;
+ }
+ }
+ return EntryDescriptor( aDocument, eLocation, aLibName, aLibSubName, aModName, OBJ_TYPE_MODULE );
+}
+
+void ModulWindow::SetReadOnly (bool b)
+{
+ if ( GetEditView() )
+ GetEditView()->SetReadOnly( b );
+}
+
+bool ModulWindow::IsReadOnly()
+{
+ return GetEditView() && GetEditView()->IsReadOnly();
+}
+
+bool ModulWindow::IsPasteAllowed()
+{
+ bool bPaste = false;
+
+ // get clipboard
+ Reference< datatransfer::clipboard::XClipboard > xClipboard = GetClipboard();
+ if ( xClipboard.is() )
+ {
+
+ Reference< datatransfer::XTransferable > xTransf;
+ {
+ SolarMutexReleaser aReleaser;
+ // get clipboard content
+ xTransf = xClipboard->getContents();
+ }
+ if ( xTransf.is() )
+ {
+ datatransfer::DataFlavor aFlavor;
+ SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor );
+ if ( xTransf->isDataFlavorSupported( aFlavor ) )
+ bPaste = true;
+ }
+ }
+
+ return bPaste;
+}
+
+void ModulWindow::OnNewDocument ()
+{
+ bool bLineNumbers = ::officecfg::Office::BasicIDE::EditorSettings::LineNumbering::get();
+ m_aXEditorWindow->SetLineNumberDisplay(bLineNumbers);
+}
+
+OString ModulWindow::GetHid () const
+{
+ return HID_BASICIDE_MODULWINDOW;
+}
+ItemType ModulWindow::GetType () const
+{
+ return TYPE_MODULE;
+}
+
+bool ModulWindow::HasActiveEditor () const
+{
+ return !IsSuspended();
+}
+
+
+void ModulWindow::UpdateModule ()
+{
+ OUString const aModule = getTextEngineText(*GetEditEngine());
+
+ // update module in basic
+ assert(m_xModule.is());
+
+ // update module in module window
+ SetModule(aModule);
+
+ // update module in library
+ OSL_VERIFY(m_aDocument.updateModule(m_aLibName, m_aName, aModule));
+
+ GetEditEngine()->SetModified(false);
+ MarkDocumentModified(m_aDocument);
+}
+
+ModulWindowLayout::ModulWindowLayout (vcl::Window* pParent, ObjectCatalog& rObjectCatalog_) :
+ Layout(pParent),
+ pChild(nullptr),
+ aWatchWindow(VclPtr<WatchWindow>::Create(this)),
+ aStackWindow(VclPtr<StackWindow>::Create(this)),
+ rObjectCatalog(rObjectCatalog_)
+{ }
+
+ModulWindowLayout::~ModulWindowLayout()
+{
+ disposeOnce();
+}
+
+void ModulWindowLayout::dispose()
+{
+ aWatchWindow.disposeAndClear();
+ aStackWindow.disposeAndClear();
+ pChild.clear();
+ Layout::dispose();
+}
+
+void ModulWindowLayout::UpdateDebug (bool bBasicStopped)
+{
+ aWatchWindow->UpdateWatches(bBasicStopped);
+ aStackWindow->UpdateCalls();
+}
+
+void ModulWindowLayout::Paint (vcl::RenderContext& rRenderContext, tools::Rectangle const&)
+{
+ rRenderContext.DrawText(Point(), IDEResId(RID_STR_NOMODULE));
+}
+
+void ModulWindowLayout::Activating (BaseWindow& rChild)
+{
+ assert(dynamic_cast<ModulWindow*>(&rChild));
+ pChild = &static_cast<ModulWindow&>(rChild);
+ aWatchWindow->Show();
+ aStackWindow->Show();
+ rObjectCatalog.Show();
+ rObjectCatalog.SetLayoutWindow(this);
+ rObjectCatalog.UpdateEntries();
+ Layout::Activating(rChild);
+ aSyntaxColors.SetActiveEditor(&pChild->GetEditorWindow());
+}
+
+void ModulWindowLayout::Deactivating ()
+{
+ aSyntaxColors.SetActiveEditor(nullptr);
+ Layout::Deactivating();
+ aWatchWindow->Hide();
+ aStackWindow->Hide();
+ rObjectCatalog.Hide();
+ pChild = nullptr;
+}
+
+void ModulWindowLayout::GetState (SfxItemSet &rSet, unsigned nWhich)
+{
+ switch (nWhich)
+ {
+ case SID_SHOW_PROPERTYBROWSER:
+ rSet.Put(SfxVisibilityItem(nWhich, false));
+ break;
+
+ case SID_BASICIDE_CHOOSEMACRO:
+ rSet.Put(SfxVisibilityItem(nWhich, true));
+ break;
+ }
+}
+
+void ModulWindowLayout::BasicAddWatch (OUString const& rWatchStr)
+{
+ aWatchWindow->AddWatch(rWatchStr);
+}
+
+void ModulWindowLayout::BasicRemoveWatch ()
+{
+ aWatchWindow->RemoveSelectedWatch();
+}
+
+void ModulWindowLayout::OnFirstSize (tools::Long const nWidth, tools::Long const nHeight)
+{
+ AddToLeft(&rObjectCatalog, Size(nWidth * 0.20, nHeight * 0.75));
+ AddToBottom(aWatchWindow.get(), Size(nWidth * 0.67, nHeight * 0.25));
+ AddToBottom(aStackWindow.get(), Size(nWidth * 0.33, nHeight * 0.25));
+}
+
+ModulWindowLayout::SyntaxColors::SyntaxColors () :
+ pEditor(nullptr)
+{
+ aConfig.AddListener(this);
+
+ NewConfig(true);
+}
+
+ModulWindowLayout::SyntaxColors::~SyntaxColors ()
+{
+ aConfig.RemoveListener(this);
+}
+
+// virtual
+void ModulWindowLayout::SyntaxColors::ConfigurationChanged (utl::ConfigurationBroadcaster*, ConfigurationHints)
+{
+ NewConfig(false);
+}
+
+// when a new configuration has to be set
+void ModulWindowLayout::SyntaxColors::NewConfig (bool bFirst)
+{
+ static struct
+ {
+ TokenType eTokenType;
+ svtools::ColorConfigEntry eEntry;
+ }
+ const vIds[] =
+ {
+ { TokenType::Unknown, svtools::FONTCOLOR },
+ { TokenType::Identifier, svtools::BASICIDENTIFIER },
+ { TokenType::Whitespace, svtools::FONTCOLOR },
+ { TokenType::Number, svtools::BASICNUMBER },
+ { TokenType::String, svtools::BASICSTRING },
+ { TokenType::EOL, svtools::FONTCOLOR },
+ { TokenType::Comment, svtools::BASICCOMMENT },
+ { TokenType::Error, svtools::BASICERROR },
+ { TokenType::Operator, svtools::BASICOPERATOR },
+ { TokenType::Keywords, svtools::BASICKEYWORD },
+ };
+
+ Color aDocColor = aConfig.GetColorValue(svtools::DOCCOLOR).nColor;
+ if (bFirst || aDocColor != m_aBackgroundColor)
+ {
+ m_aBackgroundColor = aDocColor;
+ if (!bFirst && pEditor)
+ {
+ pEditor->SetBackground(Wallpaper(m_aBackgroundColor));
+ pEditor->Invalidate();
+ }
+ }
+
+ Color aFontColor = aConfig.GetColorValue(svtools::FONTCOLOR).nColor;
+ if (bFirst || aFontColor != m_aFontColor)
+ {
+ m_aFontColor = aFontColor;
+ if (!bFirst && pEditor)
+ pEditor->ChangeFontColor(m_aFontColor);
+ }
+
+ bool bChanged = false;
+ for (unsigned i = 0; i != std::size(vIds); ++i)
+ {
+ Color const aColor = aConfig.GetColorValue(vIds[i].eEntry).nColor;
+ Color& rMyColor = aColors[vIds[i].eTokenType];
+ if (bFirst || aColor != rMyColor)
+ {
+ rMyColor = aColor;
+ bChanged = true;
+ }
+ }
+ if (bChanged && !bFirst && pEditor)
+ pEditor->UpdateSyntaxHighlighting();
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/baside2.hxx b/basctl/source/basicide/baside2.hxx
new file mode 100644
index 000000000..bf84323a3
--- /dev/null
+++ b/basctl/source/basicide/baside2.hxx
@@ -0,0 +1,514 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <mutex>
+#include <layout.hxx>
+#include "breakpoint.hxx"
+#include "linenumberwindow.hxx"
+
+#include <basic/sbmod.hxx>
+#include <basic/sbstar.hxx>
+#include <vcl/InterimItemWindow.hxx>
+#include <vcl/idle.hxx>
+#include <vcl/weld.hxx>
+
+#include <svtools/colorcfg.hxx>
+#include <o3tl/enumarray.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <set>
+#include <string_view>
+
+#include <vcl/textdata.hxx>
+#include <basic/codecompletecache.hxx>
+#include <com/sun/star/reflection/XIdlClass.hpp>
+#include <comphelper/syntaxhighlight.hxx>
+
+class ExtTextEngine;
+class TextView;
+class SvxSearchItem;
+namespace com::sun::star::beans { class XMultiPropertySet; }
+
+namespace basctl
+{
+
+class ObjectCatalog;
+class CodeCompleteWindow;
+class ModulWindowLayout;
+
+// #108672 Helper functions to get/set text in TextEngine
+// using the stream interface (get/setText() only supports
+// tools Strings limited to 64K).
+// defined in baside2b.cxx
+OUString getTextEngineText (ExtTextEngine&);
+void setTextEngineText (ExtTextEngine&, std::u16string_view);
+
+class EditorWindow final : public vcl::Window, public SfxListener
+{
+friend class CodeCompleteWindow;
+friend class EditorWindowUIObject;
+private:
+ class ChangesListener;
+
+ std::unique_ptr<TextView> pEditView;
+ std::unique_ptr<ExtTextEngine> pEditEngine;
+ ModulWindow& rModulWindow;
+
+ rtl::Reference< ChangesListener > listener_;
+ std::mutex mutex_;
+ css::uno::Reference< css::beans::XMultiPropertySet >
+ notifier_;
+
+ tools::Long nCurTextWidth;
+
+ ImplSVEvent* m_nSetSourceInBasicId;
+
+ SyntaxHighlighter aHighlighter;
+ Idle aSyntaxIdle;
+ std::set<sal_uInt16> aSyntaxLineTable;
+ DECL_LINK(SyntaxTimerHdl, Timer *, void);
+ DECL_LINK(SetSourceInBasicHdl, void*, void);
+
+ // progress bar
+ class ProgressInfo;
+ std::unique_ptr<ProgressInfo> pProgress;
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ void ImpDoHighlight( sal_uInt32 nLineOff );
+ void ImplSetFont();
+
+ bool bHighlighting;
+ bool bDoSyntaxHighlight;
+ bool bDelayHighlight;
+
+ virtual css::uno::Reference< css::awt::XWindowPeer > GetComponentInterface(bool bCreate = true) override;
+ CodeCompleteDataCache aCodeCompleteCache;
+ VclPtr<CodeCompleteWindow> pCodeCompleteWnd;
+ OUString GetActualSubName( sal_uInt32 nLine ); // gets the actual subroutine name according to line number
+ void SetupAndShowCodeCompleteWnd(const std::vector< OUString >& aEntryVect, TextSelection aSel );
+ void HandleAutoCorrect();
+ void HandleAutoCloseParen();
+ void HandleAutoCloseDoubleQuotes();
+ void HandleCodeCompletion();
+ void HandleProcedureCompletion();
+ TextSelection GetLastHighlightPortionTextSelection() const;
+
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& ) override;
+ virtual void Resize() override;
+ virtual void KeyInput( const KeyEvent& rKeyEvt ) override;
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+ virtual void Command( const CommandEvent& rCEvt ) override;
+ virtual void LoseFocus() override;
+ virtual void RequestHelp( const HelpEvent& rHEvt ) override;
+
+ void DoSyntaxHighlight( sal_uInt32 nPara );
+ OUString GetWordAtCursor();
+ bool ImpCanModify();
+
+public:
+ EditorWindow (vcl::Window* pParent, ModulWindow*);
+ virtual ~EditorWindow() override;
+ virtual void dispose() override;
+
+ ExtTextEngine* GetEditEngine() const { return pEditEngine.get(); }
+ TextView* GetEditView() const { return pEditView.get(); }
+
+ void CreateProgress( const OUString& rText, sal_uInt32 nRange );
+ void DestroyProgress();
+
+ void ParagraphInsertedDeleted( sal_uInt32 nNewPara, bool bInserted );
+ void DoDelayedSyntaxHighlight( sal_uInt32 nPara );
+
+ void CreateEditEngine();
+ void SetScrollBarRanges();
+ void InitScrollBars();
+
+ void ForceSyntaxTimeout();
+ void SetSourceInBasic();
+
+ bool CanModify() { return ImpCanModify(); }
+
+ void ChangeFontColor( Color aColor );
+ void UpdateSyntaxHighlighting ();
+
+ bool GetProcedureName(std::u16string_view rLine, OUString& rProcType, OUString& rProcName) const;
+
+ FactoryFunction GetUITestFactory() const override;
+};
+
+class BreakPointWindow final : public vcl::Window
+{
+ ModulWindow& rModulWindow;
+ tools::Long nCurYOffset;
+ sal_uInt16 nMarkerPos;
+ BreakPointList aBreakPointList;
+ bool bErrorMarker;
+
+ virtual void DataChanged(DataChangedEvent const & rDCEvt) override;
+
+ void setBackgroundColor(Color aColor);
+
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override;
+ BreakPoint* FindBreakPoint( const Point& rMousePos );
+ void ShowMarker(vcl::RenderContext& rRenderContext);
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void Command( const CommandEvent& rCEvt ) override;
+
+ bool SyncYOffset();
+
+public:
+ BreakPointWindow (vcl::Window* pParent, ModulWindow*);
+
+ void SetMarkerPos( sal_uInt16 nLine, bool bErrorMarker = false );
+ void SetNoMarker ();
+
+ void DoScroll( tools::Long nVertScroll );
+ tools::Long& GetCurYOffset() { return nCurYOffset; }
+ BreakPointList& GetBreakPoints() { return aBreakPointList; }
+};
+
+class WatchWindow final : public DockingWindow
+{
+private:
+ std::unique_ptr<weld::Container> m_xTitleArea;
+ std::unique_ptr<weld::Label> m_xTitle;
+ std::unique_ptr<weld::Entry> m_xEdit;
+ std::unique_ptr<weld::Button> m_xRemoveWatchButton;
+ std::unique_ptr<weld::TreeView> m_xTreeListBox;
+
+ ImplSVEvent* m_nUpdateWatchesId;
+ OUString aEditingRes;
+
+ virtual void Resize() override;
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
+
+ SbxBase* ImplGetSBXForEntry(const weld::TreeIter& rEntry, bool& rbArrayElement);
+
+ void implEnableChildren(const weld::TreeIter& rEntry, bool bEnable);
+
+ DECL_STATIC_LINK(WatchWindow, ButtonHdl, weld::Button&, void);
+ DECL_LINK(TreeListHdl, weld::TreeView&, void);
+ DECL_LINK(RequestingChildrenHdl, const weld::TreeIter&, bool);
+ DECL_LINK(ActivateHdl, weld::Entry&, bool);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(EditingEntryHdl, const weld::TreeIter&, bool);
+ typedef std::pair<const weld::TreeIter&, OUString> IterString;
+ DECL_LINK(EditedEntryHdl, const IterString&, bool);
+ DECL_LINK(ExecuteUpdateWatches, void*, void);
+
+public:
+ explicit WatchWindow (Layout* pParent);
+ virtual ~WatchWindow() override;
+ virtual void dispose() override;
+
+ void AddWatch( const OUString& rVName );
+ void RemoveSelectedWatch();
+ void UpdateWatches(bool bBasicStopped = false);
+};
+
+class StackWindow : public DockingWindow
+{
+private:
+ std::unique_ptr<weld::Label> m_xTitle;
+ std::unique_ptr<weld::TreeView> m_xTreeListBox;
+
+protected:
+ virtual void Resize() override;
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
+
+public:
+ explicit StackWindow (Layout* pParent);
+ virtual ~StackWindow() override;
+ virtual void dispose() override;
+
+ void UpdateCalls();
+};
+
+
+class ComplexEditorWindow final : public vcl::Window
+{
+private:
+ VclPtr<BreakPointWindow> aBrkWindow;
+ VclPtr<LineNumberWindow> aLineNumberWindow;
+ VclPtr<EditorWindow> aEdtWindow;
+ VclPtr<ScrollBar> aEWVScrollBar;
+
+ virtual void DataChanged(DataChangedEvent const & rDCEvt) override;
+
+ virtual void Resize() override;
+ DECL_LINK( ScrollHdl, ScrollBar*, void );
+
+public:
+ explicit ComplexEditorWindow( ModulWindow* pParent );
+ virtual ~ComplexEditorWindow() override;
+ virtual void dispose() override;
+ BreakPointWindow& GetBrkWindow() { return *aBrkWindow; }
+ LineNumberWindow& GetLineNumberWindow() { return *aLineNumberWindow; }
+ EditorWindow& GetEdtWindow() { return *aEdtWindow; }
+ ScrollBar& GetEWVScrollBar() { return *aEWVScrollBar; }
+
+ void SetLineNumberDisplay(bool b);
+};
+
+
+class ModulWindow: public BaseWindow
+{
+private:
+ ModulWindowLayout& m_rLayout;
+ StarBASICRef m_xBasic;
+ short m_nValid;
+ VclPtr<ComplexEditorWindow> m_aXEditorWindow;
+ BasicStatus m_aStatus;
+ SbModuleRef m_xModule;
+ OUString m_aModule;
+
+ void CheckCompileBasic();
+ void BasicExecute();
+
+ sal_Int32 FormatAndPrint( Printer* pPrinter, sal_Int32 nPage );
+ SbModuleRef const & XModule();
+protected:
+ virtual void Resize() override;
+ virtual void GetFocus() override;
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& ) override;
+ virtual void DoInit() override;
+ virtual void DoScroll( ScrollBar* pCurScrollBar ) override;
+
+public:
+ ModulWindow( ModulWindowLayout* pParent, const ScriptDocument& rDocument, const OUString& aLibName, const OUString& aName, OUString aModule );
+
+ virtual ~ModulWindow() override;
+ virtual void dispose() override;
+
+ virtual void ExecuteCommand (SfxRequest& rReq) override;
+ virtual void ExecuteGlobal (SfxRequest& rReq) override;
+ virtual void GetState( SfxItemSet& ) override;
+ virtual void StoreData() override;
+ virtual void UpdateData() override;
+ // return number of pages to be printed
+ virtual sal_Int32 countPages( Printer* pPrinter ) override;
+ // print page
+ virtual void printPage( sal_Int32 nPage, Printer* pPrinter ) override;
+ virtual OUString GetTitle() override;
+ virtual EntryDescriptor CreateEntryDescriptor() override;
+ virtual bool AllowUndo() override;
+ virtual void SetReadOnly (bool bReadOnly) override;
+ virtual bool IsReadOnly() override;
+
+ StarBASIC* GetBasic() { XModule(); return m_xBasic.get(); }
+
+ SbModule* GetSbModule() { return m_xModule.get(); }
+ void SetSbModule( SbModule* pModule ) { m_xModule = pModule; }
+ OUString GetSbModuleName();
+
+ void CompileBasic();
+ void BasicRun();
+ void BasicStepOver();
+ void BasicStepInto();
+ void BasicStepOut();
+ void BasicStop();
+ void BasicToggleBreakPoint();
+ void BasicToggleBreakPointEnabled();
+ void ManageBreakPoints();
+ void UpdateBreakPoint( const BreakPoint& rBrk );
+ void BasicAddWatch();
+
+ void BasicErrorHdl( StarBASIC const * pBasic );
+ BasicDebugFlags BasicBreakHdl();
+ void AssertValidEditEngine();
+
+ void LoadBasic();
+ void SaveBasicSource();
+ void ImportDialog();
+
+ void EditMacro( const OUString& rMacroName );
+
+ void ToggleBreakPoint( sal_uInt16 nLine );
+
+ BasicStatus& GetBasicStatus() { return m_aStatus; }
+
+ virtual bool IsModified () override;
+ bool IsPasteAllowed ();
+
+ void ShowCursor( bool bOn );
+
+ virtual SearchOptionFlags GetSearchOptions() override;
+ virtual sal_uInt16 StartSearchAndReplace (SvxSearchItem const&, bool bFromStart = false) override;
+
+ EditorWindow& GetEditorWindow() { return m_aXEditorWindow->GetEdtWindow(); }
+ BreakPointWindow& GetBreakPointWindow() { return m_aXEditorWindow->GetBrkWindow(); }
+ LineNumberWindow& GetLineNumberWindow() { return m_aXEditorWindow->GetLineNumberWindow(); }
+ ScrollBar& GetEditVScrollBar() { return m_aXEditorWindow->GetEWVScrollBar(); }
+ ExtTextEngine* GetEditEngine() { return GetEditorWindow().GetEditEngine(); }
+ TextView* GetEditView() { return GetEditorWindow().GetEditView(); }
+ BreakPointList& GetBreakPoints() { return GetBreakPointWindow().GetBreakPoints(); }
+ ModulWindowLayout& GetLayout () { return m_rLayout; }
+
+ virtual void BasicStarted() override;
+ virtual void BasicStopped() override;
+
+ virtual SfxUndoManager*
+ GetUndoManager() override;
+
+ const OUString& GetModule() const { return m_aModule; }
+ void SetModule( const OUString& aModule ) { m_aModule = aModule; }
+
+ virtual void Activating () override;
+ virtual void Deactivating () override;
+
+ virtual void OnNewDocument () override;
+ virtual OString GetHid () const override;
+ virtual ItemType GetType () const override;
+ virtual bool HasActiveEditor () const override;
+
+ void UpdateModule ();
+};
+
+class ModulWindowLayout: public Layout
+{
+public:
+ ModulWindowLayout (vcl::Window* pParent, ObjectCatalog&);
+ virtual ~ModulWindowLayout() override;
+ virtual void dispose() override;
+public:
+ // Layout:
+ virtual void Activating (BaseWindow&) override;
+ virtual void Deactivating () override;
+ virtual void GetState (SfxItemSet&, unsigned nWhich) override;
+ virtual void UpdateDebug (bool bBasicStopped) override;
+public:
+ void BasicAddWatch (OUString const&);
+ void BasicRemoveWatch ();
+ Color const & GetSyntaxBackgroundColor () const { return aSyntaxColors.GetBackgroundColor(); }
+ Color const & GetFontColor () const { return aSyntaxColors.GetFontColor(); }
+ Color const & GetSyntaxColor (TokenType eType) const { return aSyntaxColors.GetColor(eType); }
+
+protected:
+ // Window:
+ virtual void Paint (vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+ // Layout:
+ virtual void OnFirstSize (tools::Long nWidth, tools::Long nHeight) override;
+
+private:
+ // main child window
+ VclPtr<ModulWindow> pChild;
+ // dockable windows
+ VclPtr<WatchWindow> aWatchWindow;
+ VclPtr<StackWindow> aStackWindow;
+ ObjectCatalog& rObjectCatalog;
+
+ // SyntaxColors -- stores Basic syntax highlighting colors
+ class SyntaxColors : public utl::ConfigurationListener
+ {
+ public:
+ SyntaxColors ();
+ virtual ~SyntaxColors () override;
+ public:
+ void SetActiveEditor (EditorWindow* pEditor_) { pEditor = pEditor_; }
+ public:
+ Color const & GetBackgroundColor () const { return m_aBackgroundColor; };
+ Color const & GetFontColor () const { return m_aFontColor; }
+ Color const & GetColor(TokenType eType) const { return aColors[eType]; }
+
+ private:
+ virtual void ConfigurationChanged (utl::ConfigurationBroadcaster*, ConfigurationHints) override;
+ void NewConfig (bool bFirst);
+
+ private:
+ Color m_aBackgroundColor;
+ Color m_aFontColor;
+ // the color values (the indexes are TokenType, see comphelper/syntaxhighlight.hxx)
+ o3tl::enumarray<TokenType, Color> aColors;
+ // the configuration
+ svtools::ColorConfig aConfig;
+ // the active editor
+ VclPtr<EditorWindow> pEditor;
+
+ } aSyntaxColors;
+};
+
+class CodeCompleteWindow final : public InterimItemWindow
+{
+private:
+ VclPtr<EditorWindow> pParent; // parent window
+ TextSelection m_aTextSelection;
+ std::unique_ptr<weld::TreeView> m_xListBox;
+
+ /* a buffer to build up function name when typing
+ * a function name, used for showing/hiding listbox values
+ * */
+ OUStringBuffer aFuncBuffer;
+
+ void InsertSelectedEntry(); // insert the selected entry
+ void SetMatchingEntries(); // sets the visible entries based on aFuncBuffer variable
+ TextView* GetParentEditView();
+
+ DECL_LINK(ImplDoubleClickHdl, weld::TreeView&, bool);
+ DECL_LINK(ImplSelectHdl, weld::TreeView&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+
+public:
+ explicit CodeCompleteWindow( EditorWindow* pPar );
+ virtual ~CodeCompleteWindow() override;
+ virtual void dispose() override;
+
+ void InsertEntry( const OUString& aStr );
+ void ClearListBox();
+ void SetTextSelection( const TextSelection& aSel );
+ const TextSelection& GetTextSelection() const { return m_aTextSelection;}
+ void ResizeAndPositionListBox();
+ void SelectFirstEntry(); //selects first entry in ListBox
+
+ /*
+ * clears if typed anything, then hides
+ * the window, clear internal variables
+ * */
+ void ClearAndHide();
+ void HideAndRestoreFocus();
+
+ bool HandleKeyInput(const KeyEvent& rKeyEvt);
+};
+
+class UnoTypeCodeCompletetor
+{
+private:
+ css::uno::Reference< css::reflection::XIdlClass > xClass;
+ bool bCanComplete;
+
+ bool CheckField( const OUString& sFieldName );
+ bool CheckMethod( const OUString& sMethName );
+
+public:
+ UnoTypeCodeCompletetor( const std::vector< OUString >& aVect, const OUString& sVarType );
+
+ std::vector< OUString > GetXIdlClassMethods() const;
+ std::vector< OUString > GetXIdlClassFields() const;
+
+ bool CanCodeComplete() const { return bCanComplete;}
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/baside2b.cxx b/basctl/source/basicide/baside2b.cxx
new file mode 100644
index 000000000..df8196570
--- /dev/null
+++ b/basctl/source/basicide/baside2b.cxx
@@ -0,0 +1,2922 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <string_view>
+
+#include <helpids.h>
+#include <iderid.hxx>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+
+#include "baside2.hxx"
+#include "brkdlg.hxx"
+#include <basidesh.hxx>
+#include <basobj.hxx>
+#include <iderdll.hxx>
+
+#include <basic/sbmeth.hxx>
+#include <basic/sbuno.hxx>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/beans/XPropertiesChangeListener.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/script/XLibraryContainer2.hpp>
+#include <comphelper/string.hxx>
+#include <o3tl/string_view.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/progress.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <tools/debug.hxx>
+#include <utility>
+#include <vcl/image.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+#include <svl/urihelper.hxx>
+#include <svx/svxids.hrc>
+#include <vcl/commandevent.hxx>
+#include <vcl/xtextedt.hxx>
+#include <vcl/textview.hxx>
+#include <vcl/txtattr.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/taskpanelist.hxx>
+#include <vcl/help.hxx>
+#include <o3tl/string_view.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <vector>
+#include <com/sun/star/reflection/theCoreReflection.hpp>
+#include <unotools/charclass.hxx>
+#include <o3tl/string_view.hxx>
+#include "textwindowpeer.hxx"
+#include "uiobject.hxx"
+
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+sal_uInt16 const NoMarker = 0xFFFF;
+tools::Long const nBasePad = 2;
+tools::Long const nCursorPad = 5;
+
+tools::Long nVirtToolBoxHeight; // inited in WatchWindow, used in Stackwindow
+
+// Returns pBase converted to SbxVariable if valid and is not an SbxMethod.
+SbxVariable* IsSbxVariable (SbxBase* pBase)
+{
+ if (SbxVariable* pVar = dynamic_cast<SbxVariable*>(pBase))
+ if (!dynamic_cast<SbxMethod*>(pVar))
+ return pVar;
+ return nullptr;
+}
+
+Image GetImage(const OUString& rId)
+{
+ return Image(StockImage::Yes, rId);
+}
+
+int const nScrollLine = 12;
+int const nScrollPage = 60;
+int const DWBORDER = 3;
+
+std::u16string_view const cSuffixes = u"%&!#@$";
+
+} // namespace
+
+
+/**
+ * Helper functions to get/set text in TextEngine using
+ * the stream interface.
+ *
+ * get/setText() only supports tools Strings limited to 64K).
+ */
+OUString getTextEngineText (ExtTextEngine& rEngine)
+{
+ SvMemoryStream aMemStream;
+ aMemStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 );
+ aMemStream.SetLineDelimiter( LINEEND_LF );
+ rEngine.Write( aMemStream );
+ std::size_t nSize = aMemStream.Tell();
+ OUString aText( static_cast<const char*>(aMemStream.GetData()),
+ nSize, RTL_TEXTENCODING_UTF8 );
+ return aText;
+}
+
+void setTextEngineText (ExtTextEngine& rEngine, std::u16string_view aStr)
+{
+ rEngine.SetText(OUString());
+ OString aUTF8Str = OUStringToOString( aStr, RTL_TEXTENCODING_UTF8 );
+ SvMemoryStream aMemStream( const_cast<char *>(aUTF8Str.getStr()), aUTF8Str.getLength(),
+ StreamMode::READ );
+ aMemStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 );
+ aMemStream.SetLineDelimiter( LINEEND_LF );
+ rEngine.Read(aMemStream);
+}
+
+namespace
+{
+
+void lcl_DrawIDEWindowFrame(DockingWindow const * pWin, vcl::RenderContext& rRenderContext)
+{
+ if (pWin->IsFloatingMode())
+ return;
+
+ Size aSz(pWin->GetOutputSizePixel());
+ const Color aOldLineColor(rRenderContext.GetLineColor());
+ rRenderContext.SetLineColor(COL_WHITE);
+ // White line on top
+ rRenderContext.DrawLine(Point(0, 0), Point(aSz.Width(), 0));
+ // Black line at bottom
+ rRenderContext.SetLineColor(COL_BLACK);
+ rRenderContext.DrawLine(Point(0, aSz.Height() - 1),
+ Point(aSz.Width(), aSz.Height() - 1));
+ rRenderContext.SetLineColor(aOldLineColor);
+}
+
+void lcl_SeparateNameAndIndex( const OUString& rVName, OUString& rVar, OUString& rIndex )
+{
+ rVar = rVName;
+ rIndex.clear();
+ sal_Int32 nIndexStart = rVar.indexOf( '(' );
+ if ( nIndexStart != -1 )
+ {
+ sal_Int32 nIndexEnd = rVar.indexOf( ')', nIndexStart );
+ if (nIndexEnd != -1)
+ {
+ rIndex = rVar.copy(nIndexStart + 1, nIndexEnd - nIndexStart - 1);
+ rVar = rVar.copy(0, nIndexStart);
+ rVar = comphelper::string::stripEnd(rVar, ' ');
+ rIndex = comphelper::string::strip(rIndex, ' ');
+ }
+ }
+
+ if ( !rVar.isEmpty() )
+ {
+ sal_uInt16 nLastChar = rVar.getLength()-1;
+ if ( cSuffixes.find(rVar[ nLastChar ] ) != std::u16string_view::npos )
+ rVar = rVar.replaceAt( nLastChar, 1, u"" );
+ }
+ if ( !rIndex.isEmpty() )
+ {
+ sal_uInt16 nLastChar = rIndex.getLength()-1;
+ if ( cSuffixes.find(rIndex[ nLastChar ] ) != std::u16string_view::npos )
+ rIndex = rIndex.replaceAt( nLastChar, 1, u"" );
+ }
+}
+
+} // namespace
+
+
+// EditorWindow
+
+
+class EditorWindow::ChangesListener:
+ public cppu::WeakImplHelper< beans::XPropertiesChangeListener >
+{
+public:
+ explicit ChangesListener(EditorWindow & editor): editor_(editor) {}
+
+private:
+ virtual ~ChangesListener() override {}
+
+ virtual void SAL_CALL disposing(lang::EventObject const &) override
+ {
+ std::unique_lock g(editor_.mutex_);
+ editor_.notifier_.clear();
+ }
+
+ virtual void SAL_CALL propertiesChange(
+ Sequence< beans::PropertyChangeEvent > const &) override
+ {
+ SolarMutexGuard g;
+ editor_.ImplSetFont();
+ }
+
+ EditorWindow & editor_;
+};
+
+class EditorWindow::ProgressInfo : public SfxProgress
+{
+public:
+ ProgressInfo (SfxObjectShell* pObjSh, OUString const& rText, sal_uInt32 nRange) :
+ SfxProgress(pObjSh, rText, nRange),
+ nCurState(0)
+ { }
+
+ void StepProgress ()
+ {
+ SetState(++nCurState);
+ }
+
+private:
+ sal_uLong nCurState;
+};
+
+EditorWindow::EditorWindow (vcl::Window* pParent, ModulWindow* pModulWindow) :
+ Window(pParent, WB_BORDER),
+ rModulWindow(*pModulWindow),
+ nCurTextWidth(0),
+ m_nSetSourceInBasicId(nullptr),
+ aHighlighter(HighlighterLanguage::Basic),
+ aSyntaxIdle( "basctl EditorWindow aSyntaxIdle" ),
+ bHighlighting(false),
+ bDoSyntaxHighlight(true),
+ bDelayHighlight(true),
+ pCodeCompleteWnd(VclPtr<CodeCompleteWindow>::Create(this))
+{
+ set_id("EditorWindow");
+ SetBackground(Wallpaper(rModulWindow.GetLayout().GetSyntaxBackgroundColor()));
+ SetPointer( PointerStyle::Text );
+ SetHelpId( HID_BASICIDE_EDITORWINDOW );
+
+ listener_ = new ChangesListener(*this);
+ Reference< beans::XMultiPropertySet > n(
+ officecfg::Office::Common::Font::SourceViewFont::get(),
+ UNO_QUERY_THROW);
+ {
+ std::unique_lock g(mutex_);
+ notifier_ = n;
+ }
+ const Sequence<OUString> aPropertyNames{"FontHeight", "FontName"};
+ n->addPropertiesChangeListener(aPropertyNames, listener_);
+}
+
+
+EditorWindow::~EditorWindow()
+{
+ disposeOnce();
+}
+
+void EditorWindow::dispose()
+{
+ if (m_nSetSourceInBasicId)
+ {
+ Application::RemoveUserEvent(m_nSetSourceInBasicId);
+ m_nSetSourceInBasicId = nullptr;
+ }
+
+ Reference< beans::XMultiPropertySet > n;
+ {
+ std::unique_lock g(mutex_);
+ n = notifier_;
+ }
+ if (n.is()) {
+ n->removePropertiesChangeListener(listener_);
+ }
+
+ aSyntaxIdle.Stop();
+
+ if ( pEditEngine )
+ {
+ EndListening( *pEditEngine );
+ pEditEngine->RemoveView(pEditView.get());
+ }
+ pCodeCompleteWnd.disposeAndClear();
+ vcl::Window::dispose();
+}
+
+OUString EditorWindow::GetWordAtCursor()
+{
+ OUString aWord;
+
+ if ( pEditView )
+ {
+ TextEngine* pTextEngine = pEditView->GetTextEngine();
+ if ( pTextEngine )
+ {
+ // check first, if the cursor is at a help URL
+ const TextSelection& rSelection = pEditView->GetSelection();
+ const TextPaM& rSelStart = rSelection.GetStart();
+ const TextPaM& rSelEnd = rSelection.GetEnd();
+ OUString aText = pTextEngine->GetText( rSelEnd.GetPara() );
+ CharClass aClass( ::comphelper::getProcessComponentContext() , Application::GetSettings().GetLanguageTag() );
+ sal_Int32 nSelStart = rSelStart.GetIndex();
+ sal_Int32 nSelEnd = rSelEnd.GetIndex();
+ sal_Int32 nLength = aText.getLength();
+ sal_Int32 nStart = 0;
+ sal_Int32 nEnd = nLength;
+ while ( nStart < nLength )
+ {
+ OUString aURL( URIHelper::FindFirstURLInText( aText, nStart, nEnd, aClass ) );
+ INetURLObject aURLObj( aURL );
+ if ( aURLObj.GetProtocol() == INetProtocol::VndSunStarHelp
+ && nSelStart >= nStart && nSelStart <= nEnd && nSelEnd >= nStart && nSelEnd <= nEnd )
+ {
+ aWord = aURL;
+ break;
+ }
+ nStart = nEnd;
+ nEnd = nLength;
+ }
+
+ // Not the selected range, but at the CursorPosition,
+ // if a word is partially selected.
+ if ( aWord.isEmpty() )
+ aWord = pTextEngine->GetWord( rSelEnd );
+
+ // Can be empty when full word selected, as Cursor behind it
+ if ( aWord.isEmpty() && pEditView->HasSelection() )
+ aWord = pTextEngine->GetWord( rSelStart );
+ }
+ }
+
+ return aWord;
+}
+
+void EditorWindow::RequestHelp( const HelpEvent& rHEvt )
+{
+ bool bDone = false;
+
+ // Should have been activated at some point
+ if ( pEditEngine )
+ {
+ if ( rHEvt.GetMode() & HelpEventMode::CONTEXT )
+ {
+ OUString aKeyword = GetWordAtCursor();
+ Application::GetHelp()->SearchKeyword( aKeyword );
+ bDone = true;
+ }
+ else if ( rHEvt.GetMode() & HelpEventMode::QUICK )
+ {
+ OUString aHelpText;
+ tools::Rectangle aHelpRect;
+ if ( StarBASIC::IsRunning() )
+ {
+ Point aWindowPos = rHEvt.GetMousePosPixel();
+ aWindowPos = ScreenToOutputPixel( aWindowPos );
+ Point aDocPos = GetEditView()->GetDocPos( aWindowPos );
+ TextPaM aCursor = GetEditView()->GetTextEngine()->GetPaM(aDocPos);
+ TextPaM aStartOfWord;
+ OUString aWord = GetEditView()->GetTextEngine()->GetWord( aCursor, &aStartOfWord );
+ if ( !aWord.isEmpty() && !comphelper::string::isdigitAsciiString(aWord) )
+ {
+ sal_uInt16 nLastChar = aWord.getLength() - 1;
+ if ( cSuffixes.find(aWord[ nLastChar ] ) != std::u16string_view::npos )
+ aWord = aWord.replaceAt( nLastChar, 1, u"" );
+ SbxBase* pSBX = StarBASIC::FindSBXInCurrentScope( aWord );
+ if (SbxVariable const* pVar = IsSbxVariable(pSBX))
+ {
+ SbxDataType eType = pVar->GetType();
+ if ( static_cast<sal_uInt8>(eType) == sal_uInt8(SbxOBJECT) )
+ // might cause a crash e. g. at the selections-object
+ // Type == Object does not mean pVar == Object!
+ ; // aHelpText = ((SbxObject*)pVar)->GetClassName();
+ else if ( eType & SbxARRAY )
+ ; // aHelpText = "{...}";
+ else if ( static_cast<sal_uInt8>(eType) != sal_uInt8(SbxEMPTY) )
+ {
+ aHelpText = pVar->GetName();
+ if ( aHelpText.isEmpty() ) // name is not copied with the passed parameters
+ aHelpText = aWord;
+ aHelpText += "=" + pVar->GetOUString();
+ }
+ }
+ if ( !aHelpText.isEmpty() )
+ {
+ tools::Rectangle aStartWordRect(GetEditView()->GetTextEngine()->PaMtoEditCursor(aStartOfWord));
+ TextPaM aEndOfWord(aStartOfWord.GetPara(), aStartOfWord.GetIndex() + aWord.getLength());
+ tools::Rectangle aEndWordRect(GetEditView()->GetTextEngine()->PaMtoEditCursor(aEndOfWord));
+ aHelpRect = aStartWordRect.GetUnion(aEndWordRect);
+
+ Point aTopLeft = GetEditView()->GetWindowPos(aHelpRect.TopLeft());
+ aTopLeft = GetEditView()->GetWindow()->OutputToScreenPixel(aTopLeft);
+
+ aHelpRect.SetPos(aTopLeft);
+ }
+ }
+ }
+ Help::ShowQuickHelp( this, aHelpRect, aHelpText, QuickHelpFlags::NONE);
+ bDone = true;
+ }
+ }
+
+ if ( !bDone )
+ Window::RequestHelp( rHEvt );
+}
+
+
+void EditorWindow::Resize()
+{
+ // ScrollBars, etc. happens in Adjust...
+ if ( !pEditView )
+ return;
+
+ tools::Long nVisY = pEditView->GetStartDocPos().Y();
+
+ pEditView->ShowCursor();
+ Size aOutSz( GetOutputSizePixel() );
+ tools::Long nMaxVisAreaStart = pEditView->GetTextEngine()->GetTextHeight() - aOutSz.Height();
+ if ( nMaxVisAreaStart < 0 )
+ nMaxVisAreaStart = 0;
+ if ( pEditView->GetStartDocPos().Y() > nMaxVisAreaStart )
+ {
+ Point aStartDocPos( pEditView->GetStartDocPos() );
+ aStartDocPos.setY( nMaxVisAreaStart );
+ pEditView->SetStartDocPos( aStartDocPos );
+ pEditView->ShowCursor();
+ rModulWindow.GetBreakPointWindow().GetCurYOffset() = aStartDocPos.Y();
+ rModulWindow.GetLineNumberWindow().GetCurYOffset() = aStartDocPos.Y();
+ }
+ InitScrollBars();
+ if ( nVisY != pEditView->GetStartDocPos().Y() )
+ Invalidate();
+}
+
+
+void EditorWindow::MouseMove( const MouseEvent &rEvt )
+{
+ if ( pEditView )
+ pEditView->MouseMove( rEvt );
+}
+
+
+void EditorWindow::MouseButtonUp( const MouseEvent &rEvt )
+{
+ if ( pEditView )
+ {
+ pEditView->MouseButtonUp( rEvt );
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate( SID_BASICIDE_STAT_POS );
+ pBindings->Invalidate( SID_BASICIDE_STAT_TITLE );
+ }
+ }
+}
+
+void EditorWindow::MouseButtonDown( const MouseEvent &rEvt )
+{
+ GrabFocus();
+ if (!pEditView)
+ return;
+ pEditView->MouseButtonDown(rEvt);
+ if( pCodeCompleteWnd->IsVisible() )
+ {
+ if (pEditView->GetSelection() != pCodeCompleteWnd->GetTextSelection())
+ {
+ //selection changed, code complete window should be hidden
+ pCodeCompleteWnd->HideAndRestoreFocus();
+ }
+ }
+}
+
+void EditorWindow::Command( const CommandEvent& rCEvt )
+{
+ if ( !pEditView )
+ return;
+
+ pEditView->Command( rCEvt );
+ if ( ( rCEvt.GetCommand() == CommandEventId::Wheel ) ||
+ ( rCEvt.GetCommand() == CommandEventId::StartAutoScroll ) ||
+ ( rCEvt.GetCommand() == CommandEventId::AutoScroll ) )
+ {
+ HandleScrollCommand( rCEvt, rModulWindow.GetHScrollBar(), &rModulWindow.GetEditVScrollBar() );
+ } else if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) {
+ SfxDispatcher* pDispatcher = GetDispatcher();
+ if ( pDispatcher )
+ {
+ SfxDispatcher::ExecutePopup();
+ }
+ if( pCodeCompleteWnd->IsVisible() ) // hide the code complete window
+ pCodeCompleteWnd->ClearAndHide();
+ }
+}
+
+bool EditorWindow::ImpCanModify()
+{
+ bool bCanModify = true;
+ if ( StarBASIC::IsRunning() && rModulWindow.GetBasicStatus().bIsRunning )
+ {
+ // If in Trace-mode, abort the trace or refuse input
+ // Remove markers in the modules in Notify at Basic::Stopped
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Question, VclButtonsType::OkCancel,
+ IDEResId(RID_STR_WILLSTOPPRG)));
+ if (xQueryBox->run() == RET_OK)
+ {
+ rModulWindow.GetBasicStatus().bIsRunning = false;
+ StopBasic();
+ }
+ else
+ bCanModify = false;
+ }
+ return bCanModify;
+}
+
+void EditorWindow::KeyInput( const KeyEvent& rKEvt )
+{
+ if ( !pEditView ) // Happens in Win95
+ return;
+
+ bool const bWasModified = pEditEngine->IsModified();
+ // see if there is an accelerator to be processed first
+ SfxViewShell *pVS( SfxViewShell::Current());
+ bool bDone = pVS && pVS->KeyInput( rKEvt );
+
+ if (pCodeCompleteWnd->IsVisible() && CodeCompleteOptions::IsCodeCompleteOn())
+ {
+ if (pCodeCompleteWnd->HandleKeyInput(rKEvt))
+ return;
+ }
+
+ if( (rKEvt.GetKeyCode().GetCode() == KEY_SPACE ||
+ rKEvt.GetKeyCode().GetCode() == KEY_TAB ||
+ rKEvt.GetKeyCode().GetCode() == KEY_RETURN ) && CodeCompleteOptions::IsAutoCorrectOn() )
+ {
+ HandleAutoCorrect();
+ }
+
+ if( rKEvt.GetCharCode() == '"' && CodeCompleteOptions::IsAutoCloseQuotesOn() )
+ {//autoclose double quotes
+ HandleAutoCloseDoubleQuotes();
+ }
+
+ if( rKEvt.GetCharCode() == '(' && CodeCompleteOptions::IsAutoCloseParenthesisOn() )
+ {//autoclose parenthesis
+ HandleAutoCloseParen();
+ }
+
+ if( rKEvt.GetKeyCode().GetCode() == KEY_RETURN && CodeCompleteOptions::IsProcedureAutoCompleteOn() )
+ {//autoclose implementation
+ HandleProcedureCompletion();
+ }
+
+ if( rKEvt.GetKeyCode().GetCode() == KEY_POINT && CodeCompleteOptions::IsCodeCompleteOn() )
+ {
+ HandleCodeCompletion();
+ }
+ if ( !bDone && ( !TextEngine::DoesKeyChangeText( rKEvt ) || ImpCanModify() ) )
+ {
+ if ( ( rKEvt.GetKeyCode().GetCode() == KEY_TAB ) && !rKEvt.GetKeyCode().IsMod1() &&
+ !rKEvt.GetKeyCode().IsMod2() && !GetEditView()->IsReadOnly() )
+ {
+ TextSelection aSel( pEditView->GetSelection() );
+ if ( aSel.GetStart().GetPara() != aSel.GetEnd().GetPara() )
+ {
+ bDelayHighlight = false;
+ if ( !rKEvt.GetKeyCode().IsShift() )
+ pEditView->IndentBlock();
+ else
+ pEditView->UnindentBlock();
+ bDelayHighlight = true;
+ bDone = true;
+ }
+ }
+ if ( !bDone )
+ bDone = pEditView->KeyInput( rKEvt );
+ }
+ if ( !bDone )
+ {
+ Window::KeyInput( rKEvt );
+ }
+ else
+ {
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate( SID_BASICIDE_STAT_POS );
+ pBindings->Invalidate( SID_BASICIDE_STAT_TITLE );
+ if ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_CURSOR )
+ {
+ pBindings->Update( SID_BASICIDE_STAT_POS );
+ pBindings->Update( SID_BASICIDE_STAT_TITLE );
+ }
+ if ( !bWasModified && pEditEngine->IsModified() )
+ {
+ pBindings->Invalidate( SID_SAVEDOC );
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+ pBindings->Invalidate( SID_UNDO );
+ }
+ if ( rKEvt.GetKeyCode().GetCode() == KEY_INSERT )
+ pBindings->Invalidate( SID_ATTR_INSERT );
+ }
+ }
+}
+
+void EditorWindow::HandleAutoCorrect()
+{
+ TextSelection aSel = GetEditView()->GetSelection();
+ const sal_uInt32 nLine = aSel.GetStart().GetPara();
+ const sal_Int32 nIndex = aSel.GetStart().GetIndex();
+ OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
+ const OUString& sActSubName = GetActualSubName( nLine ); // the actual procedure
+
+ std::vector<HighlightPortion> aPortions;
+ aHighlighter.getHighlightPortions( aLine, aPortions );
+
+ if( aPortions.empty() )
+ return;
+
+ HighlightPortion& r = aPortions.back();
+ if( static_cast<size_t>(nIndex) != aPortions.size()-1 )
+ {//cursor is not standing at the end of the line
+ for (auto const& portion : aPortions)
+ {
+ if( portion.nEnd == nIndex )
+ {
+ r = portion;
+ break;
+ }
+ }
+ }
+
+ OUString sStr = aLine.copy( r.nBegin, r.nEnd - r.nBegin );
+ //if WS or empty string: stop, nothing to do
+ if( ( r.tokenType == TokenType::Whitespace ) || sStr.isEmpty() )
+ return;
+ //create the appropriate TextSelection, and update the cache
+ TextPaM aStart( nLine, r.nBegin );
+ TextPaM aEnd( nLine, r.nBegin + sStr.getLength() );
+ TextSelection sTextSelection( aStart, aEnd );
+ rModulWindow.UpdateModule();
+ rModulWindow.GetSbModule()->GetCodeCompleteDataFromParse( aCodeCompleteCache );
+ // correct the last entered keyword
+ if( r.tokenType == TokenType::Keywords )
+ {
+ sStr = sStr.toAsciiLowerCase();
+ if( !SbModule::GetKeywordCase(sStr).isEmpty() )
+ // if it is a keyword, get its correct case
+ sStr = SbModule::GetKeywordCase(sStr);
+ else
+ // else capitalize first letter/select the correct one, and replace
+ sStr = sStr.replaceAt( 0, 1, OUString(sStr[0]).toAsciiUpperCase() );
+
+ pEditEngine->ReplaceText( sTextSelection, sStr );
+ pEditView->SetSelection( aSel );
+ }
+ if( r.tokenType != TokenType::Identifier )
+ return;
+
+// correct variables
+ if( !aCodeCompleteCache.GetCorrectCaseVarName( sStr, sActSubName ).isEmpty() )
+ {
+ sStr = aCodeCompleteCache.GetCorrectCaseVarName( sStr, sActSubName );
+ pEditEngine->ReplaceText( sTextSelection, sStr );
+ pEditView->SetSelection( aSel );
+ }
+ else
+ {
+ //autocorrect procedures
+ SbxArray* pArr = rModulWindow.GetSbModule()->GetMethods().get();
+ for (sal_uInt32 i = 0; i < pArr->Count(); ++i)
+ {
+ if (pArr->Get(i)->GetName().equalsIgnoreAsciiCase(sStr))
+ {
+ sStr = pArr->Get(i)->GetName(); //if found, get the correct case
+ pEditEngine->ReplaceText( sTextSelection, sStr );
+ pEditView->SetSelection( aSel );
+ return;
+ }
+ }
+ }
+}
+
+TextSelection EditorWindow::GetLastHighlightPortionTextSelection() const
+{//creates a text selection from the highlight portion on the cursor
+ const sal_uInt32 nLine = GetEditView()->GetSelection().GetStart().GetPara();
+ const sal_Int32 nIndex = GetEditView()->GetSelection().GetStart().GetIndex();
+ OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
+ std::vector<HighlightPortion> aPortions;
+ aHighlighter.getHighlightPortions( aLine, aPortions );
+
+ assert(!aPortions.empty());
+ HighlightPortion& r = aPortions.back();
+ if( static_cast<size_t>(nIndex) != aPortions.size()-1 )
+ {//cursor is not standing at the end of the line
+ for (auto const& portion : aPortions)
+ {
+ if( portion.nEnd == nIndex )
+ {
+ r = portion;
+ break;
+ }
+ }
+ }
+
+ if( aPortions.empty() )
+ return TextSelection();
+
+ OUString sStr = aLine.copy( r.nBegin, r.nEnd - r.nBegin );
+ TextPaM aStart( nLine, r.nBegin );
+ TextPaM aEnd( nLine, r.nBegin + sStr.getLength() );
+ return TextSelection( aStart, aEnd );
+}
+
+void EditorWindow::HandleAutoCloseParen()
+{
+ TextSelection aSel = GetEditView()->GetSelection();
+ const sal_uInt32 nLine = aSel.GetStart().GetPara();
+ OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
+
+ if( aLine.getLength() > 0 && aLine[aSel.GetEnd().GetIndex()-1] != '(' )
+ {
+ GetEditView()->InsertText(")");
+ //leave the cursor on its place: inside the parenthesis
+ TextPaM aEnd(nLine, aSel.GetEnd().GetIndex());
+ GetEditView()->SetSelection( TextSelection( aEnd, aEnd ) );
+ }
+}
+
+void EditorWindow::HandleAutoCloseDoubleQuotes()
+{
+ TextSelection aSel = GetEditView()->GetSelection();
+ const sal_uInt32 nLine = aSel.GetStart().GetPara();
+ OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
+
+ std::vector<HighlightPortion> aPortions;
+ aHighlighter.getHighlightPortions( aLine, aPortions );
+
+ if( aPortions.empty() )
+ return;
+
+ if( aLine.getLength() > 0 && !aLine.endsWith("\"") && (aPortions.back().tokenType != TokenType::String) )
+ {
+ GetEditView()->InsertText("\"");
+ //leave the cursor on its place: inside the two double quotes
+ TextPaM aEnd(nLine, aSel.GetEnd().GetIndex());
+ GetEditView()->SetSelection( TextSelection( aEnd, aEnd ) );
+ }
+}
+
+void EditorWindow::HandleProcedureCompletion()
+{
+
+ TextSelection aSel = GetEditView()->GetSelection();
+ const sal_uInt32 nLine = aSel.GetStart().GetPara();
+ OUString aLine( pEditEngine->GetText( nLine ) );
+
+ OUString sProcType;
+ OUString sProcName;
+ bool bFoundName = GetProcedureName(aLine, sProcType, sProcName);
+ if (!bFoundName)
+ return;
+
+ OUString sText("\nEnd ");
+ aSel = GetEditView()->GetSelection();
+ if( sProcType.equalsIgnoreAsciiCase("function") )
+ sText += "Function\n";
+ if( sProcType.equalsIgnoreAsciiCase("sub") )
+ sText += "Sub\n";
+
+ if( nLine+1 == pEditEngine->GetParagraphCount() )
+ {
+ pEditView->InsertText( sText );//append to the end
+ GetEditView()->SetSelection(aSel);
+ }
+ else
+ {
+ for( sal_uInt32 i = nLine+1; i < pEditEngine->GetParagraphCount(); ++i )
+ {//searching forward for end token, or another sub/function definition
+ OUString aCurrLine = pEditEngine->GetText( i );
+ std::vector<HighlightPortion> aCurrPortions;
+ aHighlighter.getHighlightPortions( aCurrLine, aCurrPortions );
+
+ if( aCurrPortions.size() >= 3 )
+ {//at least 3 tokens: (sub|function) whitespace identifier...
+ HighlightPortion& r = aCurrPortions.front();
+ std::u16string_view sStr = aCurrLine.subView(r.nBegin, r.nEnd - r.nBegin);
+
+ if( r.tokenType == TokenType::Keywords )
+ {
+ if( o3tl::equalsIgnoreAsciiCase(sStr, u"sub") || o3tl::equalsIgnoreAsciiCase(sStr, u"function") )
+ {
+ pEditView->InsertText( sText );//append to the end
+ GetEditView()->SetSelection(aSel);
+ break;
+ }
+ if( o3tl::equalsIgnoreAsciiCase(sStr, u"end") )
+ break;
+ }
+ }
+ }
+ }
+}
+
+bool EditorWindow::GetProcedureName(std::u16string_view rLine, OUString& rProcType, OUString& rProcName) const
+{
+ std::vector<HighlightPortion> aPortions;
+ aHighlighter.getHighlightPortions(rLine, aPortions);
+
+ if( aPortions.empty() )
+ return false;
+
+ bool bFoundType = false;
+ bool bFoundName = false;
+
+ for (auto const& portion : aPortions)
+ {
+ std::u16string_view sTokStr = rLine.substr(portion.nBegin, portion.nEnd - portion.nBegin);
+
+ if( portion.tokenType == TokenType::Keywords && ( o3tl::equalsIgnoreAsciiCase(sTokStr, u"sub")
+ || o3tl::equalsIgnoreAsciiCase(sTokStr, u"function")) )
+ {
+ rProcType = sTokStr;
+ bFoundType = true;
+ }
+ if( portion.tokenType == TokenType::Identifier && bFoundType )
+ {
+ rProcName = sTokStr;
+ bFoundName = true;
+ break;
+ }
+ }
+
+ if( !bFoundType || !bFoundName )
+ return false;// no sub/function keyword or there is no identifier
+
+ return true;
+
+}
+
+void EditorWindow::HandleCodeCompletion()
+{
+ rModulWindow.UpdateModule();
+ rModulWindow.GetSbModule()->GetCodeCompleteDataFromParse(aCodeCompleteCache);
+ TextSelection aSel = GetEditView()->GetSelection();
+ const sal_uInt32 nLine = aSel.GetStart().GetPara();
+ OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
+ std::vector< OUString > aVect; //vector to hold the base variable+methods for the nested reflection
+
+ std::vector<HighlightPortion> aPortions;
+ aLine = aLine.copy(0, aSel.GetEnd().GetIndex());
+ aHighlighter.getHighlightPortions( aLine, aPortions );
+ if( aPortions.empty() )
+ return;
+
+ //use the syntax highlighter to grab out nested reflection calls, eg. aVar.aMethod("aa").aOtherMethod ..
+ for( std::vector<HighlightPortion>::reverse_iterator i(
+ aPortions.rbegin());
+ i != aPortions.rend(); ++i)
+ {
+ if( i->tokenType == TokenType::Whitespace ) // a whitespace: stop; if there is no ws, it goes to the beginning of the line
+ break;
+ if( i->tokenType == TokenType::Identifier || i->tokenType == TokenType::Keywords ) // extract the identifiers(methods, base variable)
+ /* an example: Dim aLocVar2 as com.sun.star.beans.PropertyValue
+ * here, aLocVar2.Name, and PropertyValue's Name field is treated as a keyword(?!)
+ * */
+ aVect.insert( aVect.begin(), aLine.copy(i->nBegin, i->nEnd - i->nBegin) );
+ }
+
+ if( aVect.empty() )//nothing to do
+ return;
+
+ OUString sBaseName = aVect[aVect.size()-1];//variable name
+ OUString sVarType = aCodeCompleteCache.GetVarType( sBaseName );
+
+ if( !sVarType.isEmpty() && CodeCompleteOptions::IsAutoCorrectOn() )
+ {//correct variable name, if autocorrection on
+ const OUString& sStr = aCodeCompleteCache.GetCorrectCaseVarName( sBaseName, GetActualSubName(nLine) );
+ if( !sStr.isEmpty() )
+ {
+ TextPaM aStart(nLine, aSel.GetStart().GetIndex() - sStr.getLength() );
+ TextSelection sTextSelection(aStart, TextPaM(nLine, aSel.GetStart().GetIndex()));
+ pEditEngine->ReplaceText( sTextSelection, sStr );
+ pEditView->SetSelection( aSel );
+ }
+ }
+
+ UnoTypeCodeCompletetor aTypeCompletor( aVect, sVarType );
+
+ if( !aTypeCompletor.CanCodeComplete() )
+ return;
+
+ std::vector< OUString > aEntryVect;//entries to be inserted into the list
+ std::vector< OUString > aFieldVect = aTypeCompletor.GetXIdlClassFields();//fields
+ aEntryVect.insert(aEntryVect.end(), aFieldVect.begin(), aFieldVect.end() );
+ if( CodeCompleteOptions::IsExtendedTypeDeclaration() )
+ {// if extended types on, reflect classes, else just the structs (XIdlClass without methods)
+ std::vector< OUString > aMethVect = aTypeCompletor.GetXIdlClassMethods();//methods
+ aEntryVect.insert(aEntryVect.end(), aMethVect.begin(), aMethVect.end() );
+ }
+ if( !aEntryVect.empty() )
+ SetupAndShowCodeCompleteWnd( aEntryVect, aSel );
+}
+
+void EditorWindow::SetupAndShowCodeCompleteWnd( const std::vector< OUString >& aEntryVect, TextSelection aSel )
+{
+ // clear the listbox
+ pCodeCompleteWnd->ClearListBox();
+ // fill the listbox
+ for(const auto & l : aEntryVect)
+ {
+ pCodeCompleteWnd->InsertEntry( l );
+ }
+ // show it
+ pCodeCompleteWnd->Show();
+ pCodeCompleteWnd->ResizeAndPositionListBox();
+ pCodeCompleteWnd->SelectFirstEntry();
+ // correct text selection, and set it
+ ++aSel.GetStart().GetIndex();
+ ++aSel.GetEnd().GetIndex();
+ pCodeCompleteWnd->SetTextSelection( aSel );
+ //give the focus to the EditView
+ pEditView->GetWindow()->GrabFocus();
+}
+
+void EditorWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ if (!pEditEngine) // We need it now at latest
+ CreateEditEngine();
+
+ pEditView->Paint(rRenderContext, rRect);
+}
+
+void EditorWindow::LoseFocus()
+{
+ // tdf#114258 wait until the next event loop cycle to do this so it doesn't
+ // happen during a mouse down/up selection in the treeview whose contents
+ // this may update
+ if (!m_nSetSourceInBasicId)
+ m_nSetSourceInBasicId = Application::PostUserEvent(LINK(this, EditorWindow, SetSourceInBasicHdl));
+ Window::LoseFocus();
+}
+
+IMPL_LINK_NOARG(EditorWindow, SetSourceInBasicHdl, void*, void)
+{
+ m_nSetSourceInBasicId = nullptr;
+ SetSourceInBasic();
+}
+
+void EditorWindow::SetSourceInBasic()
+{
+ if ( pEditEngine && pEditEngine->IsModified()
+ && !GetEditView()->IsReadOnly() ) // Added for #i60626, otherwise
+ // any read only bug in the text engine could lead to a crash later
+ {
+ if ( !StarBASIC::IsRunning() ) // Not at runtime!
+ {
+ rModulWindow.UpdateModule();
+ }
+ }
+}
+
+// Returns the position of the last character of any of the following
+// EOL char combinations: CR, CR/LF, LF, return -1 if no EOL is found
+sal_Int32 searchEOL( std::u16string_view rStr, sal_Int32 fromIndex )
+{
+ size_t iLF = rStr.find( LINE_SEP, fromIndex );
+ if( iLF != std::u16string_view::npos )
+ return iLF;
+
+ size_t iCR = rStr.find( LINE_SEP_CR, fromIndex );
+ return iCR == std::u16string_view::npos ? -1 : iCR;
+}
+
+void EditorWindow::CreateEditEngine()
+{
+ if (pEditEngine)
+ return;
+
+ pEditEngine.reset(new ExtTextEngine);
+ pEditView.reset(new TextView(pEditEngine.get(), this));
+ pEditView->SetAutoIndentMode(true);
+ pEditEngine->SetUpdateMode(false);
+ pEditEngine->InsertView(pEditView.get());
+
+ ImplSetFont();
+
+ aSyntaxIdle.SetInvokeHandler( LINK( this, EditorWindow, SyntaxTimerHdl ) );
+
+ bool bWasDoSyntaxHighlight = bDoSyntaxHighlight;
+ bDoSyntaxHighlight = false; // too slow for large texts...
+ OUString aOUSource(rModulWindow.GetModule());
+ sal_Int32 nLines = 0;
+ sal_Int32 nIndex = -1;
+ do
+ {
+ nLines++;
+ nIndex = searchEOL( aOUSource, nIndex+1 );
+ }
+ while (nIndex >= 0);
+
+ // nLines*4: SetText+Formatting+DoHighlight+Formatting
+ // it could be cut down on one formatting but you would wait even longer
+ // for the text then if the source code is long...
+ pProgress.reset(new ProgressInfo(GetShell()->GetViewFrame()->GetObjectShell(),
+ IDEResId(RID_STR_GENERATESOURCE),
+ nLines * 4));
+ setTextEngineText(*pEditEngine, aOUSource);
+
+ pEditView->SetStartDocPos(Point(0, 0));
+ pEditView->SetSelection(TextSelection());
+ rModulWindow.GetBreakPointWindow().GetCurYOffset() = 0;
+ rModulWindow.GetLineNumberWindow().GetCurYOffset() = 0;
+ pEditEngine->SetUpdateMode(true);
+ rModulWindow.PaintImmediately(); // has only been invalidated at UpdateMode = true
+
+ pEditView->ShowCursor();
+
+ StartListening(*pEditEngine);
+
+ aSyntaxIdle.Stop();
+ bDoSyntaxHighlight = bWasDoSyntaxHighlight;
+
+ for (sal_Int32 nLine = 0; nLine < nLines; nLine++)
+ aSyntaxLineTable.insert(nLine);
+ ForceSyntaxTimeout();
+
+ pProgress.reset();
+
+ pEditEngine->SetModified( false );
+ pEditEngine->EnableUndo( true );
+
+ InitScrollBars();
+
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate(SID_BASICIDE_STAT_POS);
+ pBindings->Invalidate(SID_BASICIDE_STAT_TITLE);
+ }
+
+ DBG_ASSERT(rModulWindow.GetBreakPointWindow().GetCurYOffset() == 0, "CreateEditEngine: breakpoints moved?");
+
+ // set readonly mode for readonly libraries
+ ScriptDocument aDocument(rModulWindow.GetDocument());
+ OUString aOULibName(rModulWindow.GetLibName());
+ Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ if (xModLibContainer.is()
+ && xModLibContainer->hasByName(aOULibName)
+ && xModLibContainer->isLibraryReadOnly(aOULibName))
+ {
+ rModulWindow.SetReadOnly(true);
+ }
+
+ if (aDocument.isDocument() && aDocument.isReadOnly())
+ rModulWindow.SetReadOnly(true);
+}
+
+void EditorWindow::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
+{
+ TextHint const* pTextHint = dynamic_cast<TextHint const*>(&rHint);
+ if (!pTextHint)
+ return;
+
+ TextHint const& rTextHint = *pTextHint;
+ if( rTextHint.GetId() == SfxHintId::TextViewScrolled )
+ {
+ if ( rModulWindow.GetHScrollBar() )
+ rModulWindow.GetHScrollBar()->SetThumbPos( pEditView->GetStartDocPos().X() );
+ rModulWindow.GetEditVScrollBar().SetThumbPos( pEditView->GetStartDocPos().Y() );
+ rModulWindow.GetBreakPointWindow().DoScroll
+ ( rModulWindow.GetBreakPointWindow().GetCurYOffset() - pEditView->GetStartDocPos().Y() );
+ rModulWindow.GetLineNumberWindow().DoScroll
+ ( rModulWindow.GetLineNumberWindow().GetCurYOffset() - pEditView->GetStartDocPos().Y() );
+ }
+ else if( rTextHint.GetId() == SfxHintId::TextHeightChanged )
+ {
+ if ( pEditView->GetStartDocPos().Y() )
+ {
+ tools::Long nOutHeight = GetOutputSizePixel().Height();
+ tools::Long nTextHeight = pEditEngine->GetTextHeight();
+ if ( nTextHeight < nOutHeight )
+ pEditView->Scroll( 0, pEditView->GetStartDocPos().Y() );
+
+ rModulWindow.GetLineNumberWindow().Invalidate();
+ }
+
+ SetScrollBarRanges();
+ }
+ else if( rTextHint.GetId() == SfxHintId::TextFormatted )
+ {
+ if ( rModulWindow.GetHScrollBar() )
+ {
+ const tools::Long nWidth = pEditEngine->CalcTextWidth();
+ if ( nWidth != nCurTextWidth )
+ {
+ nCurTextWidth = nWidth;
+ rModulWindow.GetHScrollBar()->SetRange( Range( 0, nCurTextWidth-1) );
+ rModulWindow.GetHScrollBar()->SetThumbPos( pEditView->GetStartDocPos().X() );
+ }
+ }
+ tools::Long nPrevTextWidth = nCurTextWidth;
+ nCurTextWidth = pEditEngine->CalcTextWidth();
+ if ( nCurTextWidth != nPrevTextWidth )
+ SetScrollBarRanges();
+ }
+ else if( rTextHint.GetId() == SfxHintId::TextParaInserted )
+ {
+ ParagraphInsertedDeleted( rTextHint.GetValue(), true );
+ DoDelayedSyntaxHighlight( rTextHint.GetValue() );
+ }
+ else if( rTextHint.GetId() == SfxHintId::TextParaRemoved )
+ {
+ ParagraphInsertedDeleted( rTextHint.GetValue(), false );
+ }
+ else if( rTextHint.GetId() == SfxHintId::TextParaContentChanged )
+ {
+ DoDelayedSyntaxHighlight( rTextHint.GetValue() );
+ }
+ else if( rTextHint.GetId() == SfxHintId::TextViewSelectionChanged )
+ {
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate( SID_CUT );
+ pBindings->Invalidate( SID_COPY );
+ }
+ }
+}
+
+OUString EditorWindow::GetActualSubName( sal_uInt32 nLine )
+{
+ SbxArrayRef pMethods = rModulWindow.GetSbModule()->GetMethods();
+ for (sal_uInt32 i = 0; i < pMethods->Count(); i++)
+ {
+ SbMethod* pMeth = dynamic_cast<SbMethod*>(pMethods->Get(i));
+ if( pMeth )
+ {
+ sal_uInt16 l1,l2;
+ pMeth->GetLineRange(l1,l2);
+ if( (l1 <= nLine+1) && (nLine+1 <= l2) )
+ {
+ return pMeth->GetName();
+ }
+ }
+ }
+ return OUString();
+}
+
+void EditorWindow::SetScrollBarRanges()
+{
+ // extra method, not InitScrollBars, because for EditEngine events too
+ if ( !pEditEngine )
+ return;
+
+ if ( rModulWindow.GetHScrollBar() )
+ rModulWindow.GetHScrollBar()->SetRange( Range( 0, nCurTextWidth-1 ) );
+
+ rModulWindow.GetEditVScrollBar().SetRange( Range( 0, pEditEngine->GetTextHeight()-1 ) );
+}
+
+void EditorWindow::InitScrollBars()
+{
+ if (!pEditEngine)
+ return;
+
+ SetScrollBarRanges();
+ Size aOutSz(GetOutputSizePixel());
+ rModulWindow.GetEditVScrollBar().SetVisibleSize(aOutSz.Height());
+ rModulWindow.GetEditVScrollBar().SetPageSize(aOutSz.Height() * 8 / 10);
+ rModulWindow.GetEditVScrollBar().SetLineSize(GetTextHeight());
+ rModulWindow.GetEditVScrollBar().SetThumbPos(pEditView->GetStartDocPos().Y());
+ rModulWindow.GetEditVScrollBar().Show();
+
+ if (rModulWindow.GetHScrollBar())
+ {
+ rModulWindow.GetHScrollBar()->SetVisibleSize(aOutSz.Width());
+ rModulWindow.GetHScrollBar()->SetPageSize(aOutSz.Width() * 8 / 10);
+ rModulWindow.GetHScrollBar()->SetLineSize(GetTextWidth( "x" ) );
+ rModulWindow.GetHScrollBar()->SetThumbPos(pEditView->GetStartDocPos().X());
+ rModulWindow.GetHScrollBar()->Show();
+ }
+}
+
+void EditorWindow::ImpDoHighlight( sal_uInt32 nLine )
+{
+ if ( !bDoSyntaxHighlight )
+ return;
+
+ OUString aLine( pEditEngine->GetText( nLine ) );
+ bool const bWasModified = pEditEngine->IsModified();
+ pEditEngine->RemoveAttribs( nLine );
+ std::vector<HighlightPortion> aPortions;
+ aHighlighter.getHighlightPortions( aLine, aPortions );
+
+ for (auto const& portion : aPortions)
+ {
+ Color const aColor = rModulWindow.GetLayout().GetSyntaxColor(portion.tokenType);
+ pEditEngine->SetAttrib(TextAttribFontColor(aColor), nLine, portion.nBegin, portion.nEnd);
+ }
+
+ pEditEngine->SetModified(bWasModified);
+}
+
+void EditorWindow::ChangeFontColor( Color aColor )
+{
+ if (pEditEngine)
+ {
+ vcl::Font aFont(pEditEngine->GetFont());
+ aFont.SetColor(aColor);
+ pEditEngine->SetFont(aFont);
+ }
+}
+
+void EditorWindow::UpdateSyntaxHighlighting ()
+{
+ const sal_uInt32 nCount = pEditEngine->GetParagraphCount();
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ DoDelayedSyntaxHighlight(i);
+}
+
+void EditorWindow::ImplSetFont()
+{
+ OUString sFontName(officecfg::Office::Common::Font::SourceViewFont::FontName::get().value_or(OUString()));
+ if (sFontName.isEmpty())
+ {
+ vcl::Font aTmpFont(OutputDevice::GetDefaultFont(DefaultFontType::FIXED,
+ Application::GetSettings().GetUILanguageTag().getLanguageType(),
+ GetDefaultFontFlags::NONE, GetOutDev()));
+ sFontName = aTmpFont.GetFamilyName();
+ }
+ Size aFontSize(0, officecfg::Office::Common::Font::SourceViewFont::FontHeight::get());
+ vcl::Font aFont(sFontName, aFontSize);
+ aFont.SetColor(rModulWindow.GetLayout().GetFontColor());
+ SetPointFont(*GetOutDev(), aFont); // FIXME RenderContext
+ aFont = GetFont();
+
+ rModulWindow.GetBreakPointWindow().SetFont(aFont);
+ rModulWindow.GetLineNumberWindow().SetFont(aFont);
+
+ if (pEditEngine)
+ {
+ bool const bModified = pEditEngine->IsModified();
+ pEditEngine->SetFont(aFont);
+ pEditEngine->SetModified(bModified);
+ }
+}
+
+void EditorWindow::DoSyntaxHighlight( sal_uInt32 nPara )
+{
+ // because of the DelayedSyntaxHighlight it's possible
+ // that this line does not exist anymore!
+ if ( nPara < pEditEngine->GetParagraphCount() )
+ {
+ // unfortunately I'm not sure that exactly this line does Modified()...
+ if ( pProgress )
+ pProgress->StepProgress();
+ ImpDoHighlight( nPara );
+ }
+}
+
+void EditorWindow::DoDelayedSyntaxHighlight( sal_uInt32 nPara )
+{
+ // line is only added to list, processed in TimerHdl
+ // => don't manipulate breaks while EditEngine is formatting
+ if ( pProgress )
+ pProgress->StepProgress();
+
+ if ( !bHighlighting && bDoSyntaxHighlight )
+ {
+ if ( bDelayHighlight )
+ {
+ aSyntaxLineTable.insert( nPara );
+ aSyntaxIdle.Start();
+ }
+ else
+ DoSyntaxHighlight( nPara );
+ }
+}
+
+IMPL_LINK_NOARG(EditorWindow, SyntaxTimerHdl, Timer *, void)
+{
+ DBG_ASSERT( pEditView, "Not yet a View, but Syntax-Highlight?!" );
+
+ bool const bWasModified = pEditEngine->IsModified();
+ //pEditEngine->SetUpdateMode(false);
+
+ bHighlighting = true;
+ for (auto const& syntaxLine : aSyntaxLineTable)
+ {
+ DoSyntaxHighlight(syntaxLine);
+ }
+
+ // #i45572#
+ if ( pEditView )
+ pEditView->ShowCursor( false );
+
+ pEditEngine->SetModified( bWasModified );
+
+ aSyntaxLineTable.clear();
+ bHighlighting = false;
+}
+
+void EditorWindow::ParagraphInsertedDeleted( sal_uInt32 nPara, bool bInserted )
+{
+ if ( pProgress )
+ pProgress->StepProgress();
+
+ if ( !bInserted && ( nPara == TEXT_PARA_ALL ) )
+ {
+ rModulWindow.GetBreakPoints().reset();
+ rModulWindow.GetBreakPointWindow().Invalidate();
+ rModulWindow.GetLineNumberWindow().Invalidate();
+ }
+ else
+ {
+ rModulWindow.GetBreakPoints().AdjustBreakPoints( static_cast<sal_uInt16>(nPara)+1, bInserted );
+
+ tools::Long nLineHeight = GetTextHeight();
+ Size aSz = rModulWindow.GetBreakPointWindow().GetOutDev()->GetOutputSize();
+ tools::Rectangle aInvRect( Point( 0, 0 ), aSz );
+ tools::Long nY = nPara*nLineHeight - rModulWindow.GetBreakPointWindow().GetCurYOffset();
+ aInvRect.SetTop( nY );
+ rModulWindow.GetBreakPointWindow().Invalidate( aInvRect );
+
+ Size aLnSz(rModulWindow.GetLineNumberWindow().GetWidth(),
+ GetOutputSizePixel().Height() - 2 * DWBORDER);
+ rModulWindow.GetLineNumberWindow().SetPosSizePixel(Point(DWBORDER + 19, DWBORDER), aLnSz);
+ rModulWindow.GetLineNumberWindow().Invalidate();
+ }
+}
+
+void EditorWindow::CreateProgress( const OUString& rText, sal_uInt32 nRange )
+{
+ DBG_ASSERT( !pProgress, "ProgressInfo exists already" );
+ pProgress.reset(new ProgressInfo(
+ GetShell()->GetViewFrame()->GetObjectShell(),
+ rText,
+ nRange
+ ));
+}
+
+void EditorWindow::DestroyProgress()
+{
+ pProgress.reset();
+}
+
+void EditorWindow::ForceSyntaxTimeout()
+{
+ aSyntaxIdle.Stop();
+ aSyntaxIdle.Invoke();
+}
+
+FactoryFunction EditorWindow::GetUITestFactory() const
+{
+ return EditorWindowUIObject::create;
+}
+
+
+// BreakPointWindow
+
+BreakPointWindow::BreakPointWindow (vcl::Window* pParent, ModulWindow* pModulWindow)
+ : Window(pParent, WB_BORDER)
+ , rModulWindow(*pModulWindow)
+ , nCurYOffset(0) // memorize nCurYOffset and not take it from EditEngine
+ , nMarkerPos(NoMarker)
+ , bErrorMarker(false)
+{
+ setBackgroundColor(GetSettings().GetStyleSettings().GetFieldColor());
+ SetHelpId(HID_BASICIDE_BREAKPOINTWINDOW);
+}
+
+void BreakPointWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ if (SyncYOffset())
+ return;
+
+ Size const aOutSz = rRenderContext.GetOutputSize();
+ tools::Long const nLineHeight = rRenderContext.GetTextHeight();
+
+ Image const aBrk[2] =
+ {
+ GetImage(RID_BMP_BRKDISABLED),
+ GetImage(RID_BMP_BRKENABLED)
+ };
+
+ Size const aBmpSz = rRenderContext.PixelToLogic(aBrk[1].GetSizePixel());
+ Point const aBmpOff((aOutSz.Width() - aBmpSz.Width()) / 2,
+ (nLineHeight - aBmpSz.Height()) / 2);
+
+ for (size_t i = 0, n = GetBreakPoints().size(); i < n; ++i)
+ {
+ BreakPoint& rBrk = GetBreakPoints().at(i);
+ sal_uInt16 const nLine = rBrk.nLine - 1;
+ size_t const nY = nLine*nLineHeight - nCurYOffset;
+ rRenderContext.DrawImage(Point(0, nY) + aBmpOff, aBrk[rBrk.bEnabled]);
+ }
+
+ ShowMarker(rRenderContext);
+}
+
+void BreakPointWindow::ShowMarker(vcl::RenderContext& rRenderContext)
+{
+ if (nMarkerPos == NoMarker)
+ return;
+
+ Size const aOutSz = GetOutDev()->GetOutputSize();
+ tools::Long const nLineHeight = GetTextHeight();
+
+ Image aMarker = GetImage(bErrorMarker ? OUString(RID_BMP_ERRORMARKER) : OUString(RID_BMP_STEPMARKER));
+
+ Size aMarkerSz(aMarker.GetSizePixel());
+ aMarkerSz = rRenderContext.PixelToLogic(aMarkerSz);
+ Point aMarkerOff(0, 0);
+ aMarkerOff.setX( (aOutSz.Width() - aMarkerSz.Width()) / 2 );
+ aMarkerOff.setY( (nLineHeight - aMarkerSz.Height()) / 2 );
+
+ sal_uLong nY = nMarkerPos * nLineHeight - nCurYOffset;
+ Point aPos(0, nY);
+ aPos += aMarkerOff;
+
+ rRenderContext.DrawImage(aPos, aMarker);
+}
+
+void BreakPointWindow::DoScroll( tools::Long nVertScroll )
+{
+ nCurYOffset -= nVertScroll;
+ Window::Scroll( 0, nVertScroll );
+}
+
+void BreakPointWindow::SetMarkerPos( sal_uInt16 nLine, bool bError )
+{
+ if ( SyncYOffset() )
+ PaintImmediately();
+
+ nMarkerPos = nLine;
+ bErrorMarker = bError;
+ Invalidate();
+}
+
+void BreakPointWindow::SetNoMarker ()
+{
+ SetMarkerPos(NoMarker);
+}
+
+BreakPoint* BreakPointWindow::FindBreakPoint( const Point& rMousePos )
+{
+ size_t nLineHeight = GetTextHeight();
+ nLineHeight = nLineHeight > 0 ? nLineHeight : 1;
+ size_t nYPos = rMousePos.Y() + nCurYOffset;
+
+ for ( size_t i = 0, n = GetBreakPoints().size(); i < n ; ++i )
+ {
+ BreakPoint& rBrk = GetBreakPoints().at( i );
+ sal_uInt16 nLine = rBrk.nLine-1;
+ size_t nY = nLine*nLineHeight;
+ if ( ( nYPos > nY ) && ( nYPos < ( nY + nLineHeight ) ) )
+ return &rBrk;
+ }
+ return nullptr;
+}
+
+void BreakPointWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.GetClicks() == 2 )
+ {
+ Point aMousePos( PixelToLogic( rMEvt.GetPosPixel() ) );
+ tools::Long nLineHeight = GetTextHeight();
+ if(nLineHeight)
+ {
+ tools::Long nYPos = aMousePos.Y() + nCurYOffset;
+ tools::Long nLine = nYPos / nLineHeight + 1;
+ rModulWindow.ToggleBreakPoint( static_cast<sal_uLong>(nLine) );
+ Invalidate();
+ }
+ }
+}
+
+void BreakPointWindow::Command( const CommandEvent& rCEvt )
+{
+ if ( rCEvt.GetCommand() != CommandEventId::ContextMenu )
+ return;
+
+ Point aPos( rCEvt.IsMouseEvent() ? rCEvt.GetMousePosPixel() : Point(1,1) );
+ tools::Rectangle aRect(aPos, Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+
+ std::unique_ptr<weld::Builder> xUIBuilder(Application::CreateBuilder(pPopupParent, "modules/BasicIDE/ui/breakpointmenus.ui"));
+
+ Point aEventPos( PixelToLogic( aPos ) );
+ BreakPoint* pBrk = rCEvt.IsMouseEvent() ? FindBreakPoint( aEventPos ) : nullptr;
+ if ( pBrk )
+ {
+ // test if break point is enabled...
+ std::unique_ptr<weld::Menu> xBrkPropMenu = xUIBuilder->weld_menu("breakmenu");
+ xBrkPropMenu->set_active("active", pBrk->bEnabled);
+ OString sCommand = xBrkPropMenu->popup_at_rect(pPopupParent, aRect);
+ if (sCommand == "active")
+ {
+ pBrk->bEnabled = !pBrk->bEnabled;
+ rModulWindow.UpdateBreakPoint( *pBrk );
+ Invalidate();
+ }
+ else if (sCommand == "properties")
+ {
+ BreakPointDialog aBrkDlg(pPopupParent, GetBreakPoints());
+ aBrkDlg.SetCurrentBreakPoint( *pBrk );
+ aBrkDlg.run();
+ Invalidate();
+ }
+ }
+ else
+ {
+ std::unique_ptr<weld::Menu> xBrkListMenu = xUIBuilder->weld_menu("breaklistmenu");
+ OString sCommand = xBrkListMenu->popup_at_rect(pPopupParent, aRect);
+ if (sCommand == "manage")
+ {
+ BreakPointDialog aBrkDlg(pPopupParent, GetBreakPoints());
+ aBrkDlg.run();
+ Invalidate();
+ }
+ }
+}
+
+bool BreakPointWindow::SyncYOffset()
+{
+ TextView* pView = rModulWindow.GetEditView();
+ if ( pView )
+ {
+ tools::Long nViewYOffset = pView->GetStartDocPos().Y();
+ if ( nCurYOffset != nViewYOffset )
+ {
+ nCurYOffset = nViewYOffset;
+ Invalidate();
+ return true;
+ }
+ }
+ return false;
+}
+
+// virtual
+void BreakPointWindow::DataChanged(DataChangedEvent const & rDCEvt)
+{
+ Window::DataChanged(rDCEvt);
+ if (rDCEvt.GetType() == DataChangedEventType::SETTINGS
+ && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
+ {
+ Color aColor(GetSettings().GetStyleSettings().GetFieldColor());
+ const AllSettings* pOldSettings = rDCEvt.GetOldSettings();
+ if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFieldColor())
+ {
+ setBackgroundColor(aColor);
+ Invalidate();
+ }
+ }
+}
+
+void BreakPointWindow::setBackgroundColor(Color aColor)
+{
+ SetBackground(Wallpaper(aColor));
+}
+
+namespace {
+
+struct WatchItem
+{
+ OUString maName;
+ OUString maDisplayName;
+ SbxObjectRef mpObject;
+ std::vector<OUString> maMemberList;
+
+ SbxDimArrayRef mpArray;
+ int nDimLevel; // 0 = Root
+ int nDimCount;
+ std::vector<sal_Int32> vIndices;
+
+ WatchItem* mpArrayParentItem;
+
+ explicit WatchItem (OUString aName):
+ maName(std::move(aName)),
+ nDimLevel(0),
+ nDimCount(0),
+ mpArrayParentItem(nullptr)
+ { }
+
+ void clearWatchItem ()
+ {
+ maMemberList.clear();
+ }
+
+ WatchItem* GetRootItem();
+ SbxDimArray* GetRootArray();
+};
+
+}
+
+WatchWindow::WatchWindow(Layout* pParent)
+ : DockingWindow(pParent, "modules/BasicIDE/ui/dockingwatch.ui", "DockingWatch")
+ , m_nUpdateWatchesId(nullptr)
+{
+ m_xTitleArea = m_xBuilder->weld_container("titlearea");
+
+ nVirtToolBoxHeight = m_xTitleArea->get_preferred_size().Height();
+
+ m_xTitle = m_xBuilder->weld_label("title");
+ m_xTitle->set_label(IDEResId(RID_STR_REMOVEWATCH));
+
+ m_xEdit = m_xBuilder->weld_entry("edit");
+ m_xRemoveWatchButton = m_xBuilder->weld_button("remove");
+ m_xTreeListBox = m_xBuilder->weld_tree_view("treeview");
+
+ m_xEdit->set_accessible_name(IDEResId(RID_STR_WATCHNAME));
+ m_xEdit->set_help_id(HID_BASICIDE_WATCHWINDOW_EDIT);
+ m_xEdit->set_size_request(LogicToPixel(Size(80, 0), MapMode(MapUnit::MapAppFont)).Width(), -1);
+ m_xEdit->connect_activate(LINK( this, WatchWindow, ActivateHdl));
+ m_xEdit->connect_key_press(LINK( this, WatchWindow, KeyInputHdl));
+ m_xTreeListBox->set_accessible_name(IDEResId(RID_STR_WATCHNAME));
+
+ m_xRemoveWatchButton->set_sensitive(false);
+ m_xRemoveWatchButton->connect_clicked(LINK( this, WatchWindow, ButtonHdl));
+ m_xRemoveWatchButton->set_help_id(HID_BASICIDE_REMOVEWATCH);
+ m_xRemoveWatchButton->set_tooltip_text(IDEResId(RID_STR_REMOVEWATCHTIP));
+
+ m_xTreeListBox->set_help_id(HID_BASICIDE_WATCHWINDOW_LIST);
+ m_xTreeListBox->connect_editing(LINK(this, WatchWindow, EditingEntryHdl),
+ LINK(this, WatchWindow, EditedEntryHdl));
+ m_xTreeListBox->connect_changed( LINK( this, WatchWindow, TreeListHdl ) );
+ m_xTreeListBox->connect_expanding(LINK(this, WatchWindow, RequestingChildrenHdl));
+
+ // VarTabWidth, ValueTabWidth, TypeTabWidth
+ std::vector<int> aWidths { 220, 100, 1250 };
+ std::vector<bool> aEditables { false, true, false };
+ m_xTreeListBox->set_column_fixed_widths(aWidths);
+ m_xTreeListBox->set_column_editables(aEditables);
+
+ SetText(IDEResId(RID_STR_WATCHNAME));
+
+ SetHelpId( HID_BASICIDE_WATCHWINDOW );
+
+ // make watch window keyboard accessible
+ GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
+}
+
+WatchWindow::~WatchWindow()
+{
+ disposeOnce();
+}
+
+void WatchWindow::dispose()
+{
+ if (m_nUpdateWatchesId)
+ {
+ Application::RemoveUserEvent(m_nUpdateWatchesId);
+ m_nUpdateWatchesId = nullptr;
+ }
+
+ // Destroy user data
+ m_xTreeListBox->all_foreach([this](weld::TreeIter& rEntry){
+ WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(rEntry));
+ delete pItem;
+ return false;
+ });
+
+ m_xTitle.reset();
+ m_xEdit.reset();
+ m_xRemoveWatchButton.reset();
+ m_xTitleArea.reset();
+ m_xTreeListBox.reset();
+ GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
+ DockingWindow::dispose();
+}
+
+void WatchWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ lcl_DrawIDEWindowFrame(this, rRenderContext);
+}
+
+void WatchWindow::Resize()
+{
+ Size aSz = GetOutputSizePixel();
+ Size aBoxSz(aSz.Width() - 2*DWBORDER, aSz.Height() - 2*DWBORDER);
+
+ if ( aBoxSz.Width() < 4 )
+ aBoxSz.setWidth( 0 );
+ if ( aBoxSz.Height() < 4 )
+ aBoxSz.setHeight( 0 );
+
+ m_xBox->SetPosSizePixel(Point(DWBORDER, DWBORDER), aBoxSz);
+
+ Invalidate();
+}
+
+WatchItem* WatchItem::GetRootItem()
+{
+ WatchItem* pItem = mpArrayParentItem;
+ while( pItem )
+ {
+ if( pItem->mpArray.is() )
+ break;
+ pItem = pItem->mpArrayParentItem;
+ }
+ return pItem;
+}
+
+SbxDimArray* WatchItem::GetRootArray()
+{
+ WatchItem* pRootItem = GetRootItem();
+ SbxDimArray* pRet = nullptr;
+ if( pRootItem )
+ pRet = pRootItem->mpArray.get();
+ return pRet;
+}
+
+void WatchWindow::AddWatch( const OUString& rVName )
+{
+ OUString aVar, aIndex;
+ lcl_SeparateNameAndIndex( rVName, aVar, aIndex );
+ WatchItem* pWatchItem = new WatchItem(aVar);
+
+ OUString sId(weld::toId(pWatchItem));
+ std::unique_ptr<weld::TreeIter> xRet = m_xTreeListBox->make_iterator();
+ m_xTreeListBox->insert(nullptr, -1, &aVar, &sId, nullptr, nullptr, false, xRet.get());
+ m_xTreeListBox->set_text(*xRet, "", 1);
+ m_xTreeListBox->set_text(*xRet, "", 2);
+
+ m_xTreeListBox->set_cursor(*xRet);
+ m_xTreeListBox->select(*xRet);
+ m_xTreeListBox->scroll_to_row(*xRet);
+ m_xRemoveWatchButton->set_sensitive(true);
+
+ UpdateWatches(false);
+}
+
+void WatchWindow::RemoveSelectedWatch()
+{
+ std::unique_ptr<weld::TreeIter> xEntry = m_xTreeListBox->make_iterator();
+ bool bEntry = m_xTreeListBox->get_cursor(xEntry.get());
+ if (bEntry)
+ {
+ m_xTreeListBox->remove(*xEntry);
+ bEntry = m_xTreeListBox->get_cursor(xEntry.get());
+ if (bEntry)
+ m_xEdit->set_text(weld::fromId<WatchItem*>(m_xTreeListBox->get_id(*xEntry))->maName);
+ else
+ m_xEdit->set_text(OUString());
+ if ( !m_xTreeListBox->n_children() )
+ m_xRemoveWatchButton->set_sensitive(false);
+ }
+}
+
+IMPL_STATIC_LINK_NOARG(WatchWindow, ButtonHdl, weld::Button&, void)
+{
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ pDispatcher->Execute(SID_BASICIDE_REMOVEWATCH);
+}
+
+IMPL_LINK_NOARG(WatchWindow, TreeListHdl, weld::TreeView&, void)
+{
+ std::unique_ptr<weld::TreeIter> xCurEntry = m_xTreeListBox->make_iterator();
+ bool bCurEntry = m_xTreeListBox->get_cursor(xCurEntry.get());
+ if (!bCurEntry)
+ return;
+ WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(*xCurEntry));
+ if (!pItem)
+ return;
+ m_xEdit->set_text(pItem->maName);
+}
+
+IMPL_LINK_NOARG(WatchWindow, ActivateHdl, weld::Entry&, bool)
+{
+ OUString aCurText(m_xEdit->get_text());
+ if (!aCurText.isEmpty())
+ {
+ AddWatch(aCurText);
+ m_xEdit->select_region(0, -1);
+ }
+ return true;
+}
+
+IMPL_LINK(WatchWindow, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled = false;
+
+ sal_uInt16 nKeyCode = rKEvt.GetKeyCode().GetCode();
+ if (nKeyCode == KEY_ESCAPE)
+ {
+ m_xEdit->set_text(OUString());
+ bHandled = true;
+ }
+
+ return bHandled;
+}
+
+// StackWindow
+StackWindow::StackWindow(Layout* pParent)
+ : DockingWindow(pParent, "modules/BasicIDE/ui/dockingstack.ui", "DockingStack")
+{
+ m_xTitle = m_xBuilder->weld_label("title");
+ m_xTitle->set_label(IDEResId(RID_STR_STACK));
+
+ m_xTitle->set_size_request(-1, nVirtToolBoxHeight); // so the two title areas are the same height
+
+ m_xTreeListBox = m_xBuilder->weld_tree_view("stack");
+
+ m_xTreeListBox->set_help_id(HID_BASICIDE_STACKWINDOW_LIST);
+ m_xTreeListBox->set_accessible_name(IDEResId(RID_STR_STACKNAME));
+ m_xTreeListBox->set_selection_mode(SelectionMode::NONE);
+ m_xTreeListBox->append_text(OUString());
+
+ SetText(IDEResId(RID_STR_STACKNAME));
+
+ SetHelpId( HID_BASICIDE_STACKWINDOW );
+
+ // make stack window keyboard accessible
+ GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
+}
+
+StackWindow::~StackWindow()
+{
+ disposeOnce();
+}
+
+void StackWindow::dispose()
+{
+ GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
+ m_xTitle.reset();
+ m_xTreeListBox.reset();
+ DockingWindow::dispose();
+}
+
+void StackWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ lcl_DrawIDEWindowFrame(this, rRenderContext);
+}
+
+void StackWindow::Resize()
+{
+ Size aSz = GetOutputSizePixel();
+ Size aBoxSz(aSz.Width() - 2*DWBORDER, aSz.Height() - 2*DWBORDER);
+
+ if ( aBoxSz.Width() < 4 )
+ aBoxSz.setWidth( 0 );
+ if ( aBoxSz.Height() < 4 )
+ aBoxSz.setHeight( 0 );
+
+ m_xBox->SetPosSizePixel(Point(DWBORDER, DWBORDER), aBoxSz);
+
+ Invalidate();
+}
+
+void StackWindow::UpdateCalls()
+{
+ m_xTreeListBox->freeze();
+ m_xTreeListBox->clear();
+
+ if (StarBASIC::IsRunning())
+ {
+ ErrCode eOld = SbxBase::GetError();
+ m_xTreeListBox->set_selection_mode(SelectionMode::Single);
+
+ sal_Int32 nScope = 0;
+ SbMethod* pMethod = StarBASIC::GetActiveMethod( nScope );
+ while ( pMethod )
+ {
+ OUStringBuffer aEntry( OUString::number(nScope ));
+ if ( aEntry.getLength() < 2 )
+ aEntry.insert(0, " ");
+ aEntry.append(": " + pMethod->GetName());
+ SbxArray* pParams = pMethod->GetParameters();
+ SbxInfo* pInfo = pMethod->GetInfo();
+ if ( pParams )
+ {
+ aEntry.append("(");
+ // 0 is the sub's name...
+ for (sal_uInt32 nParam = 1; nParam < pParams->Count(); nParam++)
+ {
+ SbxVariable* pVar = pParams->Get(nParam);
+ assert(pVar && "Parameter?!");
+ if ( !pVar->GetName().isEmpty() )
+ {
+ aEntry.append(pVar->GetName());
+ }
+ else if ( pInfo )
+ {
+ assert(nParam <= std::numeric_limits<sal_uInt16>::max());
+ const SbxParamInfo* pParam = pInfo->GetParam( sal::static_int_cast<sal_uInt16>(nParam) );
+ if ( pParam )
+ {
+ aEntry.append(pParam->aName);
+ }
+ }
+ aEntry.append("=");
+ SbxDataType eType = pVar->GetType();
+ if( eType & SbxARRAY )
+ {
+ aEntry.append("...");
+ }
+ else if( eType != SbxOBJECT )
+ {
+ aEntry.append(pVar->GetOUString());
+ }
+ if (nParam < (pParams->Count() - 1))
+ {
+ aEntry.append(", ");
+ }
+ }
+ aEntry.append(")");
+ }
+ m_xTreeListBox->append_text(aEntry.makeStringAndClear());
+ nScope++;
+ pMethod = StarBASIC::GetActiveMethod( nScope );
+ }
+
+ SbxBase::ResetError();
+ if( eOld != ERRCODE_NONE )
+ SbxBase::SetError( eOld );
+ }
+ else
+ {
+ m_xTreeListBox->set_selection_mode(SelectionMode::NONE);
+ m_xTreeListBox->append_text(OUString());
+ }
+
+ m_xTreeListBox->thaw();
+}
+
+ComplexEditorWindow::ComplexEditorWindow( ModulWindow* pParent ) :
+ Window( pParent, WB_3DLOOK | WB_CLIPCHILDREN ),
+ aBrkWindow(VclPtr<BreakPointWindow>::Create(this, pParent)),
+ aLineNumberWindow(VclPtr<LineNumberWindow>::Create(this, pParent)),
+ aEdtWindow(VclPtr<EditorWindow>::Create(this, pParent)),
+ aEWVScrollBar( VclPtr<ScrollBar>::Create(this, WB_VSCROLL | WB_DRAG) )
+{
+ aEdtWindow->Show();
+ aBrkWindow->Show();
+
+ aEWVScrollBar->SetLineSize(nScrollLine);
+ aEWVScrollBar->SetPageSize(nScrollPage);
+ aEWVScrollBar->SetScrollHdl( LINK( this, ComplexEditorWindow, ScrollHdl ) );
+ aEWVScrollBar->Show();
+}
+
+ComplexEditorWindow::~ComplexEditorWindow()
+{
+ disposeOnce();
+}
+
+void ComplexEditorWindow::dispose()
+{
+ aBrkWindow.disposeAndClear();
+ aLineNumberWindow.disposeAndClear();
+ aEdtWindow.disposeAndClear();
+ aEWVScrollBar.disposeAndClear();
+ vcl::Window::dispose();
+}
+
+void ComplexEditorWindow::Resize()
+{
+ Size aOutSz = GetOutputSizePixel();
+ Size aSz(aOutSz);
+ aSz.AdjustWidth( -(2*DWBORDER) );
+ aSz.AdjustHeight( -(2*DWBORDER) );
+ tools::Long nBrkWidth = 20;
+ tools::Long nSBWidth = aEWVScrollBar->GetSizePixel().Width();
+
+ Size aBrkSz(nBrkWidth, aSz.Height());
+
+ Size aLnSz(aLineNumberWindow->GetWidth(), aSz.Height());
+
+ if (aLineNumberWindow->IsVisible())
+ {
+ aBrkWindow->SetPosSizePixel( Point( DWBORDER, DWBORDER ), aBrkSz );
+ aLineNumberWindow->SetPosSizePixel(Point(DWBORDER + aBrkSz.Width() - 1, DWBORDER), aLnSz);
+ Size aEWSz(aSz.Width() - nBrkWidth - aLineNumberWindow->GetWidth() - nSBWidth + 2, aSz.Height());
+ aEdtWindow->SetPosSizePixel( Point( DWBORDER + aBrkSz.Width() + aLnSz.Width() - 1, DWBORDER ), aEWSz );
+ }
+ else
+ {
+ aBrkWindow->SetPosSizePixel( Point( DWBORDER, DWBORDER ), aBrkSz );
+ Size aEWSz(aSz.Width() - nBrkWidth - nSBWidth + 2, aSz.Height());
+ aEdtWindow->SetPosSizePixel(Point(DWBORDER + aBrkSz.Width() - 1, DWBORDER), aEWSz);
+ }
+
+ aEWVScrollBar->SetPosSizePixel( Point( aOutSz.Width() - DWBORDER - nSBWidth, DWBORDER ), Size( nSBWidth, aSz.Height() ) );
+}
+
+IMPL_LINK(ComplexEditorWindow, ScrollHdl, ScrollBar *, pCurScrollBar, void )
+{
+ if (aEdtWindow->GetEditView())
+ {
+ DBG_ASSERT( pCurScrollBar == aEWVScrollBar.get(), "Who is scrolling?" );
+ tools::Long nDiff = aEdtWindow->GetEditView()->GetStartDocPos().Y() - pCurScrollBar->GetThumbPos();
+ aEdtWindow->GetEditView()->Scroll( 0, nDiff );
+ aBrkWindow->DoScroll( nDiff );
+ aLineNumberWindow->DoScroll( nDiff );
+ aEdtWindow->GetEditView()->ShowCursor(false);
+ pCurScrollBar->SetThumbPos( aEdtWindow->GetEditView()->GetStartDocPos().Y() );
+ }
+}
+
+void ComplexEditorWindow::DataChanged(DataChangedEvent const & rDCEvt)
+{
+ Window::DataChanged(rDCEvt);
+ if (rDCEvt.GetType() == DataChangedEventType::SETTINGS
+ && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
+ {
+ Color aColor(GetSettings().GetStyleSettings().GetFaceColor());
+ const AllSettings* pOldSettings = rDCEvt.GetOldSettings();
+ if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFaceColor())
+ {
+ SetBackground(Wallpaper(aColor));
+ Invalidate();
+ }
+ }
+}
+
+void ComplexEditorWindow::SetLineNumberDisplay(bool b)
+{
+ aLineNumberWindow->Show(b);
+ Resize();
+}
+
+uno::Reference< awt::XWindowPeer >
+EditorWindow::GetComponentInterface(bool bCreate)
+{
+ uno::Reference< awt::XWindowPeer > xPeer(
+ Window::GetComponentInterface(false));
+ if (!xPeer.is() && bCreate)
+ {
+ // Make sure edit engine and view are available:
+ if (!pEditEngine)
+ CreateEditEngine();
+
+ xPeer = createTextWindowPeer(*GetEditView());
+ SetComponentInterface(xPeer);
+ }
+ return xPeer;
+}
+
+static sal_uInt32 getCorrectedPropCount(SbxArray* p)
+{
+ sal_uInt32 nPropCount = p->Count();
+ if (nPropCount >= 3 && p->Get(nPropCount - 1)->GetName().equalsIgnoreAsciiCase("Dbg_Methods")
+ && p->Get(nPropCount - 2)->GetName().equalsIgnoreAsciiCase("Dbg_Properties")
+ && p->Get(nPropCount - 3)->GetName().equalsIgnoreAsciiCase("Dbg_SupportedInterfaces"))
+ {
+ nPropCount -= 3;
+ }
+ return nPropCount;
+}
+
+IMPL_LINK(WatchWindow, RequestingChildrenHdl, const weld::TreeIter&, rParent, bool)
+{
+ if( !StarBASIC::IsRunning() )
+ return true;
+
+ if (m_xTreeListBox->iter_has_child(rParent))
+ return true;
+
+ WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(rParent));
+ std::unique_ptr<weld::TreeIter> xRet = m_xTreeListBox->make_iterator();
+
+ SbxDimArray* pArray = pItem->mpArray.get();
+ SbxDimArray* pRootArray = pItem->GetRootArray();
+ bool bArrayIsRootArray = false;
+ if( !pArray && pRootArray )
+ {
+ pArray = pRootArray;
+ bArrayIsRootArray = true;
+ }
+
+ SbxObject* pObj = pItem->mpObject.get();
+ if( pObj )
+ {
+ createAllObjectProperties( pObj );
+ SbxArray* pProps = pObj->GetProperties();
+ const sal_uInt32 nPropCount = getCorrectedPropCount(pProps);
+ pItem->maMemberList.reserve(nPropCount);
+
+ for( sal_uInt32 i = 0 ; i < nPropCount ; ++i )
+ {
+ SbxVariable* pVar = pProps->Get(i);
+
+ pItem->maMemberList.push_back(pVar->GetName());
+ OUString const& rName = pItem->maMemberList.back();
+
+ WatchItem* pWatchItem = new WatchItem(rName);
+ OUString sId(weld::toId(pWatchItem));
+
+ m_xTreeListBox->insert(&rParent, -1, &rName, &sId, nullptr, nullptr, false, xRet.get());
+ m_xTreeListBox->set_text(*xRet, "", 1);
+ m_xTreeListBox->set_text(*xRet, "", 2);
+ }
+
+ if (nPropCount > 0 && !m_nUpdateWatchesId)
+ {
+ m_nUpdateWatchesId = Application::PostUserEvent(LINK(this, WatchWindow, ExecuteUpdateWatches));
+ }
+ }
+ else if( pArray )
+ {
+ sal_uInt16 nElementCount = 0;
+
+ // Loop through indices of current level
+ int nParentLevel = bArrayIsRootArray ? pItem->nDimLevel : 0;
+ int nThisLevel = nParentLevel + 1;
+ sal_Int32 nMin, nMax;
+ if (pArray->GetDim(nThisLevel, nMin, nMax))
+ {
+ for (sal_Int32 i = nMin; i <= nMax; i++)
+ {
+ WatchItem* pChildItem = new WatchItem(pItem->maName);
+
+ // Copy data and create name
+
+ OUStringBuffer aIndexStr = "(";
+ pChildItem->mpArrayParentItem = pItem;
+ pChildItem->nDimLevel = nThisLevel;
+ pChildItem->nDimCount = pItem->nDimCount;
+ pChildItem->vIndices.resize(pChildItem->nDimCount);
+ sal_Int32 j;
+ for (j = 0; j < nParentLevel; j++)
+ {
+ sal_Int32 n = pChildItem->vIndices[j] = pItem->vIndices[j];
+ aIndexStr.append( OUString::number(n) + "," );
+ }
+ pChildItem->vIndices[nParentLevel] = i;
+ aIndexStr.append( OUString::number(i) + ")" );
+
+ OUString aDisplayName;
+ WatchItem* pArrayRootItem = pChildItem->GetRootItem();
+ if (pArrayRootItem && pArrayRootItem->mpArrayParentItem)
+ aDisplayName = pItem->maDisplayName;
+ else
+ aDisplayName = pItem->maName;
+ aDisplayName += aIndexStr;
+ pChildItem->maDisplayName = aDisplayName;
+
+ OUString sId(weld::toId(pChildItem));
+
+ m_xTreeListBox->insert(&rParent, -1, &aDisplayName, &sId, nullptr, nullptr, false,
+ xRet.get());
+ m_xTreeListBox->set_text(*xRet, "", 1);
+ m_xTreeListBox->set_text(*xRet, "", 2);
+
+ nElementCount++;
+ }
+ }
+ if (nElementCount > 0 && !m_nUpdateWatchesId)
+ {
+ m_nUpdateWatchesId = Application::PostUserEvent(LINK(this, WatchWindow, ExecuteUpdateWatches));
+ }
+ }
+
+ return true;
+}
+
+IMPL_LINK_NOARG(WatchWindow, ExecuteUpdateWatches, void*, void)
+{
+ m_nUpdateWatchesId = nullptr;
+ UpdateWatches();
+}
+
+SbxBase* WatchWindow::ImplGetSBXForEntry(const weld::TreeIter& rEntry, bool& rbArrayElement)
+{
+ SbxBase* pSBX = nullptr;
+ rbArrayElement = false;
+
+ WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(rEntry));
+ OUString aVName( pItem->maName );
+
+ std::unique_ptr<weld::TreeIter> xParentEntry = m_xTreeListBox->make_iterator(&rEntry);
+ bool bParentEntry = m_xTreeListBox->iter_parent(*xParentEntry);
+ WatchItem* pParentItem = bParentEntry ? weld::fromId<WatchItem*>(m_xTreeListBox->get_id(*xParentEntry)) : nullptr;
+ if( pParentItem )
+ {
+ SbxObject* pObj = pParentItem->mpObject.get();
+ SbxDimArray* pArray;
+ if( pObj )
+ {
+ pSBX = pObj->Find( aVName, SbxClassType::DontCare );
+ if (SbxVariable const* pVar = IsSbxVariable(pSBX))
+ {
+ // Force getting value
+ SbxValues aRes;
+ aRes.eType = SbxVOID;
+ pVar->Get( aRes );
+ }
+ }
+ // Array?
+ else if( (pArray = pItem->GetRootArray()) != nullptr )
+ {
+ rbArrayElement = true;
+ if( pParentItem->nDimLevel + 1 == pParentItem->nDimCount )
+ pSBX = pArray->Get(pItem->vIndices.empty() ? nullptr : &*pItem->vIndices.begin());
+ }
+ }
+ else
+ {
+ pSBX = StarBASIC::FindSBXInCurrentScope( aVName );
+ }
+ return pSBX;
+}
+
+IMPL_LINK(WatchWindow, EditingEntryHdl, const weld::TreeIter&, rIter, bool)
+{
+ WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(rIter));
+
+ bool bEdit = false;
+ if (StarBASIC::IsRunning() && StarBASIC::GetActiveMethod() && !SbxBase::IsError())
+ {
+ // No out of scope entries
+ bool bArrayElement;
+ SbxBase* pSbx = ImplGetSBXForEntry(rIter, bArrayElement);
+ if (IsSbxVariable(pSbx) || bArrayElement)
+ {
+ // Accept no objects and only end nodes of arrays for editing
+ if( !pItem->mpObject.is() && ( !pItem->mpArray.is() || pItem->nDimLevel == pItem->nDimCount ) )
+ {
+ aEditingRes = m_xTreeListBox->get_text(rIter, 1);
+ aEditingRes = comphelper::string::strip(aEditingRes, ' ');
+ bEdit = true;
+ }
+ }
+ }
+
+ return bEdit;
+}
+
+IMPL_LINK(WatchWindow, EditedEntryHdl, const IterString&, rIterString, bool)
+{
+ const weld::TreeIter& rIter = rIterString.first;
+ OUString aResult = comphelper::string::strip(rIterString.second, ' ');
+
+ sal_uInt16 nResultLen = aResult.getLength();
+ sal_Unicode cFirst = aResult[0];
+ sal_Unicode cLast = aResult[ nResultLen - 1 ];
+ if( cFirst == '\"' && cLast == '\"' )
+ aResult = aResult.copy( 1, nResultLen - 2 );
+
+ if (aResult == aEditingRes)
+ return false;
+
+ bool bArrayElement;
+ SbxBase* pSBX = ImplGetSBXForEntry(rIter, bArrayElement);
+
+ if (SbxVariable* pVar = IsSbxVariable(pSBX))
+ {
+ SbxDataType eType = pVar->GetType();
+ if ( static_cast<sal_uInt8>(eType) != sal_uInt8(SbxOBJECT)
+ && ( eType & SbxARRAY ) == 0 )
+ {
+ // If the type is variable, the conversion of the SBX does not matter,
+ // else the string is converted.
+ pVar->PutStringExt( aResult );
+ }
+ }
+
+ if ( SbxBase::IsError() )
+ {
+ SbxBase::ResetError();
+ }
+
+ UpdateWatches();
+
+ // The text should never be taken/copied 1:1,
+ // as the UpdateWatches will be lost
+ return false;
+}
+
+namespace
+{
+
+void implCollapseModifiedObjectEntry(const weld::TreeIter& rParent, weld::TreeView& rTree)
+{
+ rTree.collapse_row(rParent);
+
+ std::unique_ptr<weld::TreeIter> xDeleteEntry = rTree.make_iterator(&rParent);
+
+ while (rTree.iter_children(*xDeleteEntry))
+ {
+ implCollapseModifiedObjectEntry(*xDeleteEntry, rTree);
+
+ WatchItem* pItem = weld::fromId<WatchItem*>(rTree.get_id(*xDeleteEntry));
+ delete pItem;
+ rTree.remove(*xDeleteEntry);
+ rTree.copy_iterator(rParent, *xDeleteEntry);
+ }
+}
+
+OUString implCreateTypeStringForDimArray( WatchItem* pItem, SbxDataType eType )
+{
+ OUString aRetStr = getBasicTypeName( eType );
+
+ SbxDimArray* pArray = pItem->mpArray.get();
+ if( !pArray )
+ pArray = pItem->GetRootArray();
+ if( pArray )
+ {
+ int nDimLevel = pItem->nDimLevel;
+ int nDims = pItem->nDimCount;
+ if( nDimLevel < nDims )
+ {
+ aRetStr += "(";
+ for( int i = nDimLevel ; i < nDims ; i++ )
+ {
+ sal_Int32 nMin, nMax;
+ pArray->GetDim(sal::static_int_cast<sal_Int32>(i + 1), nMin, nMax);
+ aRetStr += OUString::number(nMin) + " to " + OUString::number(nMax);
+ if( i < nDims - 1 )
+ aRetStr += ", ";
+ }
+ aRetStr += ")";
+ }
+ }
+ return aRetStr;
+}
+
+} // namespace
+
+void WatchWindow::implEnableChildren(const weld::TreeIter& rEntry, bool bEnable)
+{
+ if (bEnable)
+ {
+ if (!m_xTreeListBox->get_row_expanded(rEntry))
+ m_xTreeListBox->set_children_on_demand(rEntry, true);
+ }
+ else
+ {
+ assert(!m_xTreeListBox->get_row_expanded(rEntry));
+ m_xTreeListBox->set_children_on_demand(rEntry, false);
+ }
+}
+
+void WatchWindow::UpdateWatches(bool bBasicStopped)
+{
+ SbMethod* pCurMethod = StarBASIC::GetActiveMethod();
+
+ ErrCode eOld = SbxBase::GetError();
+ setBasicWatchMode( true );
+
+ m_xTreeListBox->all_foreach([this, pCurMethod, bBasicStopped](weld::TreeIter& rEntry){
+ WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(rEntry));
+ DBG_ASSERT( !pItem->maName.isEmpty(), "Var? - Must not be empty!" );
+ OUString aWatchStr;
+ OUString aTypeStr;
+ if ( pCurMethod )
+ {
+ bool bCollapse = false;
+ TriState eEnableChildren = TRISTATE_INDET;
+
+ bool bArrayElement;
+ SbxBase* pSBX = ImplGetSBXForEntry(rEntry, bArrayElement);
+
+ // Array? If no end node create type string
+ if( bArrayElement && pItem->nDimLevel < pItem->nDimCount )
+ {
+ SbxDimArray* pRootArray = pItem->GetRootArray();
+ SbxDataType eType = pRootArray->GetType();
+ aTypeStr = implCreateTypeStringForDimArray( pItem, eType );
+ eEnableChildren = TRISTATE_TRUE;
+ }
+
+ if (SbxVariable* pVar = dynamic_cast<SbxVariable*>(pSBX))
+ {
+ // extra treatment of arrays
+ SbxDataType eType = pVar->GetType();
+ if ( eType & SbxARRAY )
+ {
+ // consider multidimensional arrays!
+ if (SbxDimArray* pNewArray = dynamic_cast<SbxDimArray*>(pVar->GetObject()))
+ {
+ SbxDimArray* pOldArray = pItem->mpArray.get();
+
+ bool bArrayChanged = false;
+ if (pOldArray != nullptr)
+ {
+ // Compare Array dimensions to see if array has changed
+ // Can be a copy, so comparing pointers does not work
+ sal_Int32 nOldDims = pOldArray->GetDims();
+ sal_Int32 nNewDims = pNewArray->GetDims();
+ if( nOldDims != nNewDims )
+ {
+ bArrayChanged = true;
+ }
+ else
+ {
+ for( sal_Int32 i = 0 ; i < nOldDims ; i++ )
+ {
+ sal_Int32 nOldMin, nOldMax;
+ sal_Int32 nNewMin, nNewMax;
+
+ pOldArray->GetDim(i + 1, nOldMin, nOldMax);
+ pNewArray->GetDim(i + 1, nNewMin, nNewMax);
+ if( nOldMin != nNewMin || nOldMax != nNewMax )
+ {
+ bArrayChanged = true;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ bArrayChanged = true;
+ }
+ eEnableChildren = TRISTATE_TRUE;
+ // #i37227 Clear always and replace array
+ if( pNewArray != pOldArray )
+ {
+ pItem->clearWatchItem();
+ eEnableChildren = TRISTATE_TRUE;
+
+ pItem->mpArray = pNewArray;
+ sal_Int32 nDims = pNewArray->GetDims();
+ pItem->nDimLevel = 0;
+ pItem->nDimCount = nDims;
+ }
+ if( bArrayChanged && pOldArray != nullptr )
+ {
+ bCollapse = true;
+ }
+ aTypeStr = implCreateTypeStringForDimArray( pItem, eType );
+ }
+ else
+ {
+ aWatchStr += "<?>";
+ }
+ }
+ else if ( static_cast<sal_uInt8>(eType) == sal_uInt8(SbxOBJECT) )
+ {
+ if (SbxObject* pObj = dynamic_cast<SbxObject*>(pVar->GetObject()))
+ {
+ if ( pItem->mpObject.is() && !pItem->maMemberList.empty() )
+ {
+ createAllObjectProperties(pObj);
+ SbxArray* pProps = pObj->GetProperties();
+ const sal_uInt32 nPropCount = getCorrectedPropCount(pProps);
+ // Check if member list has changed
+ bCollapse = pItem->maMemberList.size() != nPropCount;
+ for( sal_uInt32 i = 0 ; !bCollapse && i < nPropCount ; i++ )
+ {
+ SbxVariable* pVar_ = pProps->Get(i);
+ if( pItem->maMemberList[i] != pVar_->GetName() )
+ bCollapse = true;
+ }
+ }
+
+ pItem->mpObject = pObj;
+ eEnableChildren = TRISTATE_TRUE;
+ aTypeStr = getBasicObjectTypeName( pObj );
+ }
+ else
+ {
+ aWatchStr = "Null";
+ if( pItem->mpObject.is() )
+ {
+ bCollapse = true;
+ eEnableChildren = TRISTATE_FALSE;
+ }
+ }
+ }
+ else
+ {
+ if( pItem->mpObject.is() )
+ {
+ bCollapse = true;
+ eEnableChildren = TRISTATE_FALSE;
+ }
+
+ bool bString = (static_cast<sal_uInt8>(eType) == sal_uInt8(SbxSTRING));
+ OUString aStrStr( "\"" );
+ if( bString )
+ {
+ aWatchStr += aStrStr;
+ }
+ // tdf#57308 - avoid a second call to retrieve the data
+ const SbxFlagBits nFlags = pVar->GetFlags();
+ pVar->SetFlag(SbxFlagBits::NoBroadcast);
+ aWatchStr += pVar->GetOUString();
+ pVar->SetFlags(nFlags);
+ if( bString )
+ {
+ aWatchStr += aStrStr;
+ }
+ }
+ if( aTypeStr.isEmpty() )
+ {
+ if( !pVar->IsFixed() )
+ {
+ aTypeStr = "Variant/";
+ }
+ aTypeStr += getBasicTypeName( pVar->GetType() );
+ }
+ }
+ else if( !bArrayElement )
+ {
+ aWatchStr += "<Out of Scope>";
+ }
+
+ if( bCollapse )
+ {
+ implCollapseModifiedObjectEntry(rEntry, *m_xTreeListBox);
+ pItem->clearWatchItem();
+ }
+
+ if (eEnableChildren != TRISTATE_INDET)
+ implEnableChildren(rEntry, eEnableChildren == TRISTATE_TRUE);
+ }
+ else if( bBasicStopped )
+ {
+ if( pItem->mpObject.is() || pItem->mpArray.is() )
+ {
+ implCollapseModifiedObjectEntry(rEntry, *m_xTreeListBox);
+ pItem->mpObject.clear();
+ pItem->mpArray.clear();
+ }
+ pItem->clearWatchItem();
+ }
+
+ m_xTreeListBox->set_text(rEntry, aWatchStr, 1);
+ m_xTreeListBox->set_text(rEntry, aTypeStr, 2);
+
+ return false;
+ });
+
+ SbxBase::ResetError();
+ if( eOld != ERRCODE_NONE )
+ SbxBase::SetError( eOld );
+ setBasicWatchMode( false );
+}
+
+IMPL_LINK_NOARG(CodeCompleteWindow, ImplDoubleClickHdl, weld::TreeView&, bool)
+{
+ InsertSelectedEntry();
+ return true;
+}
+
+IMPL_LINK_NOARG(CodeCompleteWindow, ImplSelectHdl, weld::TreeView&, void)
+{
+ //give back the focus to the parent
+ pParent->GrabFocus();
+}
+
+TextView* CodeCompleteWindow::GetParentEditView()
+{
+ return pParent->GetEditView();
+}
+
+void CodeCompleteWindow::InsertSelectedEntry()
+{
+ OUString sSelectedEntry = m_xListBox->get_selected_text();
+
+ if( !aFuncBuffer.isEmpty() )
+ {
+ // if the user typed in something: remove, and insert
+ GetParentEditView()->SetSelection(pParent->GetLastHighlightPortionTextSelection());
+ GetParentEditView()->DeleteSelected();
+
+ if (!sSelectedEntry.isEmpty())
+ {
+ // if the user selected something
+ GetParentEditView()->InsertText(sSelectedEntry);
+ }
+ }
+ else
+ {
+ if (!sSelectedEntry.isEmpty())
+ {
+ // if the user selected something
+ GetParentEditView()->InsertText(sSelectedEntry);
+ }
+ }
+ HideAndRestoreFocus();
+}
+
+void CodeCompleteWindow::SetMatchingEntries()
+{
+ for (sal_Int32 i = 0, nEntryCount = m_xListBox->n_children(); i< nEntryCount; ++i)
+ {
+ OUString sEntry = m_xListBox->get_text(i);
+ if (sEntry.startsWithIgnoreAsciiCase(aFuncBuffer))
+ {
+ m_xListBox->select(i);
+ break;
+ }
+ }
+}
+
+IMPL_LINK(CodeCompleteWindow, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return HandleKeyInput(rKEvt);
+}
+
+bool CodeCompleteWindow::HandleKeyInput( const KeyEvent& rKeyEvt )
+{
+ bool bHandled = true;
+
+ sal_Unicode aChar = rKeyEvt.GetKeyCode().GetCode();
+ if( (( aChar >= KEY_A ) && ( aChar <= KEY_Z ))
+ || ((aChar >= KEY_0) && (aChar <= KEY_9)) )
+ {
+ aFuncBuffer.append(rKeyEvt.GetCharCode());
+ SetMatchingEntries();
+ }
+ else
+ {
+ switch( aChar )
+ {
+ case KEY_POINT:
+ break;
+ case KEY_ESCAPE: // hide, do nothing
+ HideAndRestoreFocus();
+ break;
+ case KEY_RIGHT:
+ {
+ TextSelection aTextSelection( GetParentEditView()->GetSelection() );
+ if( aTextSelection.GetEnd().GetPara() != GetTextSelection().GetEnd().GetPara()-1 )
+ {
+ HideAndRestoreFocus();
+ }
+ break;
+ }
+ case KEY_LEFT:
+ {
+ TextSelection aTextSelection( GetParentEditView()->GetSelection() );
+ if( aTextSelection.GetStart().GetIndex()-1 < GetTextSelection().GetStart().GetIndex() )
+ {//leave the cursor where it is
+ HideAndRestoreFocus();
+ }
+ break;
+ }
+ case KEY_TAB:
+ {
+ TextSelection aTextSelection = pParent->GetLastHighlightPortionTextSelection();
+ OUString sTypedText = pParent->GetEditEngine()->GetText(aTextSelection);
+ if( !aFuncBuffer.isEmpty() )
+ {
+ sal_Int32 nInd = m_xListBox->get_selected_index();
+ if (nInd != -1)
+ {
+ int nEntryCount = m_xListBox->n_children();
+ //if there is something selected
+ bool bFound = false;
+ for (sal_Int32 i = nInd; i != nEntryCount; ++i)
+ {
+ OUString sEntry = m_xListBox->get_text(i);
+ if( sEntry.startsWithIgnoreAsciiCase( aFuncBuffer )
+ && (std::u16string_view(aFuncBuffer) != sTypedText) && (i != nInd) )
+ {
+ m_xListBox->select(i);
+ bFound = true;
+ break;
+ }
+ }
+ if( !bFound )
+ SetMatchingEntries();
+
+ GetParentEditView()->SetSelection( aTextSelection );
+ GetParentEditView()->DeleteSelected();
+ GetParentEditView()->InsertText(m_xListBox->get_selected_text());
+ }
+ }
+ break;
+ }
+ case KEY_SPACE:
+ HideAndRestoreFocus();
+ break;
+ case KEY_BACKSPACE: case KEY_DELETE:
+ if( !aFuncBuffer.isEmpty() )
+ {
+ //if there was something inserted by tab: add it to aFuncBuffer
+ TextSelection aSel( GetParentEditView()->GetSelection() );
+ TextPaM aEnd( GetParentEditView()->CursorEndOfLine(GetTextSelection().GetEnd()) );
+ GetParentEditView()->SetSelection(TextSelection(GetTextSelection().GetStart(), aEnd ) );
+ OUString aTabInsertedStr( GetParentEditView()->GetSelected() );
+ GetParentEditView()->SetSelection( aSel );
+
+ if( !aTabInsertedStr.isEmpty() && aTabInsertedStr != std::u16string_view(aFuncBuffer) )
+ {
+ aFuncBuffer = aTabInsertedStr;
+ }
+ aFuncBuffer.remove(aFuncBuffer.getLength()-1, 1);
+ SetMatchingEntries();
+ }
+ else
+ {
+ ClearAndHide();
+ bHandled = false;
+ }
+ break;
+ case KEY_RETURN:
+ InsertSelectedEntry();
+ break;
+ case KEY_UP:
+ {
+ int nInd = m_xListBox->get_selected_index();
+ if (nInd)
+ m_xListBox->select(nInd - 1);
+ break;
+ }
+ case KEY_DOWN:
+ {
+ int nInd = m_xListBox->get_selected_index();
+ if (nInd + 1 < m_xListBox->n_children())
+ m_xListBox->select(nInd + 1);
+ break;
+ }
+ default:
+ bHandled = false;
+ break;
+ }
+ }
+
+ return bHandled;
+}
+
+void CodeCompleteWindow::HideAndRestoreFocus()
+{
+ Hide();
+ pParent->GrabFocus();
+}
+
+CodeCompleteWindow::CodeCompleteWindow(EditorWindow* pPar)
+ : InterimItemWindow(pPar, "modules/BasicIDE/ui/codecomplete.ui", "CodeComplete")
+ , pParent(pPar)
+ , m_xListBox(m_xBuilder->weld_tree_view("treeview"))
+{
+ m_xListBox->connect_row_activated(LINK(this, CodeCompleteWindow, ImplDoubleClickHdl));
+ m_xListBox->connect_changed(LINK(this, CodeCompleteWindow, ImplSelectHdl));
+ m_xListBox->connect_key_press(LINK(this, CodeCompleteWindow, KeyInputHdl));
+ m_xListBox->make_sorted();
+
+ m_xListBox->set_size_request(150, 150); // default, this will adopt the line length
+ SetSizePixel(m_xContainer->get_preferred_size());
+}
+
+CodeCompleteWindow::~CodeCompleteWindow()
+{
+ disposeOnce();
+}
+
+void CodeCompleteWindow::dispose()
+{
+ m_xListBox.reset();
+ pParent.clear();
+ InterimItemWindow::dispose();
+}
+
+void CodeCompleteWindow::InsertEntry( const OUString& aStr )
+{
+ m_xListBox->append_text(aStr);
+}
+
+void CodeCompleteWindow::ClearListBox()
+{
+ m_xListBox->clear();
+ aFuncBuffer.setLength(0);
+}
+
+void CodeCompleteWindow::SetTextSelection( const TextSelection& aSel )
+{
+ m_aTextSelection = aSel;
+}
+
+void CodeCompleteWindow::ResizeAndPositionListBox()
+{
+ if (m_xListBox->n_children() < 1)
+ return;
+
+ // if there is at least one element inside
+ // calculate basic position: under the current line
+ tools::Rectangle aRect = static_cast<TextEngine*>(pParent->GetEditEngine())->PaMtoEditCursor( pParent->GetEditView()->GetSelection().GetEnd() );
+ tools::Long nViewYOffset = pParent->GetEditView()->GetStartDocPos().Y();
+ Point aPos = aRect.BottomRight();// this variable will be used later (if needed)
+ aPos.setY( (aPos.Y() - nViewYOffset) + nBasePad );
+
+ // get line count
+ const sal_uInt16 nLines = static_cast<sal_uInt16>(std::min(6, m_xListBox->n_children()));
+
+ m_xListBox->set_size_request(-1, m_xListBox->get_height_rows(nLines));
+
+ Size aSize = m_xContainer->get_preferred_size();
+ //set the size
+ SetSizePixel( aSize );
+
+ //calculate position
+ const tools::Rectangle aVisArea( pParent->GetEditView()->GetStartDocPos(), pParent->GetOutputSizePixel() ); //the visible area
+ const Point& aBottomPoint = aVisArea.BottomRight();
+
+ if( aVisArea.TopRight().getY() + aPos.getY() + aSize.getHeight() > aBottomPoint.getY() )
+ {//clipped at the bottom: move it up
+ const tools::Long& nParentFontHeight = pParent->GetEditEngine()->GetFont().GetFontHeight(); //parent's font (in the IDE): needed for height
+ aPos.AdjustY( -(aSize.getHeight() + nParentFontHeight + nCursorPad) );
+ }
+
+ if( aVisArea.TopLeft().getX() + aPos.getX() + aSize.getWidth() > aBottomPoint.getX() )
+ {//clipped at the right side, move it a bit left
+ aPos.AdjustX( -(aSize.getWidth() + aVisArea.TopLeft().getX()) );
+ }
+ //set the position
+ SetPosPixel( aPos );
+}
+
+void CodeCompleteWindow::SelectFirstEntry()
+{
+ if (m_xListBox->n_children() > 0)
+ m_xListBox->select(0);
+}
+
+void CodeCompleteWindow::ClearAndHide()
+{
+ ClearListBox();
+ HideAndRestoreFocus();
+}
+
+UnoTypeCodeCompletetor::UnoTypeCodeCompletetor( const std::vector< OUString >& aVect, const OUString& sVarType )
+: bCanComplete( true )
+{
+ if( aVect.empty() || sVarType.isEmpty() )
+ {
+ bCanComplete = false;//invalid parameters, nothing to code complete
+ return;
+ }
+
+ try
+ {
+ // Get the base class for reflection:
+ xClass = css::reflection::theCoreReflection::get(
+ comphelper::getProcessComponentContext())->forName(sVarType);
+ }
+ catch( const Exception& )
+ {
+ bCanComplete = false;
+ return;
+ }
+
+ //start from aVect[1]: aVect[0] is the variable name
+ bCanComplete = std::none_of(aVect.begin() + 1, aVect.end(), [this](const OUString& rMethName) {
+ return (!CodeCompleteOptions::IsExtendedTypeDeclaration() || !CheckMethod(rMethName)) && !CheckField(rMethName); });
+}
+
+std::vector< OUString > UnoTypeCodeCompletetor::GetXIdlClassMethods() const
+{
+ std::vector< OUString > aRetVect;
+ if( bCanComplete && ( xClass != nullptr ) )
+ {
+ const Sequence< Reference< reflection::XIdlMethod > > aMethods = xClass->getMethods();
+ for(Reference< reflection::XIdlMethod > const & rMethod : aMethods)
+ {
+ aRetVect.push_back( rMethod->getName() );
+ }
+ }
+ return aRetVect;//this is empty when cannot code complete
+}
+
+std::vector< OUString > UnoTypeCodeCompletetor::GetXIdlClassFields() const
+{
+ std::vector< OUString > aRetVect;
+ if( bCanComplete && ( xClass != nullptr ) )
+ {
+ const Sequence< Reference< reflection::XIdlField > > aFields = xClass->getFields();
+ for(Reference< reflection::XIdlField > const & rxField : aFields)
+ {
+ aRetVect.push_back( rxField->getName() );
+ }
+ }
+ return aRetVect;//this is empty when cannot code complete
+}
+
+
+bool UnoTypeCodeCompletetor::CheckField( const OUString& sFieldName )
+{// modifies xClass!!!
+
+ if ( xClass == nullptr )
+ return false;
+
+ Reference< reflection::XIdlField> xField = xClass->getField( sFieldName );
+ if( xField != nullptr )
+ {
+ xClass = xField->getType();
+ if( xClass != nullptr )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool UnoTypeCodeCompletetor::CheckMethod( const OUString& sMethName )
+{// modifies xClass!!!
+
+
+ if ( xClass == nullptr )
+ return false;
+
+ Reference< reflection::XIdlMethod> xMethod = xClass->getMethod( sMethName );
+ if( xMethod != nullptr ) //method OK, check return type
+ {
+ xClass = xMethod->getReturnType();
+ if( xClass != nullptr )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/baside3.cxx b/basctl/source/basicide/baside3.cxx
new file mode 100644
index 000000000..1424573b0
--- /dev/null
+++ b/basctl/source/basicide/baside3.cxx
@@ -0,0 +1,1383 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <strings.hrc>
+#include <helpids.h>
+#include <iderid.hxx>
+
+#include <accessibledialogwindow.hxx>
+#include <baside3.hxx>
+#include <basidesh.hxx>
+#include <bastype2.hxx>
+#include <basobj.hxx>
+#include <dlged.hxx>
+#include <dlgeddef.hxx>
+#include <dlgedmod.hxx>
+#include <dlgedview.hxx>
+#include <iderdll.hxx>
+#include <localizationmgr.hxx>
+#include <managelang.hxx>
+
+#include <com/sun/star/script/XLibraryContainer2.hpp>
+#include <com/sun/star/resource/StringResourceWithLocation.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
+#include <comphelper/processfactory.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/visitem.hxx>
+#include <svl/whiter.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svxids.hrc>
+#include <tools/diagnose_ex.h>
+#include <tools/urlobj.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/svapp.hxx>
+#include <xmlscript/xmldlg_imexp.hxx>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::resource;
+using namespace ::com::sun::star::ui::dialogs;
+
+#ifdef _WIN32
+OUStringLiteral const FilterMask_All = u"*.*";
+#else
+constexpr OUStringLiteral FilterMask_All = u"*";
+#endif
+
+DialogWindow::DialogWindow(DialogWindowLayout* pParent, ScriptDocument const& rDocument,
+ const OUString& aLibName, const OUString& aName,
+ css::uno::Reference<css::container::XNameContainer> const& xDialogModel)
+ : BaseWindow(pParent, rDocument, aLibName, aName)
+ ,m_rLayout(*pParent)
+ ,m_pEditor(new DlgEditor(*this, m_rLayout, rDocument.isDocument()
+ ? rDocument.getDocument()
+ : Reference<frame::XModel>(), xDialogModel))
+ ,m_pUndoMgr(new SfxUndoManager)
+ ,m_nControlSlotId(SID_INSERT_SELECT)
+{
+ InitSettings();
+
+ m_pEditor->GetModel().SetNotifyUndoActionHdl(
+ &DialogWindow::NotifyUndoActionHdl
+ );
+
+ SetHelpId( HID_BASICIDE_DIALOGWINDOW );
+
+ // set readonly mode for readonly libraries
+ Reference< script::XLibraryContainer2 > xDlgLibContainer( GetDocument().getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+ if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) )
+ SetReadOnly(true);
+
+ if ( rDocument.isDocument() && rDocument.isReadOnly() )
+ SetReadOnly(true);
+}
+
+void DialogWindow::dispose()
+{
+ m_pEditor.reset();
+ BaseWindow::dispose();
+}
+
+void DialogWindow::LoseFocus()
+{
+ if ( IsModified() )
+ StoreData();
+
+ Window::LoseFocus();
+}
+
+void DialogWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ m_pEditor->Paint(rRenderContext, rRect);
+}
+
+void DialogWindow::Resize()
+{
+ if (GetHScrollBar() && GetVScrollBar())
+ {
+ m_pEditor->SetScrollBars( GetHScrollBar(), GetVScrollBar() );
+ }
+}
+
+void DialogWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ m_pEditor->MouseButtonDown( rMEvt );
+
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_SHOW_PROPERTYBROWSER );
+}
+
+void DialogWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ m_pEditor->MouseButtonUp( rMEvt );
+ if( (m_pEditor->GetMode() == DlgEditor::INSERT) && !m_pEditor->IsCreateOK() )
+ {
+ m_nControlSlotId = SID_INSERT_SELECT;
+ m_pEditor->SetMode( DlgEditor::SELECT );
+ Shell::InvalidateControlSlots();
+ }
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate( SID_SHOW_PROPERTYBROWSER );
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+ pBindings->Invalidate( SID_SAVEDOC );
+ pBindings->Invalidate( SID_COPY );
+ pBindings->Invalidate( SID_CUT );
+ }
+}
+
+void DialogWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ m_pEditor->MouseMove( rMEvt );
+}
+
+void DialogWindow::KeyInput( const KeyEvent& rKEvt )
+{
+ SfxBindings* pBindings = GetBindingsPtr();
+
+ if( rKEvt.GetKeyCode() == KEY_BACKSPACE )
+ {
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ pDispatcher->Execute( SID_BACKSPACE );
+ }
+ else
+ {
+ if( pBindings && rKEvt.GetKeyCode() == KEY_TAB )
+ pBindings->Invalidate( SID_SHOW_PROPERTYBROWSER );
+
+ if( !m_pEditor->KeyInput( rKEvt ) )
+ {
+ if( !SfxViewShell::Current()->KeyInput( rKEvt ) )
+ Window::KeyInput( rKEvt );
+ }
+ }
+
+ // may be KEY_TAB, KEY_BACKSPACE, KEY_ESCAPE
+ if( pBindings )
+ {
+ pBindings->Invalidate( SID_COPY );
+ pBindings->Invalidate( SID_CUT );
+ }
+}
+
+void DialogWindow::Command( const CommandEvent& rCEvt )
+{
+ if ( ( rCEvt.GetCommand() == CommandEventId::Wheel ) ||
+ ( rCEvt.GetCommand() == CommandEventId::StartAutoScroll ) ||
+ ( rCEvt.GetCommand() == CommandEventId::AutoScroll ) )
+ {
+ HandleScrollCommand( rCEvt, GetHScrollBar(), GetVScrollBar() );
+ }
+ else if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
+ {
+ if (GetDispatcher())
+ {
+ SdrView& rView = GetView();
+ if( !rCEvt.IsMouseEvent() && rView.AreObjectsMarked() )
+ {
+ tools::Rectangle aMarkedRect( rView.GetMarkedRect() );
+ Point MarkedCenter( aMarkedRect.Center() );
+ Point PosPixel( LogicToPixel( MarkedCenter ) );
+ SfxDispatcher::ExecutePopup( this, &PosPixel );
+ }
+ else
+ {
+ SfxDispatcher::ExecutePopup();
+ }
+
+ }
+ }
+ else
+ BaseWindow::Command( rCEvt );
+}
+
+
+void DialogWindow::NotifyUndoActionHdl( std::unique_ptr<SdrUndoAction> )
+{
+ // #i120515# pUndoAction needs to be deleted, this hand over is an ownership
+ // change. As long as it does not get added to the undo manager, it needs at
+ // least to be deleted.
+}
+
+void DialogWindow::DoInit()
+{
+ GetHScrollBar()->Show();
+ GetVScrollBar()->Show();
+ m_pEditor->SetScrollBars( GetHScrollBar(), GetVScrollBar() );
+}
+
+void DialogWindow::DoScroll( ScrollBar* )
+{
+ m_pEditor->DoScroll();
+}
+
+void DialogWindow::GetState( SfxItemSet& rSet )
+{
+ SfxWhichIter aIter(rSet);
+ bool bIsCalc = false;
+ if ( GetDocument().isDocument() )
+ {
+ Reference< frame::XModel > xModel= GetDocument().getDocument();
+ if ( xModel.is() )
+ {
+ Reference< lang::XServiceInfo > xServiceInfo ( xModel, UNO_QUERY );
+ if ( xServiceInfo.is() && xServiceInfo->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) )
+ bIsCalc = true;
+ }
+ }
+
+ for ( sal_uInt16 nWh = aIter.FirstWhich(); nWh != 0; nWh = aIter.NextWhich() )
+ {
+ switch ( nWh )
+ {
+ case SID_PASTE:
+ {
+ if ( !IsPasteAllowed() )
+ rSet.DisableItem( nWh );
+
+ if ( IsReadOnly() )
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_COPY:
+ {
+ // any object selected?
+ if ( !m_pEditor->GetView().AreObjectsMarked() )
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_CUT:
+ case SID_DELETE:
+ case SID_BACKSPACE:
+ {
+ // any object selected?
+ if ( !m_pEditor->GetView().AreObjectsMarked() )
+ rSet.DisableItem( nWh );
+
+ if ( IsReadOnly() )
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_REDO:
+ {
+ if ( !m_pUndoMgr->GetUndoActionCount() )
+ rSet.DisableItem( nWh );
+ }
+ break;
+
+ case SID_DIALOG_TESTMODE:
+ {
+ // is the IDE still active?
+ bool const bBool = GetShell()->GetFrame() &&
+ m_pEditor->GetMode() == DlgEditor::TEST;
+ rSet.Put(SfxBoolItem(SID_DIALOG_TESTMODE, bBool));
+ }
+ break;
+
+ case SID_CHOOSE_CONTROLS:
+ {
+ if ( IsReadOnly() )
+ rSet.DisableItem( nWh );
+ }
+ break;
+
+ case SID_SHOW_PROPERTYBROWSER:
+ {
+ Shell* pShell = GetShell();
+ SfxViewFrame* pViewFrame = pShell ? pShell->GetViewFrame() : nullptr;
+ if ( pViewFrame && !pViewFrame->HasChildWindow( SID_SHOW_PROPERTYBROWSER ) && !m_pEditor->GetView().AreObjectsMarked() )
+ rSet.DisableItem( nWh );
+
+ if ( IsReadOnly() )
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_INSERT_FORM_RADIO:
+ case SID_INSERT_FORM_CHECK:
+ case SID_INSERT_FORM_LIST:
+ case SID_INSERT_FORM_COMBO:
+ case SID_INSERT_FORM_VSCROLL:
+ case SID_INSERT_FORM_HSCROLL:
+ case SID_INSERT_FORM_SPIN:
+ {
+ if ( !bIsCalc || IsReadOnly() )
+ rSet.DisableItem( nWh );
+ else
+ rSet.Put( SfxBoolItem( nWh, m_nControlSlotId == nWh ) );
+ }
+ break;
+
+ case SID_INSERT_SELECT:
+ case SID_INSERT_PUSHBUTTON:
+ case SID_INSERT_RADIOBUTTON:
+ case SID_INSERT_CHECKBOX:
+ case SID_INSERT_LISTBOX:
+ case SID_INSERT_COMBOBOX:
+ case SID_INSERT_GROUPBOX:
+ case SID_INSERT_EDIT:
+ case SID_INSERT_FIXEDTEXT:
+ case SID_INSERT_IMAGECONTROL:
+ case SID_INSERT_PROGRESSBAR:
+ case SID_INSERT_HSCROLLBAR:
+ case SID_INSERT_VSCROLLBAR:
+ case SID_INSERT_HFIXEDLINE:
+ case SID_INSERT_VFIXEDLINE:
+ case SID_INSERT_DATEFIELD:
+ case SID_INSERT_TIMEFIELD:
+ case SID_INSERT_NUMERICFIELD:
+ case SID_INSERT_CURRENCYFIELD:
+ case SID_INSERT_FORMATTEDFIELD:
+ case SID_INSERT_PATTERNFIELD:
+ case SID_INSERT_FILECONTROL:
+ case SID_INSERT_SPINBUTTON:
+ case SID_INSERT_GRIDCONTROL:
+ case SID_INSERT_HYPERLINKCONTROL:
+ case SID_INSERT_TREECONTROL:
+ {
+ if ( IsReadOnly() )
+ rSet.DisableItem( nWh );
+ else
+ rSet.Put( SfxBoolItem( nWh, m_nControlSlotId == nWh ) );
+ }
+ break;
+ case SID_SHOWLINES:
+ {
+ // if this is not a module window hide the
+ // setting, doesn't make sense for example if the
+ // dialog editor is open
+ rSet.DisableItem(nWh);
+ rSet.Put(SfxVisibilityItem(nWh, false));
+ break;
+ }
+ case SID_SELECTALL:
+ {
+ rSet.DisableItem( nWh );
+ }
+ break;
+ }
+ }
+}
+
+void DialogWindow::ExecuteCommand( SfxRequest& rReq )
+{
+ const sal_uInt16 nSlotId(rReq.GetSlot());
+ SdrObjKind nInsertObj(SdrObjKind::NONE);
+
+ switch ( nSlotId )
+ {
+ case SID_CUT:
+ if ( !IsReadOnly() )
+ {
+ GetEditor().Cut();
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+ }
+ break;
+ case SID_DELETE:
+ if ( !IsReadOnly() )
+ {
+ GetEditor().Delete();
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+ }
+ break;
+ case SID_COPY:
+ GetEditor().Copy();
+ break;
+ case SID_PASTE:
+ if ( !IsReadOnly() )
+ {
+ GetEditor().Paste();
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+ }
+ break;
+
+ case SID_INSERT_FORM_RADIO:
+ nInsertObj = SdrObjKind::BasicDialogFormRadio;
+ break;
+ case SID_INSERT_FORM_CHECK:
+ nInsertObj = SdrObjKind::BasicDialogFormCheck;
+ break;
+ case SID_INSERT_FORM_LIST:
+ nInsertObj = SdrObjKind::BasicDialogFormList;
+ break;
+ case SID_INSERT_FORM_COMBO:
+ nInsertObj = SdrObjKind::BasicDialogFormCombo;
+ break;
+ case SID_INSERT_FORM_SPIN:
+ nInsertObj = SdrObjKind::BasicDialogFormSpin;
+ break;
+ case SID_INSERT_FORM_VSCROLL:
+ nInsertObj = SdrObjKind::BasicDialogFormVerticalScroll;
+ break;
+ case SID_INSERT_FORM_HSCROLL:
+ nInsertObj = SdrObjKind::BasicDialogFormHorizontalScroll;
+ break;
+ case SID_INSERT_PUSHBUTTON:
+ nInsertObj = SdrObjKind::BasicDialogPushButton;
+ break;
+ case SID_INSERT_RADIOBUTTON:
+ nInsertObj = SdrObjKind::BasicDialogRadioButton;
+ break;
+ case SID_INSERT_CHECKBOX:
+ nInsertObj = SdrObjKind::BasicDialogCheckbox;
+ break;
+ case SID_INSERT_LISTBOX:
+ nInsertObj = SdrObjKind::BasicDialogListbox;
+ break;
+ case SID_INSERT_COMBOBOX:
+ nInsertObj = SdrObjKind::BasicDialogCombobox;
+ break;
+ case SID_INSERT_GROUPBOX:
+ nInsertObj = SdrObjKind::BasicDialogGroupBox;
+ break;
+ case SID_INSERT_EDIT:
+ nInsertObj = SdrObjKind::BasicDialogEdit;
+ break;
+ case SID_INSERT_FIXEDTEXT:
+ nInsertObj = SdrObjKind::BasicDialogFixedText;
+ break;
+ case SID_INSERT_IMAGECONTROL:
+ nInsertObj = SdrObjKind::BasicDialogImageControl;
+ break;
+ case SID_INSERT_PROGRESSBAR:
+ nInsertObj = SdrObjKind::BasicDialogProgressbar;
+ break;
+ case SID_INSERT_HSCROLLBAR:
+ nInsertObj = SdrObjKind::BasicDialogHorizontalScrollbar;
+ break;
+ case SID_INSERT_VSCROLLBAR:
+ nInsertObj = SdrObjKind::BasicDialogVerticalScrollbar;
+ break;
+ case SID_INSERT_HFIXEDLINE:
+ nInsertObj = SdrObjKind::BasicDialogHorizontalFixedLine;
+ break;
+ case SID_INSERT_VFIXEDLINE:
+ nInsertObj = SdrObjKind::BasicDialogVerticalFixedLine;
+ break;
+ case SID_INSERT_DATEFIELD:
+ nInsertObj = SdrObjKind::BasicDialogDateField;
+ break;
+ case SID_INSERT_TIMEFIELD:
+ nInsertObj = SdrObjKind::BasicDialogTimeField;
+ break;
+ case SID_INSERT_NUMERICFIELD:
+ nInsertObj = SdrObjKind::BasicDialogNumericField;
+ break;
+ case SID_INSERT_CURRENCYFIELD:
+ nInsertObj = SdrObjKind::BasicDialogCurencyField;
+ break;
+ case SID_INSERT_FORMATTEDFIELD:
+ nInsertObj = SdrObjKind::BasicDialogFormattedField;
+ break;
+ case SID_INSERT_PATTERNFIELD:
+ nInsertObj = SdrObjKind::BasicDialogPatternField;
+ break;
+ case SID_INSERT_FILECONTROL:
+ nInsertObj = SdrObjKind::BasicDialogFileControl;
+ break;
+ case SID_INSERT_SPINBUTTON:
+ nInsertObj = SdrObjKind::BasicDialogSpinButton;
+ break;
+ case SID_INSERT_GRIDCONTROL:
+ nInsertObj = SdrObjKind::BasicDialogGridControl;
+ break;
+ case SID_INSERT_HYPERLINKCONTROL:
+ nInsertObj = SdrObjKind::BasicDialogHyperlinkControl;
+ break;
+ case SID_INSERT_TREECONTROL:
+ nInsertObj = SdrObjKind::BasicDialogTreeControl;
+ break;
+ case SID_INSERT_SELECT:
+ m_nControlSlotId = nSlotId;
+ GetEditor().SetMode( DlgEditor::SELECT );
+ Shell::InvalidateControlSlots();
+ break;
+
+ case SID_DIALOG_TESTMODE:
+ {
+ DlgEditor::Mode eOldMode = GetEditor().GetMode();
+ GetEditor().SetMode( DlgEditor::TEST );
+ GetEditor().SetMode( eOldMode );
+ rReq.Done();
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_DIALOG_TESTMODE );
+ return;
+ }
+ case SID_EXPORT_DIALOG:
+ SaveDialog();
+ break;
+
+ case SID_IMPORT_DIALOG:
+ ImportDialog();
+ break;
+
+ case SID_BASICIDE_DELETECURRENT:
+ if (QueryDelDialog(m_aName, GetFrameWeld()))
+ {
+ if (RemoveDialog(m_aDocument, m_aLibName, m_aName))
+ {
+ MarkDocumentModified(m_aDocument);
+ GetShell()->RemoveWindow(this, true);
+ }
+ }
+ break;
+ }
+
+ if ( nInsertObj != SdrObjKind::NONE )
+ {
+ m_nControlSlotId = nSlotId;
+ GetEditor().SetMode( DlgEditor::INSERT );
+ GetEditor().SetInsertObj( nInsertObj );
+
+ if ( rReq.GetModifier() & KEY_MOD1 )
+ {
+ GetEditor().CreateDefaultObject();
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+ }
+
+ Shell::InvalidateControlSlots();
+ }
+
+ rReq.Done();
+}
+
+Reference< container::XNameContainer > const & DialogWindow::GetDialog() const
+{
+ return m_pEditor->GetDialog();
+}
+
+bool DialogWindow::RenameDialog( const OUString& rNewName )
+{
+ if (!basctl::RenameDialog(GetFrameWeld(), GetDocument(), GetLibName(), GetName(), rNewName))
+ return false;
+
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+
+ return true;
+}
+
+void DialogWindow::DisableBrowser()
+{
+ m_rLayout.DisablePropertyBrowser();
+}
+
+void DialogWindow::UpdateBrowser()
+{
+ m_rLayout.UpdatePropertyBrowser();
+}
+
+void DialogWindow::SaveDialog()
+{
+ Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
+ sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD,
+ FileDialogFlags::NONE, this->GetFrameWeld());
+ aDlg.SetContext(sfx2::FileDialogHelper::BasicExportDialog);
+ Reference<XFilePicker3> xFP = aDlg.GetFilePicker();
+
+ Reference< XFilePickerControlAccess > xFPControl(xFP, UNO_QUERY);
+ xFPControl->enableControl(ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, false);
+ Any aValue;
+ aValue <<= true;
+ xFPControl->setValue(ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0, aValue);
+
+ xFP->setDefaultName( GetName() );
+
+ OUString aDialogStr(IDEResId(RID_STR_STDDIALOGNAME));
+ xFP->appendFilter( aDialogStr, "*.xdl" );
+ xFP->appendFilter( IDEResId(RID_STR_FILTER_ALLFILES), FilterMask_All );
+ xFP->setCurrentFilter( aDialogStr );
+
+ if( aDlg.Execute() != ERRCODE_NONE )
+ return;
+
+ Sequence< OUString > aPaths = xFP->getSelectedFiles();
+
+ // export dialog model to xml
+ Reference< container::XNameContainer > xDialogModel = GetDialog();
+ Reference< XInputStreamProvider > xISP = ::xmlscript::exportDialogModel( xDialogModel, xContext, GetDocument().isDocument() ? GetDocument().getDocument() : Reference< frame::XModel >() );
+ Reference< XInputStream > xInput( xISP->createInputStream() );
+
+ Reference< XSimpleFileAccess3 > xSFI( SimpleFileAccess::create(xContext) );
+
+ Reference< XOutputStream > xOutput;
+ try
+ {
+ if( xSFI->exists( aPaths[0] ) )
+ xSFI->kill( aPaths[0] );
+ xOutput = xSFI->openFileWrite( aPaths[0] );
+ }
+ catch(const Exception& )
+ {}
+
+ if( xOutput.is() )
+ {
+ Sequence< sal_Int8 > bytes;
+ sal_Int32 nRead = xInput->readBytes( bytes, xInput->available() );
+ for (;;)
+ {
+ if( nRead )
+ xOutput->writeBytes( bytes );
+
+ nRead = xInput->readBytes( bytes, 1024 );
+ if (! nRead)
+ break;
+ }
+
+ // With resource?
+ Reference< beans::XPropertySet > xDialogModelPropSet( xDialogModel, UNO_QUERY );
+ Reference< resource::XStringResourceResolver > xStringResourceResolver;
+ if( xDialogModelPropSet.is() )
+ {
+ try
+ {
+ Any aResourceResolver = xDialogModelPropSet->getPropertyValue( "ResourceResolver" );
+ aResourceResolver >>= xStringResourceResolver;
+ }
+ catch(const beans::UnknownPropertyException& )
+ {}
+ }
+
+ bool bResource = false;
+ if( xStringResourceResolver.is() )
+ {
+ Sequence< lang::Locale > aLocaleSeq = xStringResourceResolver->getLocales();
+ if( aLocaleSeq.hasElements() )
+ bResource = true;
+ }
+
+ if( bResource )
+ {
+ INetURLObject aURLObj(u"");
+ aURLObj.removeExtension();
+ OUString aDialogName( aURLObj.getName() );
+ aURLObj.removeSegment();
+ OUString aURL( aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ OUString aComment = "# " + aDialogName + " strings" ;
+ Reference< task::XInteractionHandler > xDummyHandler;
+
+ // Remove old properties files in case of overwriting Dialog files
+ if( xSFI->isFolder( aURL ) )
+ {
+ Sequence< OUString > aContentSeq = xSFI->getFolderContents( aURL, false );
+
+ OUString aDialogName_ = aDialogName + "_" ;
+ sal_Int32 nCount = aContentSeq.getLength();
+ const OUString* pFiles = aContentSeq.getConstArray();
+ for( int i = 0 ; i < nCount ; i++ )
+ {
+ OUString aCompleteName = pFiles[i];
+ OUString aPureName;
+ OUString aExtension;
+ sal_Int32 iDot = aCompleteName.lastIndexOf( '.' );
+ sal_Int32 iSlash = aCompleteName.lastIndexOf( '/' );
+ if( iDot != -1 )
+ {
+ sal_Int32 iCopyFrom = (iSlash != -1) ? iSlash + 1 : 0;
+ aPureName = aCompleteName.copy( iCopyFrom, iDot-iCopyFrom );
+ aExtension = aCompleteName.copy( iDot + 1 );
+ }
+
+ if( aExtension == "properties" || aExtension == "default" )
+ {
+ if( aPureName.startsWith( aDialogName_ ) )
+ {
+ try
+ {
+ xSFI->kill( aCompleteName );
+ }
+ catch(const uno::Exception& )
+ {}
+ }
+ }
+ }
+ }
+
+ Reference< XStringResourceWithLocation > xStringResourceWithLocation =
+ StringResourceWithLocation::create( xContext, aURL, false/*bReadOnly*/,
+ xStringResourceResolver->getDefaultLocale(), aDialogName, aComment, xDummyHandler );
+
+ // Add locales
+ Sequence< lang::Locale > aLocaleSeq = xStringResourceResolver->getLocales();
+ const lang::Locale* pLocales = aLocaleSeq.getConstArray();
+ sal_Int32 nLocaleCount = aLocaleSeq.getLength();
+ for( sal_Int32 iLocale = 0 ; iLocale < nLocaleCount ; iLocale++ )
+ {
+ const lang::Locale& rLocale = pLocales[ iLocale ];
+ xStringResourceWithLocation->newLocale( rLocale );
+ }
+
+ LocalizationMgr::copyResourceForDialog( xDialogModel,
+ xStringResourceResolver, xStringResourceWithLocation );
+
+ xStringResourceWithLocation->store();
+ }
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_COULDNTWRITE)));
+ xBox->run();
+ }
+}
+
+static std::vector< lang::Locale > implGetLanguagesOnlyContainedInFirstSeq
+ ( const Sequence< lang::Locale >& aFirstSeq, const Sequence< lang::Locale >& aSecondSeq )
+{
+ std::vector< lang::Locale > avRet;
+
+ const lang::Locale* pFirst = aFirstSeq.getConstArray();
+ const lang::Locale* pSecond = aSecondSeq.getConstArray();
+ sal_Int32 nFirstCount = aFirstSeq.getLength();
+ sal_Int32 nSecondCount = aSecondSeq.getLength();
+
+ for( sal_Int32 iFirst = 0 ; iFirst < nFirstCount ; iFirst++ )
+ {
+ const lang::Locale& rFirstLocale = pFirst[ iFirst ];
+
+ bool bAlsoContainedInSecondSeq = false;
+ for( sal_Int32 iSecond = 0 ; iSecond < nSecondCount ; iSecond++ )
+ {
+ const lang::Locale& rSecondLocale = pSecond[ iSecond ];
+
+ bool bMatch = localesAreEqual( rFirstLocale, rSecondLocale );
+ if( bMatch )
+ {
+ bAlsoContainedInSecondSeq = true;
+ break;
+ }
+ }
+
+ if( !bAlsoContainedInSecondSeq )
+ avRet.push_back( rFirstLocale );
+ }
+
+ return avRet;
+}
+
+namespace {
+
+class NameClashQueryBox
+{
+private:
+ std::unique_ptr<weld::MessageDialog> m_xQueryBox;
+public:
+ NameClashQueryBox(weld::Window* pParent, const OUString& rTitle, const OUString& rMessage)
+ : m_xQueryBox(Application::CreateMessageDialog(pParent, VclMessageType::Question, VclButtonsType::NONE, rMessage))
+ {
+ if (!rTitle.isEmpty())
+ m_xQueryBox->set_title(rTitle);
+ m_xQueryBox->add_button(IDEResId(RID_STR_DLGIMP_CLASH_RENAME), RET_YES);
+ m_xQueryBox->add_button(IDEResId(RID_STR_DLGIMP_CLASH_REPLACE), RET_NO);
+ m_xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
+ m_xQueryBox->set_default_response(RET_YES);
+ }
+ short run() { return m_xQueryBox->run(); }
+};
+
+class LanguageMismatchQueryBox
+{
+private:
+ std::unique_ptr<weld::MessageDialog> m_xQueryBox;
+public:
+ LanguageMismatchQueryBox(weld::Window* pParent, const OUString& rTitle, const OUString& rMessage)
+ : m_xQueryBox(Application::CreateMessageDialog(pParent, VclMessageType::Question, VclButtonsType::NONE, rMessage))
+ {
+ if (!rTitle.isEmpty())
+ m_xQueryBox->set_title(rTitle);
+ m_xQueryBox->add_button(IDEResId(RID_STR_DLGIMP_MISMATCH_ADD), RET_YES);
+ m_xQueryBox->add_button(IDEResId(RID_STR_DLGIMP_MISMATCH_OMIT), RET_NO);
+ m_xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
+ m_xQueryBox->add_button(GetStandardText(StandardButtonType::Help), RET_HELP);
+ m_xQueryBox->set_default_response(RET_YES);
+ }
+ short run() { return m_xQueryBox->run(); }
+};
+
+}
+
+bool implImportDialog(weld::Window* pWin, const ScriptDocument& rDocument, const OUString& aLibName)
+{
+ bool bDone = false;
+
+ Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
+ sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
+ FileDialogFlags::NONE, pWin);
+ aDlg.SetContext(sfx2::FileDialogHelper::BasicImportDialog);
+ Reference<XFilePicker3> xFP = aDlg.GetFilePicker();
+
+ Reference< XFilePickerControlAccess > xFPControl(xFP, UNO_QUERY);
+ xFPControl->enableControl(ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, false);
+ Any aValue;
+ aValue <<= true;
+ xFPControl->setValue(ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0, aValue);
+
+ OUString aDialogStr(IDEResId(RID_STR_STDDIALOGNAME));
+ xFP->appendFilter( aDialogStr, "*.xdl" );
+ xFP->appendFilter( IDEResId(RID_STR_FILTER_ALLFILES), FilterMask_All );
+ xFP->setCurrentFilter( aDialogStr );
+
+ if( aDlg.Execute() == ERRCODE_NONE )
+ {
+ Sequence< OUString > aPaths = xFP->getSelectedFiles();
+
+ OUString aBasePath;
+ OUString aOUCurPath( aPaths[0] );
+ sal_Int32 iSlash = aOUCurPath.lastIndexOf( '/' );
+ if( iSlash != -1 )
+ aBasePath = aOUCurPath.copy( 0, iSlash + 1 );
+
+ try
+ {
+ // create dialog model
+ Reference< container::XNameContainer > xDialogModel(
+ xContext->getServiceManager()->createInstanceWithContext("com.sun.star.awt.UnoControlDialogModel", xContext),
+ UNO_QUERY_THROW );
+
+ Reference< XSimpleFileAccess3 > xSFI( SimpleFileAccess::create(xContext) );
+
+ Reference< XInputStream > xInput;
+ if( xSFI->exists( aOUCurPath ) )
+ xInput = xSFI->openFileRead( aOUCurPath );
+
+ ::xmlscript::importDialogModel( xInput, xDialogModel, xContext, rDocument.isDocument() ? rDocument.getDocument() : Reference< frame::XModel >() );
+
+ OUString aXmlDlgName;
+ Reference< beans::XPropertySet > xDialogModelPropSet( xDialogModel, UNO_QUERY );
+ assert(xDialogModelPropSet.is());
+ try
+ {
+ Any aXmlDialogNameAny = xDialogModelPropSet->getPropertyValue( DLGED_PROP_NAME );
+ aXmlDialogNameAny >>= aXmlDlgName;
+ }
+ catch(const beans::UnknownPropertyException& )
+ {
+ TOOLS_WARN_EXCEPTION("basctl", "");
+ }
+ assert( !aXmlDlgName.isEmpty() );
+
+ bool bDialogAlreadyExists = rDocument.hasDialog( aLibName, aXmlDlgName );
+
+ OUString aNewDlgName = aXmlDlgName;
+ enum NameClashMode
+ {
+ NO_CLASH,
+ CLASH_OVERWRITE_DIALOG,
+ CLASH_RENAME_DIALOG,
+ };
+ NameClashMode eNameClashMode = NO_CLASH;
+ if( bDialogAlreadyExists )
+ {
+ OUString aQueryBoxTitle(IDEResId(RID_STR_DLGIMP_CLASH_TITLE));
+ OUString aQueryBoxText(IDEResId(RID_STR_DLGIMP_CLASH_TEXT));
+ aQueryBoxText = aQueryBoxText.replaceAll("$(ARG1)", aXmlDlgName);
+
+ NameClashQueryBox aQueryBox(pWin, aQueryBoxTitle, aQueryBoxText);
+ sal_uInt16 nRet = aQueryBox.run();
+ if( nRet == RET_YES )
+ {
+ // RET_YES == Rename, see NameClashQueryBox::NameClashQueryBox
+ eNameClashMode = CLASH_RENAME_DIALOG;
+
+ aNewDlgName = rDocument.createObjectName( E_DIALOGS, aLibName );
+ }
+ else if( nRet == RET_NO )
+ {
+ // RET_NO == Replace, see NameClashQueryBox::NameClashQueryBox
+ eNameClashMode = CLASH_OVERWRITE_DIALOG;
+ }
+ else if( nRet == RET_CANCEL )
+ {
+ return bDone;
+ }
+ }
+
+ Shell* pShell = GetShell();
+ assert(pShell);
+
+ // Resource?
+ css::lang::Locale aLocale = Application::GetSettings().GetUILanguageTag().getLocale();
+ Reference< task::XInteractionHandler > xDummyHandler;
+ Reference< XStringResourceWithLocation > xImportStringResource =
+ StringResourceWithLocation::create( xContext, aBasePath, true/*bReadOnly*/,
+ aLocale, aXmlDlgName, OUString(), xDummyHandler );
+
+ Sequence< lang::Locale > aImportLocaleSeq = xImportStringResource->getLocales();
+ sal_Int32 nImportLocaleCount = aImportLocaleSeq.getLength();
+
+ Reference< container::XNameContainer > xDialogLib( rDocument.getLibrary( E_DIALOGS, aLibName, true ) );
+ Reference< resource::XStringResourceManager > xLibStringResourceManager = LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib );
+ sal_Int32 nLibLocaleCount = 0;
+ Sequence< lang::Locale > aLibLocaleSeq;
+ if( xLibStringResourceManager.is() )
+ {
+ aLibLocaleSeq = xLibStringResourceManager->getLocales();
+ nLibLocaleCount = aLibLocaleSeq.getLength();
+ }
+
+ // Check language matches
+ std::vector< lang::Locale > aOnlyInImportLanguages =
+ implGetLanguagesOnlyContainedInFirstSeq( aImportLocaleSeq, aLibLocaleSeq );
+ int nOnlyInImportLanguageCount = aOnlyInImportLanguages.size();
+
+ // For now: Keep languages from lib
+ bool bLibLocalized = (nLibLocaleCount > 0);
+ bool bImportLocalized = (nImportLocaleCount > 0);
+
+ bool bAddDialogLanguagesToLib = false;
+ if( nOnlyInImportLanguageCount > 0 )
+ {
+ OUString aQueryBoxTitle(IDEResId(RID_STR_DLGIMP_MISMATCH_TITLE));
+ OUString aQueryBoxText(IDEResId(RID_STR_DLGIMP_MISMATCH_TEXT));
+ LanguageMismatchQueryBox aQueryBox(pWin, aQueryBoxTitle, aQueryBoxText);
+ sal_uInt16 nRet = aQueryBox.run();
+ if( nRet == RET_YES )
+ {
+ // RET_YES == Add, see LanguageMismatchQueryBox::LanguageMismatchQueryBox
+ bAddDialogLanguagesToLib = true;
+ }
+ // RET_NO == Omit, see LanguageMismatchQueryBox::LanguageMismatchQueryBox
+ // -> nothing to do here
+ //else if( RET_NO == nRet )
+ //{
+ //}
+ else if( nRet == RET_CANCEL )
+ {
+ return bDone;
+ }
+ }
+
+ if( bImportLocalized )
+ {
+ bool bCopyResourcesForDialog = true;
+ if( bAddDialogLanguagesToLib )
+ {
+ const std::shared_ptr<LocalizationMgr>& pCurMgr = pShell->GetCurLocalizationMgr();
+
+ lang::Locale aFirstLocale = aOnlyInImportLanguages[0];
+ if( nOnlyInImportLanguageCount > 1 )
+ {
+ // Check if import default belongs to only import languages and use it then
+ lang::Locale aImportDefaultLocale = xImportStringResource->getDefaultLocale();
+ lang::Locale aTmpLocale;
+ for( int i = 0 ; i < nOnlyInImportLanguageCount ; ++i )
+ {
+ aTmpLocale = aOnlyInImportLanguages[i];
+ if( localesAreEqual( aImportDefaultLocale, aTmpLocale ) )
+ {
+ aFirstLocale = aImportDefaultLocale;
+ break;
+ }
+ }
+ }
+
+ pCurMgr->handleAddLocales( {aFirstLocale} );
+
+ if( nOnlyInImportLanguageCount > 1 )
+ {
+ Sequence< lang::Locale > aRemainingLocaleSeq( nOnlyInImportLanguageCount - 1 );
+ auto pRemainingLocaleSeq = aRemainingLocaleSeq.getArray();
+ lang::Locale aTmpLocale;
+ int iSeq = 0;
+ for( int i = 0 ; i < nOnlyInImportLanguageCount ; ++i )
+ {
+ aTmpLocale = aOnlyInImportLanguages[i];
+ if( !localesAreEqual( aFirstLocale, aTmpLocale ) )
+ pRemainingLocaleSeq[iSeq++] = aTmpLocale;
+ }
+ pCurMgr->handleAddLocales( aRemainingLocaleSeq );
+ }
+ }
+ else if( !bLibLocalized )
+ {
+ LocalizationMgr::resetResourceForDialog( xDialogModel, xImportStringResource );
+ bCopyResourcesForDialog = false;
+ }
+
+ if( bCopyResourcesForDialog )
+ {
+ LocalizationMgr::copyResourceForDroppedDialog( xDialogModel, aXmlDlgName,
+ xLibStringResourceManager, xImportStringResource );
+ }
+ }
+ else if( bLibLocalized )
+ {
+ LocalizationMgr::setResourceIDsForDialog( xDialogModel, xLibStringResourceManager );
+ }
+
+
+ LocalizationMgr::setStringResourceAtDialog( rDocument, aLibName, aNewDlgName, xDialogModel );
+
+ if( eNameClashMode == CLASH_OVERWRITE_DIALOG )
+ {
+ if (basctl::RemoveDialog( rDocument, aLibName, aNewDlgName ) )
+ {
+ BaseWindow* pDlgWin = pShell->FindDlgWin( rDocument, aLibName, aNewDlgName, false, true );
+ if( pDlgWin != nullptr )
+ pShell->RemoveWindow( pDlgWin, false );
+ MarkDocumentModified( rDocument );
+ }
+ else
+ {
+ // TODO: Assertion?
+ return bDone;
+ }
+ }
+
+ if( eNameClashMode == CLASH_RENAME_DIALOG )
+ {
+ bool bRenamed = false;
+ if( xDialogModelPropSet.is() )
+ {
+ try
+ {
+ xDialogModelPropSet->setPropertyValue( DLGED_PROP_NAME, Any(aNewDlgName) );
+ bRenamed = true;
+ }
+ catch(const beans::UnknownPropertyException& )
+ {}
+ }
+
+
+ if( bRenamed )
+ {
+ LocalizationMgr::renameStringResourceIDs( rDocument, aLibName, aNewDlgName, xDialogModel );
+ }
+ else
+ {
+ // TODO: Assertion?
+ return bDone;
+ }
+ }
+
+ Reference< XInputStreamProvider > xISP = ::xmlscript::exportDialogModel( xDialogModel, xContext, rDocument.isDocument() ? rDocument.getDocument() : Reference< frame::XModel >() );
+ bool bSuccess = rDocument.insertDialog( aLibName, aNewDlgName, xISP );
+ if( bSuccess )
+ {
+ VclPtr<DialogWindow> pNewDlgWin = pShell->CreateDlgWin( rDocument, aLibName, aNewDlgName );
+ pShell->SetCurWindow( pNewDlgWin, true );
+ }
+
+ bDone = true;
+ }
+ catch(const Exception& )
+ {}
+ }
+
+ return bDone;
+}
+
+void DialogWindow::ImportDialog()
+{
+ const ScriptDocument& rDocument = GetDocument();
+ OUString aLibName = GetLibName();
+ implImportDialog(GetFrameWeld(), rDocument, aLibName);
+}
+
+DlgEdModel& DialogWindow::GetModel() const
+{
+ return m_pEditor->GetModel();
+}
+
+DlgEdPage& DialogWindow::GetPage() const
+{
+ return m_pEditor->GetPage();
+}
+
+DlgEdView& DialogWindow::GetView() const
+{
+ return m_pEditor->GetView();
+}
+
+bool DialogWindow::IsModified()
+{
+ return m_pEditor->IsModified();
+}
+
+SfxUndoManager* DialogWindow::GetUndoManager()
+{
+ return m_pUndoMgr.get();
+}
+
+OUString DialogWindow::GetTitle()
+{
+ return GetName();
+}
+
+EntryDescriptor DialogWindow::CreateEntryDescriptor()
+{
+ ScriptDocument aDocument( GetDocument() );
+ OUString aLibName( GetLibName() );
+ LibraryLocation eLocation = aDocument.getLibraryLocation( aLibName );
+ return EntryDescriptor( aDocument, eLocation, aLibName, OUString(), GetName(), OBJ_TYPE_DIALOG );
+}
+
+void DialogWindow::SetReadOnly (bool bReadOnly)
+{
+ m_pEditor->SetMode(bReadOnly ? DlgEditor::READONLY : DlgEditor::SELECT);
+}
+
+bool DialogWindow::IsReadOnly ()
+{
+ return m_pEditor->GetMode() == DlgEditor::READONLY;
+}
+
+bool DialogWindow::IsPasteAllowed()
+{
+ return m_pEditor->IsPasteAllowed();
+}
+
+void DialogWindow::StoreData()
+{
+ if ( !IsModified() )
+ return;
+
+ try
+ {
+ Reference< container::XNameContainer > xLib = GetDocument().getLibrary( E_DIALOGS, GetLibName(), true );
+
+ if( xLib.is() )
+ {
+ Reference< container::XNameContainer > xDialogModel = m_pEditor->GetDialog();
+
+ if( xDialogModel.is() )
+ {
+ Reference< XComponentContext > xContext(
+ comphelper::getProcessComponentContext() );
+ Reference< XInputStreamProvider > xISP = ::xmlscript::exportDialogModel( xDialogModel, xContext, GetDocument().isDocument() ? GetDocument().getDocument() : Reference< frame::XModel >() );
+ xLib->replaceByName( GetName(), Any( xISP ) );
+ }
+ }
+ }
+ catch (const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ MarkDocumentModified( GetDocument() );
+ m_pEditor->ClearModifyFlag();
+}
+
+void DialogWindow::Activating ()
+{
+ UpdateBrowser();
+ Show();
+}
+
+void DialogWindow::Deactivating()
+{
+ Hide();
+ if ( IsModified() )
+ MarkDocumentModified( GetDocument() );
+ DisableBrowser();
+}
+
+sal_Int32 DialogWindow::countPages( Printer* )
+{
+ return 1;
+}
+
+void DialogWindow::printPage( sal_Int32 nPage, Printer* pPrinter )
+{
+ DlgEditor::printPage( nPage, pPrinter, CreateQualifiedName() );
+}
+
+void DialogWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if( (rDCEvt.GetType()==DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ InitSettings();
+ Invalidate();
+ }
+ else
+ BaseWindow::DataChanged( rDCEvt );
+}
+
+void DialogWindow::InitSettings()
+{
+ // FIXME RenderContext
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ SetPointFont(*GetOutDev(), aFont);
+
+ SetTextColor( rStyleSettings.GetFieldTextColor() );
+ SetTextFillColor();
+
+ SetBackground( rStyleSettings.GetFieldColor() );
+}
+
+css::uno::Reference< css::accessibility::XAccessible > DialogWindow::CreateAccessible()
+{
+ return new AccessibleDialogWindow(this);
+}
+
+OString DialogWindow::GetHid () const
+{
+ return HID_BASICIDE_DIALOGWINDOW;
+}
+ItemType DialogWindow::GetType () const
+{
+ return TYPE_DIALOG;
+}
+
+
+// DialogWindowLayout
+
+
+DialogWindowLayout::DialogWindowLayout (vcl::Window* pParent, ObjectCatalog& rObjectCatalog_) :
+ Layout(pParent),
+ rObjectCatalog(rObjectCatalog_),
+ pPropertyBrowser(nullptr)
+{
+ ShowPropertyBrowser();
+}
+
+DialogWindowLayout::~DialogWindowLayout()
+{
+ disposeOnce();
+}
+
+void DialogWindowLayout::dispose()
+{
+ if (pPropertyBrowser)
+ Remove(pPropertyBrowser);
+ pPropertyBrowser.disposeAndClear();
+ Layout::dispose();
+}
+
+// shows the property browser (and creates if necessary)
+void DialogWindowLayout::ShowPropertyBrowser ()
+{
+ // not exists?
+ if (!pPropertyBrowser)
+ {
+ // creating
+ pPropertyBrowser = VclPtr<PropBrw>::Create(*this);
+ pPropertyBrowser->Show();
+ // after OnFirstSize():
+ if (HasSize())
+ AddPropertyBrowser();
+ // updating if necessary
+ UpdatePropertyBrowser();
+ }
+ else
+ pPropertyBrowser->Show();
+ // refreshing the button state
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate(SID_SHOW_PROPERTYBROWSER);
+}
+
+// disables the property browser
+void DialogWindowLayout::DisablePropertyBrowser ()
+{
+ if (pPropertyBrowser)
+ pPropertyBrowser->Update(nullptr);
+}
+
+// updates the property browser
+void DialogWindowLayout::UpdatePropertyBrowser ()
+{
+ if (pPropertyBrowser)
+ pPropertyBrowser->Update(GetShell());
+}
+
+void DialogWindowLayout::Activating (BaseWindow& rChild)
+{
+ assert(dynamic_cast<DialogWindow*>(&rChild));
+ rObjectCatalog.SetLayoutWindow(this);
+ rObjectCatalog.UpdateEntries();
+ rObjectCatalog.Show();
+ if (pPropertyBrowser)
+ pPropertyBrowser->Show();
+ Layout::Activating(rChild);
+}
+
+void DialogWindowLayout::Deactivating ()
+{
+ Layout::Deactivating();
+ rObjectCatalog.Hide();
+ if (pPropertyBrowser)
+ pPropertyBrowser->Hide();
+}
+
+void DialogWindowLayout::ExecuteGlobal (SfxRequest& rReq)
+{
+ switch (rReq.GetSlot())
+ {
+ case SID_SHOW_PROPERTYBROWSER:
+ // toggling property browser
+ if (pPropertyBrowser && pPropertyBrowser->IsVisible())
+ pPropertyBrowser->Hide();
+ else
+ ShowPropertyBrowser();
+ ArrangeWindows();
+ // refreshing the button state
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate(SID_SHOW_PROPERTYBROWSER);
+ break;
+ }
+}
+
+void DialogWindowLayout::GetState (SfxItemSet& rSet, unsigned nWhich)
+{
+ switch (nWhich)
+ {
+ case SID_SHOW_PROPERTYBROWSER:
+ rSet.Put(SfxBoolItem(nWhich, pPropertyBrowser && pPropertyBrowser->IsVisible()));
+ break;
+
+ case SID_BASICIDE_CHOOSEMACRO:
+ rSet.Put(SfxVisibilityItem(nWhich, false));
+ break;
+ }
+}
+
+void DialogWindowLayout::OnFirstSize (tools::Long const nWidth, tools::Long const nHeight)
+{
+ AddToLeft(&rObjectCatalog, Size(nWidth * 0.25, nHeight * 0.35));
+ if (pPropertyBrowser)
+ AddPropertyBrowser();
+}
+
+void DialogWindowLayout::AddPropertyBrowser () {
+ Size const aSize = GetOutputSizePixel();
+ AddToLeft(pPropertyBrowser, Size(aSize.Width() * 0.25, aSize.Height() * 0.65));
+}
+
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/basidectrlr.cxx b/basctl/source/basicide/basidectrlr.cxx
new file mode 100644
index 000000000..849bff30c
--- /dev/null
+++ b/basctl/source/basicide/basidectrlr.cxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <basidectrlr.hxx>
+#include <basidesh.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+namespace basctl
+{
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+
+namespace
+{
+
+int const nPropertyIconId = 1;
+constexpr OUStringLiteral sPropertyIconId(u"IconId");
+
+}
+
+Controller::Controller (Shell* pViewShell)
+ :OPropertyContainer( m_aBHelper )
+ ,SfxBaseController( pViewShell )
+ ,m_nIconId( ICON_MACROLIBRARY )
+{
+ registerProperty(
+ sPropertyIconId, nPropertyIconId,
+ PropertyAttribute::READONLY,
+ &m_nIconId, cppu::UnoType<decltype(m_nIconId)>::get()
+ );
+}
+
+Controller::~Controller()
+{ }
+
+// XInterface
+Any SAL_CALL Controller::queryInterface( const Type & rType )
+{
+ Any aReturn = SfxBaseController::queryInterface( rType );
+ if ( !aReturn.hasValue() )
+ aReturn = OPropertyContainer::queryInterface( rType );
+
+ return aReturn;
+}
+
+void SAL_CALL Controller::acquire() noexcept
+{
+ SfxBaseController::acquire();
+}
+
+void SAL_CALL Controller::release() noexcept
+{
+ SfxBaseController::release();
+}
+
+// XTypeProvider ( ::SfxBaseController )
+Sequence< Type > SAL_CALL Controller::getTypes()
+{
+ Sequence< Type > aTypes = ::comphelper::concatSequences(
+ SfxBaseController::getTypes(),
+ getBaseTypes()
+ );
+
+ return aTypes;
+}
+
+Sequence< sal_Int8 > SAL_CALL Controller::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XPropertySet
+Reference< beans::XPropertySetInfo > SAL_CALL Controller::getPropertySetInfo()
+{
+ Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+// OPropertySetHelper
+::cppu::IPropertyArrayHelper& Controller::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+// OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* Controller::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/basides1.cxx b/basctl/source/basicide/basides1.cxx
new file mode 100644
index 000000000..709915253
--- /dev/null
+++ b/basctl/source/basicide/basides1.cxx
@@ -0,0 +1,1407 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <iderid.hxx>
+#include <strings.hrc>
+#include <helpids.h>
+
+#include "baside2.hxx"
+#include <baside3.hxx>
+#include <basidesh.hxx>
+#include <basobj.hxx>
+#include <docsignature.hxx>
+#include <iderdll.hxx>
+#include "iderdll2.hxx"
+#include <localizationmgr.hxx>
+#include <managelang.hxx>
+
+#include <basic/basmgr.hxx>
+#include <com/sun/star/script/ModuleType.hpp>
+#include <com/sun/star/script/XLibraryContainerPassword.hpp>
+#include <com/sun/star/script/XLibraryContainer2.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <svl/srchdefs.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <sfx2/app.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/dinfdlg.hxx>
+#include <sfx2/minfitem.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svxids.hrc>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/visitem.hxx>
+#include <svl/whiter.hxx>
+#include <vcl/texteng.hxx>
+#include <vcl/textview.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+constexpr sal_Int32 TAB_HEIGHT_MARGIN = 10;
+
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+
+void Shell::ExecuteSearch( SfxRequest& rReq )
+{
+ if ( !pCurWin )
+ return;
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+ // if searching has not been done before this time
+ if (nSlot == SID_BASICIDE_REPEAT_SEARCH && !mpSearchItem)
+ {
+ rReq.SetReturnValue(SfxBoolItem(nSlot, false));
+ nSlot = 0;
+ }
+
+ switch ( nSlot )
+ {
+ case SID_SEARCH_OPTIONS:
+ break;
+ case SID_SEARCH_ITEM:
+ mpSearchItem.reset(pArgs->Get(SID_SEARCH_ITEM).Clone());
+ break;
+ case FID_SEARCH_ON:
+ mbJustOpened = true;
+ GetViewFrame()->GetBindings().Invalidate(SID_SEARCH_ITEM);
+ break;
+ case SID_BASICIDE_REPEAT_SEARCH:
+ case FID_SEARCH_NOW:
+ {
+ if (!pCurWin->HasActiveEditor())
+ break;
+
+ // If it is a repeat searching
+ if ( nSlot == SID_BASICIDE_REPEAT_SEARCH )
+ {
+ if( !mpSearchItem )
+ mpSearchItem.reset( new SvxSearchItem( SID_SEARCH_ITEM ));
+ }
+ else
+ {
+ // Get SearchItem from request if it is the first searching
+ if ( pArgs )
+ {
+ mpSearchItem.reset(pArgs->Get(SID_SEARCH_ITEM).Clone());
+ }
+ }
+
+ sal_Int32 nFound = 0;
+
+ if ( mpSearchItem->GetCommand() == SvxSearchCmd::REPLACE_ALL )
+ {
+ sal_uInt16 nActModWindows = 0;
+ for (auto const& window : aWindowTable)
+ {
+ BaseWindow* pWin = window.second;
+ if (pWin->HasActiveEditor())
+ nActModWindows++;
+ }
+
+ bool bAllModules = nActModWindows <= 1;
+ if (!bAllModules)
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pCurWin ? pCurWin->GetFrameWeld() : nullptr,
+ VclMessageType::Question, VclButtonsType::YesNo,
+ IDEResId(RID_STR_SEARCHALLMODULES)));
+ xQueryBox->set_default_response(RET_YES);
+ bAllModules = xQueryBox->run() == RET_YES;
+ }
+
+ if (bAllModules)
+ {
+ for (auto const& window : aWindowTable)
+ {
+ BaseWindow* pWin = window.second;
+ nFound += pWin->StartSearchAndReplace( *mpSearchItem );
+ }
+ }
+ else
+ nFound = pCurWin->StartSearchAndReplace( *mpSearchItem );
+
+ OUString aReplStr(IDEResId(RID_STR_SEARCHREPLACES));
+ aReplStr = aReplStr.replaceAll("XX", OUString::number(nFound));
+
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pCurWin->GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ aReplStr));
+ xInfoBox->run();
+ }
+ else
+ {
+ bool bCanceled = false;
+ nFound = pCurWin->StartSearchAndReplace( *mpSearchItem );
+ if ( !nFound && !mpSearchItem->GetSelection() )
+ {
+ // search other modules...
+ bool bChangeCurWindow = false;
+ auto it = std::find_if(aWindowTable.cbegin(), aWindowTable.cend(),
+ [this](const WindowTable::value_type& item) { return item.second == pCurWin; });
+ if (it != aWindowTable.cend())
+ ++it;
+ BaseWindow* pWin = it != aWindowTable.cend() ? it->second.get() : nullptr;
+
+ bool bSearchedFromStart = false;
+ while ( !nFound && !bCanceled && ( pWin || !bSearchedFromStart ) )
+ {
+ if ( !pWin )
+ {
+ SfxViewFrame* pViewFrame = GetViewFrame();
+ SfxChildWindow* pChildWin = pViewFrame ? pViewFrame->GetChildWindow( SID_SEARCH_DLG ) : nullptr;
+ auto xParent = pChildWin ? pChildWin->GetController() : nullptr;
+
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(xParent ? xParent->getDialog() : nullptr,
+ VclMessageType::Question, VclButtonsType::YesNo,
+ IDEResId(RID_STR_SEARCHFROMSTART)));
+ xQueryBox->set_default_response(RET_YES);
+ if (xQueryBox->run() == RET_YES)
+ {
+ it = aWindowTable.cbegin();
+ if ( it != aWindowTable.cend() )
+ pWin = it->second;
+ bSearchedFromStart = true;
+ }
+ else
+ bCanceled = true;
+ }
+
+ if (pWin && pWin->HasActiveEditor())
+ {
+ if ( pWin != pCurWin )
+ {
+ if ( pCurWin )
+ pWin->SetSizePixel( pCurWin->GetSizePixel() );
+ nFound = pWin->StartSearchAndReplace( *mpSearchItem, true );
+ }
+ if ( nFound )
+ {
+ bChangeCurWindow = true;
+ break;
+ }
+ }
+ if ( pWin && ( pWin != pCurWin ) )
+ {
+ if ( it != aWindowTable.cend() )
+ ++it;
+ pWin = it != aWindowTable.cend() ? it->second.get() : nullptr;
+ }
+ else
+ pWin = nullptr;
+ }
+ if ( !nFound && bSearchedFromStart )
+ nFound = pCurWin->StartSearchAndReplace( *mpSearchItem, true );
+ if ( bChangeCurWindow )
+ SetCurWindow( pWin, true );
+ }
+ if ( !nFound && !bCanceled )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pCurWin->GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ IDEResId(RID_STR_SEARCHNOTFOUND)));
+ xInfoBox->run();
+ }
+ }
+
+ rReq.Done();
+ break;
+ }
+ default:
+ pCurWin->ExecuteCommand( rReq );
+ }
+}
+
+void Shell::ExecuteCurrent( SfxRequest& rReq )
+{
+ if ( !pCurWin )
+ return;
+
+ switch ( rReq.GetSlot() )
+ {
+ case SID_BASICIDE_HIDECURPAGE:
+ {
+ pCurWin->StoreData();
+ RemoveWindow( pCurWin, false );
+ }
+ break;
+ case SID_BASICIDE_RENAMECURRENT:
+ {
+ pTabBar->StartEditMode( pTabBar->GetCurPageId() );
+ }
+ break;
+ case SID_UNDO:
+ case SID_REDO:
+ if ( GetUndoManager() && pCurWin->AllowUndo() )
+ GetViewFrame()->ExecuteSlot( rReq );
+ break;
+ default:
+ pCurWin->ExecuteCommand( rReq );
+ }
+}
+
+// no matter who's at the top, influence on the shell:
+void Shell::ExecuteGlobal( SfxRequest& rReq )
+{
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch ( nSlot )
+ {
+ case SID_NEWDOCDIRECT:
+ {
+ // we do not have a new document factory,
+ // so just forward to a fallback method.
+ SfxGetpApp()->ExecuteSlot(rReq);
+ }
+ break;
+
+ case SID_BASICSTOP:
+ {
+ // maybe do not simply stop if on breakpoint!
+ if (ModulWindow* pMCurWin = dynamic_cast<ModulWindow*>(pCurWin.get()))
+ pMCurWin->BasicStop();
+ StopBasic();
+ }
+ break;
+
+ case SID_SAVEDOC:
+ {
+ if ( pCurWin )
+ {
+ // rewrite date into the BASIC
+ StoreAllWindowData();
+
+ // document basic
+ ScriptDocument aDocument( pCurWin->GetDocument() );
+ if ( aDocument.isDocument() )
+ {
+ uno::Reference< task::XStatusIndicator > xStatusIndicator;
+
+ const SfxUnoAnyItem* pStatusIndicatorItem = rReq.GetArg<SfxUnoAnyItem>(SID_PROGRESS_STATUSBAR_CONTROL);
+ if ( pStatusIndicatorItem )
+ OSL_VERIFY( pStatusIndicatorItem->GetValue() >>= xStatusIndicator );
+ else
+ {
+ // get statusindicator
+ SfxViewFrame *pFrame_ = GetFrame();
+ if ( pFrame_ )
+ {
+ uno::Reference< task::XStatusIndicatorFactory > xStatFactory(
+ pFrame_->GetFrame().GetFrameInterface(),
+ uno::UNO_QUERY );
+ if( xStatFactory.is() )
+ xStatusIndicator = xStatFactory->createStatusIndicator();
+ }
+
+ if ( xStatusIndicator.is() )
+ rReq.AppendItem( SfxUnoAnyItem( SID_PROGRESS_STATUSBAR_CONTROL, uno::Any( xStatusIndicator ) ) );
+ }
+
+ aDocument.saveDocument( xStatusIndicator );
+ }
+
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+ pBindings->Invalidate( SID_SAVEDOC );
+ pBindings->Invalidate( SID_SIGNATURE );
+ }
+ }
+ }
+ break;
+ case SID_BASICIDE_MODULEDLG:
+ {
+ if ( rReq.GetArgs() )
+ {
+ const SfxUInt16Item &rTabId = rReq.GetArgs()->Get(SID_BASICIDE_ARG_TABID );
+ Organize(rReq.GetFrameWeld(), rTabId.GetValue());
+ }
+ else
+ Organize(rReq.GetFrameWeld(), 0);
+ }
+ break;
+ case SID_BASICIDE_CHOOSEMACRO:
+ {
+ ChooseMacro(rReq.GetFrameWeld(), nullptr);
+ }
+ break;
+ case SID_BASICIDE_CREATEMACRO:
+ case SID_BASICIDE_EDITMACRO:
+ {
+ DBG_ASSERT( rReq.GetArgs(), "arguments expected" );
+ const SfxMacroInfoItem& rInfo = rReq.GetArgs()->Get(SID_BASICIDE_ARG_MACROINFO );
+ BasicManager* pBasMgr = const_cast<BasicManager*>(rInfo.GetBasicManager());
+ DBG_ASSERT( pBasMgr, "Nothing selected in basic tree?" );
+
+ ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
+
+ StartListening(*pBasMgr, DuplicateHandling::Prevent /* log on only once */);
+ OUString aLibName( rInfo.GetLib() );
+ if ( aLibName.isEmpty() )
+ aLibName = "Standard" ;
+ StarBASIC* pBasic = pBasMgr->GetLib( aLibName );
+ if ( !pBasic )
+ {
+ // load module and dialog library (if not loaded)
+ aDocument.loadLibraryIfExists( E_SCRIPTS, aLibName );
+ aDocument.loadLibraryIfExists( E_DIALOGS, aLibName );
+
+ // get Basic
+ pBasic = pBasMgr->GetLib( aLibName );
+ }
+ DBG_ASSERT( pBasic, "No Basic!" );
+
+ SetCurLib( aDocument, aLibName );
+
+ if ( pBasic && rReq.GetSlot() == SID_BASICIDE_CREATEMACRO )
+ {
+ SbModule* pModule = pBasic->FindModule( rInfo.GetModule() );
+ if ( !pModule )
+ {
+ if ( !rInfo.GetModule().isEmpty() || pBasic->GetModules().empty() )
+ {
+ const OUString& aModName = rInfo.GetModule();
+
+ OUString sModuleCode;
+ if ( aDocument.createModule( aLibName, aModName, false, sModuleCode ) )
+ pModule = pBasic->FindModule( aModName );
+ }
+ else
+ pModule = pBasic->GetModules().front().get();
+ }
+ DBG_ASSERT( pModule, "No Module!" );
+ if ( pModule && !pModule->GetMethods()->Find( rInfo.GetMethod(), SbxClassType::Method ) )
+ CreateMacro( pModule, rInfo.GetMethod() );
+ }
+ SfxViewFrame* pViewFrame = GetViewFrame();
+ if ( pViewFrame )
+ pViewFrame->ToTop();
+ VclPtr<ModulWindow> pWin = FindBasWin( aDocument, aLibName, rInfo.GetModule(), true );
+ DBG_ASSERT( pWin, "Edit/Create Macro: Window was not created/found!" );
+ SetCurWindow( pWin, true );
+ pWin->EditMacro( rInfo.GetMethod() );
+ }
+ break;
+
+ case SID_BASICIDE_OBJCAT:
+ // toggling object catalog
+ aObjectCatalog->Show(!aObjectCatalog->IsVisible());
+ if (pLayout)
+ pLayout->ArrangeWindows();
+ // refresh the button state
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate(SID_BASICIDE_OBJCAT);
+ break;
+
+ case SID_BASICIDE_NAMECHANGEDONTAB:
+ {
+ DBG_ASSERT( rReq.GetArgs(), "arguments expected" );
+ const SfxUInt16Item &rTabId = rReq.GetArgs()->Get(SID_BASICIDE_ARG_TABID );
+ const SfxStringItem &rModName = rReq.GetArgs()->Get(SID_BASICIDE_ARG_MODULENAME );
+ if ( aWindowTable.find( rTabId.GetValue() ) != aWindowTable.end() )
+ {
+ VclPtr<BaseWindow> pWin = aWindowTable[ rTabId.GetValue() ];
+ const OUString& aNewName( rModName.GetValue() );
+ OUString aOldName( pWin->GetName() );
+ if ( aNewName != aOldName )
+ {
+ bool bRenameOk = false;
+ if (ModulWindow* pModWin = dynamic_cast<ModulWindow*>(pWin.get()))
+ {
+ const OUString& aLibName = pModWin->GetLibName();
+ ScriptDocument aDocument( pWin->GetDocument() );
+
+ if (RenameModule(pModWin->GetFrameWeld(), aDocument, aLibName, aOldName, aNewName))
+ {
+ bRenameOk = true;
+ // Because we listen for container events for script
+ // modules, rename will delete the 'old' window
+ // pWin has been invalidated, restore now
+ pWin = FindBasWin( aDocument, aLibName, aNewName, true );
+ }
+
+ }
+ else if (DialogWindow* pDlgWin = dynamic_cast<DialogWindow*>(pWin.get()))
+ {
+ bRenameOk = pDlgWin->RenameDialog( aNewName );
+ }
+ if ( bRenameOk )
+ {
+ MarkDocumentModified( pWin->GetDocument() );
+ }
+ else
+ {
+ // set old name in TabWriter
+ sal_uInt16 nId = GetWindowId( pWin );
+ DBG_ASSERT( nId, "No entry in Tabbar!" );
+ if ( nId )
+ pTabBar->SetPageText( nId, aOldName );
+ }
+ }
+
+ // set focus to current window
+ pWin->GrabFocus();
+ }
+ }
+ break;
+ case SID_BASICIDE_STOREMODULESOURCE:
+ case SID_BASICIDE_UPDATEMODULESOURCE:
+ {
+ DBG_ASSERT( rReq.GetArgs(), "arguments expected" );
+ const SfxMacroInfoItem& rInfo = rReq.GetArgs()->Get(SID_BASICIDE_ARG_MACROINFO );
+ BasicManager* pBasMgr = const_cast<BasicManager*>(rInfo.GetBasicManager());
+ DBG_ASSERT( pBasMgr, "Store source: No BasMgr?" );
+ ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
+ VclPtr<ModulWindow> pWin = FindBasWin( aDocument, rInfo.GetLib(), rInfo.GetModule(), false, true );
+ if ( pWin )
+ {
+ if ( rReq.GetSlot() == SID_BASICIDE_STOREMODULESOURCE )
+ pWin->StoreData();
+ else
+ pWin->UpdateData();
+ }
+ }
+ break;
+ case SID_BASICIDE_STOREALLMODULESOURCES:
+ case SID_BASICIDE_UPDATEALLMODULESOURCES:
+ {
+ for (auto const& window : aWindowTable)
+ {
+ BaseWindow* pWin = window.second;
+ if (!pWin->IsSuspended() && dynamic_cast<ModulWindow*>(pWin))
+ {
+ if ( rReq.GetSlot() == SID_BASICIDE_STOREALLMODULESOURCES )
+ pWin->StoreData();
+ else
+ pWin->UpdateData();
+ }
+ }
+ }
+ break;
+ case SID_BASICIDE_LIBSELECTED:
+ case SID_BASICIDE_LIBREMOVED:
+ case SID_BASICIDE_LIBLOADED:
+ {
+ DBG_ASSERT( rReq.GetArgs(), "arguments expected" );
+ const SfxUnoAnyItem& rShellItem = rReq.GetArgs()->Get( SID_BASICIDE_ARG_DOCUMENT_MODEL );
+ uno::Reference< frame::XModel > xModel( rShellItem.GetValue(), UNO_QUERY );
+ ScriptDocument aDocument( xModel.is() ? ScriptDocument( xModel ) : ScriptDocument::getApplicationScriptDocument() );
+ const SfxStringItem& rLibNameItem = rReq.GetArgs()->Get( SID_BASICIDE_ARG_LIBNAME );
+ const OUString& aLibName( rLibNameItem.GetValue() );
+
+ if ( nSlot == SID_BASICIDE_LIBSELECTED )
+ {
+ // load module and dialog library (if not loaded)
+ aDocument.loadLibraryIfExists( E_SCRIPTS, aLibName );
+ aDocument.loadLibraryIfExists( E_DIALOGS, aLibName );
+
+ // check password, if library is password protected and not verified
+ bool bOK = true;
+ Reference< script::XLibraryContainer > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) );
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) )
+ {
+ Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
+ if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) && !xPasswd->isLibraryPasswordVerified( aLibName ) )
+ {
+ OUString aPassword;
+ bOK = QueryPassword(rReq.GetFrameWeld(), xModLibContainer, aLibName, aPassword);
+ }
+ }
+
+ if ( bOK )
+ {
+ SetCurLib( aDocument, aLibName, true, false );
+ }
+ else
+ {
+ // adjust old value...
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate(SID_BASICIDE_LIBSELECTOR, true);
+ }
+ }
+ else if ( nSlot == SID_BASICIDE_LIBREMOVED )
+ {
+ if ( m_aCurLibName.isEmpty() || ( aDocument == m_aCurDocument && aLibName == m_aCurLibName ) )
+ {
+ RemoveWindows( aDocument, aLibName );
+ if ( aDocument == m_aCurDocument && aLibName == m_aCurLibName )
+ {
+ m_aCurDocument = ScriptDocument::getApplicationScriptDocument();
+ m_aCurLibName.clear();
+ // no UpdateWindows!
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_BASICIDE_LIBSELECTOR );
+ }
+ }
+ }
+ else // Loaded...
+ UpdateWindows();
+ }
+ break;
+ case SID_BASICIDE_NEWMODULE:
+ {
+ VclPtr<ModulWindow> pWin = CreateBasWin( m_aCurDocument, m_aCurLibName, OUString() );
+ DBG_ASSERT( pWin, "New Module: Could not create window!" );
+ SetCurWindow( pWin, true );
+ }
+ break;
+ case SID_BASICIDE_NEWDIALOG:
+ {
+ VclPtr<DialogWindow> pWin = CreateDlgWin( m_aCurDocument, m_aCurLibName, OUString() );
+ DBG_ASSERT( pWin, "New Module: Could not create window!" );
+ SetCurWindow( pWin, true );
+ }
+ break;
+ case SID_BASICIDE_SBXRENAMED:
+ {
+ DBG_ASSERT( rReq.GetArgs(), "arguments expected" );
+ }
+ break;
+ case SID_BASICIDE_SBXINSERTED:
+ {
+ DBG_ASSERT( rReq.GetArgs(), "arguments expected" );
+ const SbxItem& rSbxItem = rReq.GetArgs()->Get(SID_BASICIDE_ARG_SBX );
+ const ScriptDocument& aDocument( rSbxItem.GetDocument() );
+ const OUString& aLibName( rSbxItem.GetLibName() );
+ const OUString& aName( rSbxItem.GetName() );
+ if ( m_aCurLibName.isEmpty() || ( aDocument == m_aCurDocument && aLibName == m_aCurLibName ) )
+ {
+ if ( rSbxItem.GetType() == TYPE_MODULE )
+ FindBasWin( aDocument, aLibName, aName, true );
+ else if ( rSbxItem.GetType() == TYPE_DIALOG )
+ FindDlgWin( aDocument, aLibName, aName, true );
+ }
+ }
+ break;
+ case SID_BASICIDE_SBXDELETED:
+ {
+ DBG_ASSERT( rReq.GetArgs(), "arguments expected" );
+ const SbxItem& rSbxItem = rReq.GetArgs()->Get(SID_BASICIDE_ARG_SBX );
+ const ScriptDocument& aDocument( rSbxItem.GetDocument() );
+ VclPtr<BaseWindow> pWin = FindWindow( aDocument, rSbxItem.GetLibName(), rSbxItem.GetName(), rSbxItem.GetType(), true );
+ if ( pWin )
+ RemoveWindow( pWin, true );
+ }
+ break;
+ case SID_BASICIDE_SHOWSBX:
+ {
+ DBG_ASSERT( rReq.GetArgs(), "arguments expected" );
+ const SbxItem& rSbxItem = rReq.GetArgs()->Get(SID_BASICIDE_ARG_SBX );
+ const ScriptDocument& aDocument( rSbxItem.GetDocument() );
+ const OUString& aLibName( rSbxItem.GetLibName() );
+ const OUString& aName( rSbxItem.GetName() );
+ SetCurLib( aDocument, aLibName );
+ BaseWindow* pWin = nullptr;
+ if ( rSbxItem.GetType() == TYPE_DIALOG )
+ {
+ pWin = FindDlgWin( aDocument, aLibName, aName, true );
+ }
+ else if ( rSbxItem.GetType() == TYPE_MODULE )
+ {
+ pWin = FindBasWin( aDocument, aLibName, aName, true );
+ }
+ else if ( rSbxItem.GetType() == TYPE_METHOD )
+ {
+ pWin = FindBasWin( aDocument, aLibName, aName, true );
+ static_cast<ModulWindow*>(pWin)->EditMacro( rSbxItem.GetMethodName() );
+ }
+ DBG_ASSERT( pWin, "Window was not created!" );
+ SetCurWindow( pWin, true );
+ pTabBar->MakeVisible( pTabBar->GetCurPageId() );
+ }
+ break;
+ case SID_BASICIDE_SHOWWINDOW:
+ {
+ std::unique_ptr< ScriptDocument > pDocument;
+
+ const SfxStringItem* pDocumentItem = rReq.GetArg<SfxStringItem>(SID_BASICIDE_ARG_DOCUMENT);
+ if ( pDocumentItem )
+ {
+ const OUString& sDocumentCaption = pDocumentItem->GetValue();
+ if ( !sDocumentCaption.isEmpty() )
+ pDocument.reset( new ScriptDocument( ScriptDocument::getDocumentWithURLOrCaption( sDocumentCaption ) ) );
+ }
+
+ const SfxUnoAnyItem* pDocModelItem = rReq.GetArg<SfxUnoAnyItem>(SID_BASICIDE_ARG_DOCUMENT_MODEL);
+ if (!pDocument && pDocModelItem)
+ {
+ uno::Reference< frame::XModel > xModel( pDocModelItem->GetValue(), UNO_QUERY );
+ if ( xModel.is() )
+ pDocument.reset( new ScriptDocument( xModel ) );
+ }
+
+ if (!pDocument)
+ break;
+
+ const SfxStringItem* pLibNameItem = rReq.GetArg<SfxStringItem>(SID_BASICIDE_ARG_LIBNAME);
+ if ( !pLibNameItem )
+ break;
+
+ OUString aLibName( pLibNameItem->GetValue() );
+ pDocument->loadLibraryIfExists( E_SCRIPTS, aLibName );
+ SetCurLib( *pDocument, aLibName );
+ const SfxStringItem* pNameItem = rReq.GetArg<SfxStringItem>(SID_BASICIDE_ARG_NAME);
+ if ( pNameItem )
+ {
+ const OUString& aName( pNameItem->GetValue() );
+ OUString aModType( "Module" );
+ OUString aType( aModType );
+ const SfxStringItem* pTypeItem = rReq.GetArg<SfxStringItem>(SID_BASICIDE_ARG_TYPE);
+ if ( pTypeItem )
+ aType = pTypeItem->GetValue();
+
+ BaseWindow* pWin = nullptr;
+ if ( aType == aModType )
+ pWin = FindBasWin( *pDocument, aLibName, aName );
+ else if ( aType == "Dialog" )
+ pWin = FindDlgWin( *pDocument, aLibName, aName );
+
+ if ( pWin )
+ {
+ SetCurWindow( pWin, true );
+ if ( pTabBar )
+ pTabBar->MakeVisible( pTabBar->GetCurPageId() );
+
+ if (ModulWindow* pModWin = dynamic_cast<ModulWindow*>(pWin))
+ {
+ const SfxUInt32Item* pLineItem = rReq.GetArg<SfxUInt32Item>(SID_BASICIDE_ARG_LINE);
+ if ( pLineItem )
+ {
+ pModWin->AssertValidEditEngine();
+ TextView* pTextView = pModWin->GetEditView();
+ if ( pTextView )
+ {
+ TextEngine* pTextEngine = pTextView->GetTextEngine();
+ if ( pTextEngine )
+ {
+ sal_uInt32 nLine = pLineItem->GetValue();
+ sal_uInt32 nLineCount = 0;
+ for ( sal_uInt32 i = 0, nCount = pTextEngine->GetParagraphCount(); i < nCount; ++i )
+ nLineCount += pTextEngine->GetLineCount( i );
+ if ( nLine > nLineCount )
+ nLine = nLineCount;
+ if ( nLine > 0 )
+ --nLine;
+
+ // scroll window and set selection
+ tools::Long nVisHeight = pModWin->GetOutputSizePixel().Height();
+ tools::Long nTextHeight = pTextEngine->GetTextHeight();
+ if ( nTextHeight > nVisHeight )
+ {
+ tools::Long nMaxY = nTextHeight - nVisHeight;
+ tools::Long nOldY = pTextView->GetStartDocPos().Y();
+ tools::Long nNewY = nLine * pTextEngine->GetCharHeight() - nVisHeight / 2;
+ nNewY = std::min( nNewY, nMaxY );
+ pTextView->Scroll( 0, -( nNewY - nOldY ) );
+ pTextView->ShowCursor( false );
+ pModWin->GetEditVScrollBar().SetThumbPos( pTextView->GetStartDocPos().Y() );
+ }
+ sal_uInt16 nCol1 = 0, nCol2 = 0;
+ const SfxUInt16Item* pCol1Item = rReq.GetArg<SfxUInt16Item>(SID_BASICIDE_ARG_COLUMN1);
+ if ( pCol1Item )
+ {
+ nCol1 = pCol1Item->GetValue();
+ if ( nCol1 > 0 )
+ --nCol1;
+ nCol2 = nCol1;
+ }
+ const SfxUInt16Item* pCol2Item = rReq.GetArg<SfxUInt16Item>(SID_BASICIDE_ARG_COLUMN2);
+ if ( pCol2Item )
+ {
+ nCol2 = pCol2Item->GetValue();
+ if ( nCol2 > 0 )
+ --nCol2;
+ }
+ TextSelection aSel( TextPaM( nLine, nCol1 ), TextPaM( nLine, nCol2 ) );
+ pTextView->SetSelection( aSel );
+ pTextView->ShowCursor();
+ vcl::Window* pWindow_ = pTextView->GetWindow();
+ if ( pWindow_ )
+ pWindow_->GrabFocus();
+ }
+ }
+ }
+ }
+ }
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_BASICIDE_MANAGE_LANG:
+ {
+ auto pRequest = std::make_shared<SfxRequest>(rReq);
+ rReq.Ignore(); // the 'old' request is not relevant any more
+ auto xDlg = std::make_shared<ManageLanguageDialog>(pCurWin ? pCurWin->GetFrameWeld() : nullptr, m_pCurLocalizationMgr);
+ weld::DialogController::runAsync(xDlg, [=](sal_Int32 /*nResult*/){
+ pRequest->Done();
+ });
+ }
+ break;
+
+ default:
+ if (pLayout)
+ pLayout->ExecuteGlobal(rReq);
+ if (pCurWin)
+ pCurWin->ExecuteGlobal(rReq);
+ break;
+ }
+}
+
+void Shell::GetState(SfxItemSet &rSet)
+{
+ SfxWhichIter aIter(rSet);
+ for ( sal_uInt16 nWh = aIter.FirstWhich(); nWh != 0; nWh = aIter.NextWhich() )
+ {
+ switch ( nWh )
+ {
+ case SID_NEWDOCDIRECT:
+ {
+ // we do not have a new document factory,
+ // so just forward to a fallback method.
+ SfxGetpApp()->GetSlotState(nWh, nullptr, &rSet);
+ }
+ break;
+ case SID_DOCINFO:
+ {
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_SAVEDOC:
+ {
+ bool bDisable = false;
+
+ if ( pCurWin )
+ {
+ if ( !pCurWin->IsModified() )
+ {
+ ScriptDocument aDocument( pCurWin->GetDocument() );
+ bDisable = ( !aDocument.isAlive() )
+ || ( aDocument.isDocument() ? !aDocument.isDocumentModified() : !IsAppBasicModified() );
+ }
+ }
+ else
+ {
+ bDisable = true;
+ }
+
+ if ( bDisable )
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_NEWWINDOW:
+ case SID_SAVEASDOC:
+ {
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_SIGNATURE:
+ {
+ SignatureState nState = SignatureState::NOSIGNATURES;
+ if ( pCurWin )
+ {
+ DocumentSignature aSignature( pCurWin->GetDocument() );
+ nState = aSignature.getScriptingSignatureState();
+ }
+ rSet.Put( SfxUInt16Item( SID_SIGNATURE, static_cast<sal_uInt16>(nState) ) );
+ }
+ break;
+ case SID_BASICIDE_MODULEDLG:
+ {
+ if ( StarBASIC::IsRunning() )
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_BASICIDE_OBJCAT:
+ if (pLayout)
+ rSet.Put(SfxBoolItem(nWh, aObjectCatalog->IsVisible()));
+ else
+ rSet.Put(SfxVisibilityItem(nWh, false));
+ break;
+ case SID_BASICIDE_SHOWSBX:
+ case SID_BASICIDE_CREATEMACRO:
+ case SID_BASICIDE_EDITMACRO:
+ case SID_BASICIDE_NAMECHANGEDONTAB:
+ {
+ ;
+ }
+ break;
+
+ case SID_BASICIDE_ADDWATCH:
+ case SID_BASICIDE_REMOVEWATCH:
+ case SID_BASICLOAD:
+ case SID_BASICSAVEAS:
+ case SID_BASICIDE_MATCHGROUP:
+ {
+ if (!dynamic_cast<ModulWindow*>(pCurWin.get()))
+ rSet.DisableItem( nWh );
+ else if ( ( nWh == SID_BASICLOAD ) && ( StarBASIC::IsRunning() || ( pCurWin && pCurWin->IsReadOnly() ) ) )
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_BASICRUN:
+ case SID_BASICSTEPINTO:
+ case SID_BASICSTEPOVER:
+ case SID_BASICSTEPOUT:
+ case SID_BASICIDE_TOGGLEBRKPNT:
+ case SID_BASICIDE_MANAGEBRKPNTS:
+ {
+ if (ModulWindow* pMCurWin = dynamic_cast<ModulWindow*>(pCurWin.get()))
+ {
+ if (StarBASIC::IsRunning() && !pMCurWin->GetBasicStatus().bIsInReschedule)
+ rSet.DisableItem(nWh);
+ }
+ else
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_BASICCOMPILE:
+ {
+ if (StarBASIC::IsRunning() || !dynamic_cast<ModulWindow*>(pCurWin.get()))
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_BASICSTOP:
+ {
+ // stop is always possible when some Basic is running...
+ if (!StarBASIC::IsRunning())
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_CHOOSE_CONTROLS:
+ case SID_DIALOG_TESTMODE:
+ case SID_INSERT_SELECT:
+ case SID_INSERT_PUSHBUTTON:
+ case SID_INSERT_RADIOBUTTON:
+ case SID_INSERT_CHECKBOX:
+ case SID_INSERT_LISTBOX:
+ case SID_INSERT_COMBOBOX:
+ case SID_INSERT_GROUPBOX:
+ case SID_INSERT_EDIT:
+ case SID_INSERT_FIXEDTEXT:
+ case SID_INSERT_IMAGECONTROL:
+ case SID_INSERT_PROGRESSBAR:
+ case SID_INSERT_HSCROLLBAR:
+ case SID_INSERT_VSCROLLBAR:
+ case SID_INSERT_HFIXEDLINE:
+ case SID_INSERT_VFIXEDLINE:
+ case SID_INSERT_DATEFIELD:
+ case SID_INSERT_TIMEFIELD:
+ case SID_INSERT_NUMERICFIELD:
+ case SID_INSERT_CURRENCYFIELD:
+ case SID_INSERT_FORMATTEDFIELD:
+ case SID_INSERT_PATTERNFIELD:
+ case SID_INSERT_FILECONTROL:
+ case SID_INSERT_SPINBUTTON:
+ case SID_INSERT_GRIDCONTROL:
+ case SID_INSERT_HYPERLINKCONTROL:
+ case SID_INSERT_TREECONTROL:
+ case SID_INSERT_FORM_RADIO:
+ case SID_INSERT_FORM_CHECK:
+ case SID_INSERT_FORM_LIST:
+ case SID_INSERT_FORM_COMBO:
+ case SID_INSERT_FORM_VSCROLL:
+ case SID_INSERT_FORM_HSCROLL:
+ case SID_INSERT_FORM_SPIN:
+ {
+ if (!dynamic_cast<DialogWindow*>(pCurWin.get()))
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_SEARCH_OPTIONS:
+ {
+ SearchOptionFlags nOptions = SearchOptionFlags::NONE;
+ if( pCurWin )
+ nOptions = pCurWin->GetSearchOptions();
+ rSet.Put( SfxUInt16Item( SID_SEARCH_OPTIONS, static_cast<sal_uInt16>(nOptions) ) );
+ }
+ break;
+ case SID_BASICIDE_LIBSELECTOR:
+ {
+ OUString aName;
+ if ( !m_aCurLibName.isEmpty() )
+ {
+ LibraryLocation eLocation = m_aCurDocument.getLibraryLocation( m_aCurLibName );
+ aName = CreateMgrAndLibStr( m_aCurDocument.getTitle( eLocation ), m_aCurLibName );
+ }
+ SfxStringItem aItem( SID_BASICIDE_LIBSELECTOR, aName );
+ rSet.Put( aItem );
+ }
+ break;
+ case SID_SEARCH_ITEM:
+ {
+ if ( !mpSearchItem )
+ {
+ mpSearchItem.reset( new SvxSearchItem( SID_SEARCH_ITEM ));
+ mpSearchItem->SetSearchString( GetSelectionText( true ));
+ }
+
+ if ( mbJustOpened && HasSelection() )
+ {
+ OUString aText = GetSelectionText( true );
+
+ if ( !aText.isEmpty() )
+ {
+ mpSearchItem->SetSearchString( aText );
+ mpSearchItem->SetSelection( false );
+ }
+ else
+ mpSearchItem->SetSelection( true );
+ }
+
+ mbJustOpened = false;
+ rSet.Put( *mpSearchItem );
+ }
+ break;
+ case SID_BASICIDE_STAT_DATE:
+ {
+ SfxStringItem aItem( SID_BASICIDE_STAT_DATE, "Datum?!" );
+ rSet.Put( aItem );
+ }
+ break;
+ case SID_DOC_MODIFIED:
+ {
+ bool bModified = false;
+
+ if ( pCurWin )
+ {
+ if ( pCurWin->IsModified() )
+ bModified = true;
+ else
+ {
+ ScriptDocument aDocument( pCurWin->GetDocument() );
+ bModified = aDocument.isDocument() ? aDocument.isDocumentModified() : IsAppBasicModified();
+ }
+ }
+
+ SfxBoolItem aItem(SID_DOC_MODIFIED, bModified);
+ rSet.Put( aItem );
+ }
+ break;
+ case SID_BASICIDE_STAT_TITLE:
+ {
+ if ( pCurWin )
+ {
+ OUString aTitle = pCurWin->CreateQualifiedName();
+ SfxStringItem aItem( SID_BASICIDE_STAT_TITLE, aTitle );
+ rSet.Put( aItem );
+ }
+ }
+ break;
+ // are interpreted by the controller:
+ case SID_ATTR_SIZE:
+ case SID_ATTR_INSERT:
+ break;
+ case SID_UNDO:
+ case SID_REDO:
+ {
+ if( GetUndoManager() ) // recursive GetState else
+ GetViewFrame()->GetSlotState( nWh, nullptr, &rSet );
+ }
+ break;
+ case SID_BASICIDE_CURRENT_LANG:
+ {
+ if( (pCurWin && pCurWin->IsReadOnly()) || GetCurLibName().isEmpty() )
+ rSet.DisableItem( nWh );
+ else
+ {
+ OUString aItemStr;
+ std::shared_ptr<LocalizationMgr> pCurMgr(GetCurLocalizationMgr());
+ if ( pCurMgr->isLibraryLocalized() )
+ {
+ Sequence< lang::Locale > aLocaleSeq = pCurMgr->getStringResourceManager()->getLocales();
+ const lang::Locale* pLocale = aLocaleSeq.getConstArray();
+ sal_Int32 i, nCount = aLocaleSeq.getLength();
+
+ // Force different results for any combination of locales and default locale
+ OUString aLangStr;
+ for ( i = 0; i <= nCount; ++i )
+ {
+ lang::Locale aLocale;
+ if( i < nCount )
+ aLocale = pLocale[i];
+ else
+ aLocale = pCurMgr->getStringResourceManager()->getDefaultLocale();
+
+ aLangStr += aLocale.Language + aLocale.Country + aLocale.Variant;
+ }
+ aItemStr = aLangStr;
+ }
+ rSet.Put( SfxStringItem( nWh, aItemStr ) );
+ }
+ }
+ break;
+
+ case SID_BASICIDE_MANAGE_LANG:
+ {
+ if( (pCurWin && pCurWin->IsReadOnly()) || GetCurLibName().isEmpty() )
+ rSet.DisableItem( nWh );
+ }
+ break;
+ case SID_GOTOLINE:
+ {
+ // if this is not a module window hide the
+ // setting, doesn't make sense for example if the
+ // dialog editor is open
+ if (pCurWin && !dynamic_cast<ModulWindow*>(pCurWin.get()))
+ {
+ rSet.DisableItem( nWh );
+ rSet.Put(SfxVisibilityItem(nWh, false));
+ }
+ break;
+ }
+ case SID_BASICIDE_HIDECURPAGE:
+ {
+ if (pTabBar->GetPageCount() == 0)
+ rSet.DisableItem(nWh);
+ }
+ break;
+ case SID_BASICIDE_DELETECURRENT:
+ case SID_BASICIDE_RENAMECURRENT:
+ {
+ if (pTabBar->GetPageCount() == 0 || StarBASIC::IsRunning())
+ rSet.DisableItem(nWh);
+ else if (m_aCurDocument.isInVBAMode())
+ {
+ // disable to delete or rename object modules in IDE
+ BasicManager* pBasMgr = m_aCurDocument.getBasicManager();
+ StarBASIC* pBasic = pBasMgr ? pBasMgr->GetLib(m_aCurLibName) : nullptr;
+ if (pBasic && dynamic_cast<ModulWindow*>(pCurWin.get()))
+ {
+ SbModule* pActiveModule = pBasic->FindModule( pCurWin->GetName() );
+ if ( pActiveModule && ( pActiveModule->GetModuleType() == script::ModuleType::DOCUMENT ) )
+ rSet.DisableItem(nWh);
+ }
+ }
+ }
+ [[fallthrough]];
+
+ case SID_BASICIDE_NEWMODULE:
+ case SID_BASICIDE_NEWDIALOG:
+ {
+ Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ Reference< script::XLibraryContainer2 > xDlgLibContainer( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+ if ( ( xModLibContainer.is() && xModLibContainer->hasByName( m_aCurLibName ) && xModLibContainer->isLibraryReadOnly( m_aCurLibName ) ) ||
+ ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( m_aCurLibName ) && xDlgLibContainer->isLibraryReadOnly( m_aCurLibName ) ) )
+ rSet.DisableItem(nWh);
+ }
+ break;
+ default:
+ if (pLayout)
+ pLayout->GetState(rSet, nWh);
+ }
+ }
+ if ( pCurWin )
+ pCurWin->GetState( rSet );
+}
+
+bool Shell::HasUIFeature(SfxShellFeature nFeature) const
+{
+ assert((nFeature & ~SfxShellFeature::BasicMask) == SfxShellFeature::NONE);
+ bool bResult = false;
+
+ if (nFeature & SfxShellFeature::BasicShowBrowser)
+ {
+ // fade out (in) property browser in module (dialog) windows
+ if (dynamic_cast<DialogWindow*>(pCurWin.get()) && !pCurWin->IsReadOnly())
+ bResult = true;
+ }
+
+ return bResult;
+}
+
+void Shell::SetCurWindow( BaseWindow* pNewWin, bool bUpdateTabBar, bool bRememberAsCurrent )
+{
+ if ( pNewWin == pCurWin )
+ return;
+
+ pCurWin = pNewWin;
+ if (pLayout)
+ pLayout->Deactivating();
+ if (pCurWin)
+ {
+ if (pCurWin->GetType() == TYPE_MODULE)
+ pLayout = pModulLayout.get();
+ else
+ pLayout = pDialogLayout.get();
+ AdjustPosSizePixel(Point(0, 0), GetViewFrame()->GetWindow().GetOutputSizePixel());
+ pLayout->Activating(*pCurWin);
+ GetViewFrame()->GetWindow().SetHelpId(pCurWin->GetHid());
+ if (bRememberAsCurrent)
+ pCurWin->InsertLibInfo();
+ if (GetViewFrame()->GetWindow().IsVisible()) // SFX will do it later otherwise
+ pCurWin->Show();
+ pCurWin->Init();
+ if (!GetExtraData()->ShellInCriticalSection())
+ {
+ vcl::Window* pFrameWindow = &GetViewFrame()->GetWindow();
+ vcl::Window* pFocusWindow = Application::GetFocusWindow();
+ while ( pFocusWindow && ( pFocusWindow != pFrameWindow ) )
+ pFocusWindow = pFocusWindow->GetParent();
+ if ( pFocusWindow ) // Focus in BasicIDE
+ pCurWin->GrabFocus();
+ }
+ }
+ else
+ {
+ SetWindow(pLayout);
+ pLayout = nullptr;
+ }
+ if ( bUpdateTabBar )
+ {
+ sal_uInt16 nKey = GetWindowId( pCurWin );
+ if ( pCurWin && ( pTabBar->GetPagePos( nKey ) == TabBar::PAGE_NOT_FOUND ) )
+ pTabBar->InsertPage( nKey, pCurWin->GetTitle() ); // has just been faded in
+ pTabBar->SetCurPageId( nKey );
+ }
+ if ( pCurWin && pCurWin->IsSuspended() ) // if the window is shown in the case of an error...
+ pCurWin->SetStatus( pCurWin->GetStatus() & ~BASWIN_SUSPENDED );
+ if ( pCurWin )
+ {
+ SetWindow( pCurWin );
+ if ( pCurWin->GetDocument().isDocument() )
+ SfxObjectShell::SetCurrentComponent( pCurWin->GetDocument().getDocument() );
+ }
+ else if (pLayout)
+ {
+ SetWindow(pLayout);
+ GetViewFrame()->GetWindow().SetHelpId( HID_BASICIDE_MODULWINDOW );
+ SfxObjectShell::SetCurrentComponent(nullptr);
+ }
+ aObjectCatalog->SetCurrentEntry(pCurWin);
+ SetUndoManager( pCurWin ? pCurWin->GetUndoManager() : nullptr );
+ InvalidateBasicIDESlots();
+ InvalidateControlSlots();
+ EnableScrollbars(pCurWin != nullptr);
+
+ if ( m_pCurLocalizationMgr )
+ m_pCurLocalizationMgr->handleTranslationbar();
+
+ ManageToolbars();
+
+ // fade out (in) property browser in module (dialog) windows
+ UIFeatureChanged();
+}
+
+void Shell::ManageToolbars()
+{
+ static constexpr OUStringLiteral aMacroBarResName = u"private:resource/toolbar/macrobar";
+ static constexpr OUStringLiteral aDialogBarResName = u"private:resource/toolbar/dialogbar";
+ static constexpr OUStringLiteral aInsertControlsBarResName
+ = u"private:resource/toolbar/insertcontrolsbar";
+ static constexpr OUStringLiteral aFormControlsBarResName
+ = u"private:resource/toolbar/formcontrolsbar";
+
+ if( !pCurWin )
+ return;
+
+ Reference< beans::XPropertySet > xFrameProps
+ ( GetViewFrame()->GetFrame().GetFrameInterface(), uno::UNO_QUERY );
+ if ( !xFrameProps.is() )
+ return;
+
+ Reference< css::frame::XLayoutManager > xLayoutManager;
+ uno::Any a = xFrameProps->getPropertyValue( "LayoutManager" );
+ a >>= xLayoutManager;
+ if ( !xLayoutManager.is() )
+ return;
+
+ xLayoutManager->lock();
+ if (dynamic_cast<DialogWindow*>(pCurWin.get()))
+ {
+ xLayoutManager->destroyElement( aMacroBarResName );
+
+ xLayoutManager->requestElement( aDialogBarResName );
+ xLayoutManager->requestElement( aInsertControlsBarResName );
+ xLayoutManager->requestElement( aFormControlsBarResName );
+ }
+ else
+ {
+ xLayoutManager->destroyElement( aDialogBarResName );
+ xLayoutManager->destroyElement( aInsertControlsBarResName );
+ xLayoutManager->destroyElement( aFormControlsBarResName );
+
+ xLayoutManager->requestElement( aMacroBarResName );
+ }
+ xLayoutManager->unlock();
+}
+
+VclPtr<BaseWindow> Shell::FindApplicationWindow()
+{
+ return FindWindow( ScriptDocument::getApplicationScriptDocument(), u"", u"", TYPE_UNKNOWN );
+}
+
+VclPtr<BaseWindow> Shell::FindWindow(
+ ScriptDocument const& rDocument,
+ std::u16string_view rLibName, std::u16string_view rName,
+ ItemType eType, bool bFindSuspended
+)
+{
+ for (auto const& window : aWindowTable)
+ {
+ BaseWindow* const pWin = window.second;
+ if (pWin->Is(rDocument, rLibName, rName, eType, bFindSuspended))
+ return pWin;
+ }
+ return nullptr;
+}
+
+bool Shell::CallBasicErrorHdl( StarBASIC const * pBasic )
+{
+ VclPtr<ModulWindow> pModWin = ShowActiveModuleWindow( pBasic );
+ if ( pModWin )
+ pModWin->BasicErrorHdl( pBasic );
+ return false;
+}
+
+BasicDebugFlags Shell::CallBasicBreakHdl( StarBASIC const * pBasic )
+{
+ BasicDebugFlags nRet = BasicDebugFlags::NONE;
+ VclPtr<ModulWindow> pModWin = ShowActiveModuleWindow( pBasic );
+ if ( pModWin )
+ {
+ bool bAppWindowDisabled, bDispatcherLocked;
+ sal_uInt16 nWaitCount;
+ SfxUInt16Item *pSWActionCount, *pSWLockViewCount;
+ BasicStopped( &bAppWindowDisabled, &bDispatcherLocked,
+ &nWaitCount, &pSWActionCount, &pSWLockViewCount );
+
+ nRet = pModWin->BasicBreakHdl();
+
+ if ( StarBASIC::IsRunning() ) // if cancelled...
+ {
+ if ( bAppWindowDisabled )
+ Application::GetDefDialogParent()->set_sensitive(false);
+
+ if ( nWaitCount )
+ {
+ Shell* pShell = GetShell();
+ for ( sal_uInt16 n = 0; n < nWaitCount; n++ )
+ pShell->GetViewFrame()->GetWindow().EnterWait();
+ }
+ }
+ }
+ return nRet;
+}
+
+VclPtr<ModulWindow> Shell::ShowActiveModuleWindow( StarBASIC const * pBasic )
+{
+ SetCurLib( ScriptDocument::getApplicationScriptDocument(), OUString(), false );
+
+ SbModule* pActiveModule = StarBASIC::GetActiveModule();
+ if (SbClassModuleObject* pCMO = dynamic_cast<SbClassModuleObject*>(pActiveModule))
+ pActiveModule = pCMO->getClassModule();
+
+ DBG_ASSERT( pActiveModule, "No active module in ErrorHdl!?" );
+ if ( pActiveModule )
+ {
+ VclPtr<ModulWindow> pWin;
+ SbxObject* pParent = pActiveModule->GetParent();
+ if (StarBASIC* pLib = dynamic_cast<StarBASIC*>(pParent))
+ {
+ if (BasicManager* pBasMgr = FindBasicManager(pLib))
+ {
+ ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
+ const OUString& aLibName = pLib->GetName();
+ pWin = FindBasWin( aDocument, aLibName, pActiveModule->GetName(), true );
+ DBG_ASSERT( pWin, "Error/Step-Hdl: Window was not created/found!" );
+ SetCurLib( aDocument, aLibName );
+ SetCurWindow( pWin, true );
+ }
+ }
+ else
+ SAL_WARN( "basctl.basicide", "No BASIC!");
+ if (BasicManager* pBasicMgr = FindBasicManager(pBasic))
+ StartListening(*pBasicMgr, DuplicateHandling::Prevent /* log on only once */);
+ return pWin;
+ }
+ return nullptr;
+}
+
+void Shell::AdjustPosSizePixel( const Point &rPos, const Size &rSize )
+{
+ // not if iconified because the whole text would be displaced then at restore
+ if ( GetViewFrame()->GetWindow().GetOutputSizePixel().Height() == 0 )
+ return;
+
+ Size aTabBarSize;
+ aTabBarSize.setHeight( GetViewFrame()->GetWindow().GetFont().GetFontHeight() + TAB_HEIGHT_MARGIN );
+ aTabBarSize.setWidth( rSize.Width() );
+
+ Size aSz( rSize );
+ Size aScrollBarBoxSz( aScrollBarBox->GetSizePixel() );
+ aSz.AdjustHeight( -(aScrollBarBoxSz.Height()) );
+ aSz.AdjustHeight( -(aTabBarSize.Height()) );
+
+ Size aOutSz( aSz );
+ aSz.AdjustWidth( -(aScrollBarBoxSz.Width()) );
+ aScrollBarBox->SetPosPixel( Point( rSize.Width() - aScrollBarBoxSz.Width(), rSize.Height() - aScrollBarBoxSz.Height() ) );
+ aVScrollBar->SetPosSizePixel( Point( rPos.X()+aSz.Width(), rPos.Y() ), Size( aScrollBarBoxSz.Width(), aSz.Height() ) );
+ aHScrollBar->SetPosSizePixel( Point( rPos.X(), rPos.Y()+aSz.Height() ), Size( aSz.Width(), aScrollBarBoxSz.Height() ) );
+ pTabBar->SetPosSizePixel( Point( rPos.X(), rPos.Y()+aScrollBarBoxSz.Height()+aSz.Height()), aTabBarSize );
+
+ if (pLayout)
+ pLayout->SetPosSizePixel(rPos, dynamic_cast<DialogWindow*>(pCurWin.get()) ? aSz : aOutSz);
+}
+
+Reference< XModel > Shell::GetCurrentDocument() const
+{
+ Reference< XModel > xDocument;
+ if ( pCurWin && pCurWin->GetDocument().isDocument() )
+ xDocument = pCurWin->GetDocument().getDocument();
+ return xDocument;
+}
+
+void Shell::Activate( bool bMDI )
+{
+ SfxViewShell::Activate( bMDI );
+
+ if ( bMDI )
+ {
+ if (DialogWindow* pDCurWin = dynamic_cast<DialogWindow*>(pCurWin.get()))
+ pDCurWin->UpdateBrowser();
+ }
+}
+
+void Shell::Deactivate( bool bMDI )
+{
+ // bMDI == true means that another MDI has been activated; in case of a
+ // deactivate due to a MessageBox bMDI is false
+ if ( bMDI )
+ {
+ if (DialogWindow* pXDlgWin = dynamic_cast<DialogWindow*>(pCurWin.get()))
+ {
+ pXDlgWin->DisableBrowser();
+ if( pXDlgWin->IsModified() )
+ MarkDocumentModified( pXDlgWin->GetDocument() );
+ }
+ }
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/basides2.cxx b/basctl/source/basicide/basides2.cxx
new file mode 100644
index 000000000..ca219f4c9
--- /dev/null
+++ b/basctl/source/basicide/basides2.cxx
@@ -0,0 +1,242 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <docsignature.hxx>
+
+#include "basicrenderable.hxx"
+
+#include <com/sun/star/frame/XTitle.hpp>
+
+#include <iderid.hxx>
+#include <strings.hrc>
+#include "baside2.hxx"
+#include "basdoc.hxx"
+#include <basidesh.hxx>
+#include <tools/debug.hxx>
+#include <vcl/texteng.hxx>
+#include <vcl/textview.hxx>
+#include <sfx2/signaturestate.hxx>
+#include <sfx2/viewfrm.hxx>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+Reference< view::XRenderable > Shell::GetRenderable()
+{
+ return Reference<view::XRenderable>( new Renderable(pCurWin) );
+}
+
+bool Shell::HasSelection( bool /* bText */ ) const
+{
+ if (ModulWindow* pMCurWin = dynamic_cast<ModulWindow*>(pCurWin.get()))
+ {
+ TextView* pEditView = pMCurWin->GetEditView();
+ if ( pEditView && pEditView->HasSelection() )
+ return true;
+ }
+ return false;
+}
+
+OUString Shell::GetSelectionText( bool bWholeWord, bool /*bOnlyASample*/ )
+{
+ OUString aText;
+ if (ModulWindow* pMCurWin = dynamic_cast<ModulWindow*>(pCurWin.get()))
+ {
+ if (TextView* pEditView = pMCurWin->GetEditView())
+ {
+ if ( bWholeWord && !pEditView->HasSelection() )
+ {
+ aText = pEditView->GetTextEngine()->GetWord( pEditView->GetSelection().GetEnd() );
+ }
+ else
+ {
+ TextSelection aSel = pEditView->GetSelection();
+ if ( !bWholeWord || ( aSel.GetStart().GetPara() == aSel.GetEnd().GetPara() ) )
+ aText = pEditView->GetSelected();
+ }
+ }
+ }
+ return aText;
+}
+
+SfxPrinter* Shell::GetPrinter( bool bCreate )
+{
+ if ( pCurWin )
+ {
+ DocShell* pDocShell = static_cast<DocShell*>(GetViewFrame()->GetObjectShell());
+ assert(pDocShell && "DocShell ?!");
+ return pDocShell->GetPrinter( bCreate );
+ }
+ return nullptr;
+}
+
+sal_uInt16 Shell::SetPrinter( SfxPrinter *pNewPrinter, SfxPrinterChangeFlags )
+{
+ DocShell* pDocShell = static_cast<DocShell*>(GetViewFrame()->GetObjectShell());
+ assert(pDocShell && "DocShell ?!");
+ pDocShell->SetPrinter( pNewPrinter );
+ return 0;
+}
+
+void Shell::SetMDITitle()
+{
+ OUString aTitle;
+ if ( !m_aCurLibName.isEmpty() )
+ {
+ LibraryLocation eLocation = m_aCurDocument.getLibraryLocation( m_aCurLibName );
+ aTitle = m_aCurDocument.getTitle(eLocation) + "." + m_aCurLibName ;
+ }
+ else
+ aTitle = IDEResId(RID_STR_ALL) ;
+
+ DocumentSignature aCurSignature( m_aCurDocument );
+ if ( aCurSignature.getScriptingSignatureState() == SignatureState::OK )
+ {
+ aTitle += " " + IDEResId(RID_STR_SIGNED) + " ";
+ }
+
+ SfxViewFrame* pViewFrame = GetViewFrame();
+ if ( !pViewFrame )
+ return;
+
+ SfxObjectShell* pShell = pViewFrame->GetObjectShell();
+ if ( pShell && pShell->GetTitle( SFX_TITLE_CAPTION ) != aTitle )
+ {
+ pShell->SetTitle( aTitle );
+ pShell->SetModified(false);
+ }
+
+ css::uno::Reference< css::frame::XController > xController = GetController ();
+ css::uno::Reference< css::frame::XTitle > xTitle (xController, css::uno::UNO_QUERY);
+ if (xTitle.is ())
+ xTitle->setTitle (aTitle);
+}
+
+VclPtr<ModulWindow> Shell::CreateBasWin( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName )
+{
+ bCreatingWindow = true;
+
+ sal_uInt16 nKey = 0;
+ VclPtr<ModulWindow> pWin;
+
+ OUString aLibName( rLibName );
+ OUString aModName( rModName );
+
+ if ( aLibName.isEmpty() )
+ aLibName = "Standard" ;
+
+ uno::Reference< container::XNameContainer > xLib = rDocument.getOrCreateLibrary( E_SCRIPTS, aLibName );
+
+ if ( aModName.isEmpty() )
+ aModName = rDocument.createObjectName( E_SCRIPTS, aLibName );
+
+ // maybe there's an suspended one?
+ pWin = FindBasWin( rDocument, aLibName, aModName, false, true );
+
+ if ( !pWin )
+ {
+ OUString aModule;
+ bool bSuccess = false;
+ if ( rDocument.hasModule( aLibName, aModName ) )
+ bSuccess = rDocument.getModule( aLibName, aModName, aModule );
+ else
+ bSuccess = rDocument.createModule( aLibName, aModName, true, aModule );
+
+ if ( bSuccess )
+ {
+ pWin = FindBasWin( rDocument, aLibName, aModName, false, true );
+ if( !pWin )
+ {
+ // new module window
+ if (!pModulLayout)
+ pModulLayout.reset(VclPtr<ModulWindowLayout>::Create(&GetViewFrame()->GetWindow(), *aObjectCatalog));
+ pWin = VclPtr<ModulWindow>::Create(pModulLayout.get(), rDocument, aLibName, aModName, aModule);
+ nKey = InsertWindowInTable( pWin );
+ }
+ else // we've gotten called recursively ( via listener from createModule above ), get outta here
+ return pWin;
+ }
+ }
+ else
+ {
+ pWin->SetStatus( pWin->GetStatus() & ~BASWIN_SUSPENDED );
+ nKey = GetWindowId( pWin );
+ DBG_ASSERT( nKey, "CreateBasWin: No Key - Window not found!" );
+ }
+ if( nKey && xLib.is() && rDocument.isInVBAMode() )
+ {
+ // display a nice friendly name in the ObjectModule tab,
+ // combining the objectname and module name, e.g. Sheet1 ( Financials )
+ OUString sObjName;
+ ModuleInfoHelper::getObjectName( xLib, rModName, sObjName );
+ if( !sObjName.isEmpty() )
+ {
+ aModName += " (" + sObjName + ")";
+ }
+ }
+ pTabBar->InsertPage( nKey, aModName );
+ pTabBar->Sort();
+ if(pWin)
+ {
+ pWin->GrabScrollBars( aHScrollBar.get(), aVScrollBar.get() );
+ if ( !pCurWin )
+ SetCurWindow( pWin, false, false );
+ }
+ bCreatingWindow = false;
+ return pWin;
+}
+
+VclPtr<ModulWindow> Shell::FindBasWin (
+ ScriptDocument const& rDocument,
+ OUString const& rLibName, OUString const& rName,
+ bool bCreateIfNotExist, bool bFindSuspended
+)
+{
+ if (VclPtr<BaseWindow> pWin = FindWindow(rDocument, rLibName, rName, TYPE_MODULE, bFindSuspended))
+ return VclPtr<ModulWindow>(static_cast<ModulWindow*>(pWin.get()));
+ return bCreateIfNotExist ? CreateBasWin(rDocument, rLibName, rName) : nullptr;
+}
+
+void Shell::Move()
+{
+}
+
+void Shell::ShowCursor( bool bOn )
+{
+ if (ModulWindow* pMCurWin = dynamic_cast<ModulWindow*>(pCurWin.get()))
+ pMCurWin->ShowCursor(bOn);
+}
+
+// only if basic window above:
+void Shell::ExecuteBasic( SfxRequest& rReq )
+{
+ if (dynamic_cast<ModulWindow*>(pCurWin.get()))
+ {
+ pCurWin->ExecuteCommand( rReq );
+ if (nShellCount)
+ CheckWindows();
+ }
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/basides3.cxx b/basctl/source/basicide/basides3.cxx
new file mode 100644
index 000000000..fb827a510
--- /dev/null
+++ b/basctl/source/basicide/basides3.cxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <baside3.hxx>
+#include <basidesh.hxx>
+#include <localizationmgr.hxx>
+#include <dlgedview.hxx>
+#include <xmlscript/xmldlg_imexp.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace basctl
+{
+
+using namespace comphelper;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::io;
+
+VclPtr<DialogWindow> Shell::CreateDlgWin( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rDlgName )
+{
+ bCreatingWindow = true;
+
+ sal_uInt16 nKey = 0;
+ VclPtr<DialogWindow> pWin;
+ OUString aLibName( rLibName );
+ OUString aDlgName( rDlgName );
+
+ if ( aLibName.isEmpty() )
+ aLibName = "Standard" ;
+
+ rDocument.getOrCreateLibrary( E_DIALOGS, aLibName );
+
+ if ( aDlgName.isEmpty() )
+ aDlgName = rDocument.createObjectName( E_DIALOGS, aLibName );
+
+ // maybe there's a suspended one?
+ pWin = FindDlgWin( rDocument, aLibName, aDlgName, false, true );
+
+ if ( !pWin )
+ {
+ try
+ {
+ Reference< io::XInputStreamProvider > xISP;
+ if ( rDocument.hasDialog( aLibName, aDlgName ) )
+ rDocument.getDialog( aLibName, aDlgName, xISP );
+ else
+ rDocument.createDialog( aLibName, aDlgName, xISP );
+
+ if ( xISP.is() )
+ {
+ // create dialog model
+ Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
+ Reference< container::XNameContainer > xDialogModel( xContext->getServiceManager()->createInstanceWithContext
+ ( "com.sun.star.awt.UnoControlDialogModel", xContext ), UNO_QUERY );
+ Reference< XInputStream > xInput( xISP->createInputStream() );
+ ::xmlscript::importDialogModel( xInput, xDialogModel, xContext, rDocument.isDocument() ? rDocument.getDocument() : Reference< frame::XModel >() );
+ LocalizationMgr::setStringResourceAtDialog( rDocument, rLibName, aDlgName, xDialogModel );
+
+ // new dialog window
+ if (!pDialogLayout)
+ pDialogLayout.reset(VclPtr<DialogWindowLayout>::Create(&GetViewFrame()->GetWindow(), *aObjectCatalog));
+ pWin = VclPtr<DialogWindow>::Create(pDialogLayout.get(), rDocument, aLibName, aDlgName, xDialogModel);
+ nKey = InsertWindowInTable( pWin );
+ }
+ }
+ catch (const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+ else
+ {
+ pWin->SetStatus( pWin->GetStatus() & ~BASWIN_SUSPENDED );
+ nKey = GetWindowId( pWin );
+ DBG_ASSERT( nKey, "CreateDlgWin: No Key - Window not found!" );
+ }
+
+ if( pWin )
+ {
+ pWin->GrabScrollBars( aHScrollBar.get(), aVScrollBar.get() );
+ pTabBar->InsertPage( nKey, aDlgName );
+ pTabBar->Sort();
+ if ( !pCurWin )
+ SetCurWindow( pWin, false, false );
+ }
+
+ bCreatingWindow = false;
+ return pWin;
+}
+
+VclPtr<DialogWindow> Shell::FindDlgWin (
+ ScriptDocument const& rDocument,
+ OUString const& rLibName, OUString const& rName,
+ bool bCreateIfNotExist, bool bFindSuspended
+)
+{
+ if (VclPtr<BaseWindow> pWin = FindWindow(rDocument, rLibName, rName, TYPE_DIALOG, bFindSuspended))
+ return static_cast<DialogWindow*>(pWin.get());
+ return bCreateIfNotExist ? CreateDlgWin(rDocument, rLibName, rName) : nullptr;
+}
+
+sal_uInt16 Shell::GetWindowId(const BaseWindow* pWin) const
+{
+ for (auto const& window : aWindowTable)
+ if ( window.second == pWin )
+ return window.first;
+ return 0;
+}
+
+SdrView* Shell::GetCurDlgView() const
+{
+ if (DialogWindow* pDCurWin = dynamic_cast<DialogWindow*>(pCurWin.get()))
+ return &pDCurWin->GetView();
+ else
+ return nullptr;
+}
+
+// only if dialogue window above:
+void Shell::ExecuteDialog( SfxRequest& rReq )
+{
+ if (pCurWin && (dynamic_cast<DialogWindow*>(pCurWin.get()) || rReq.GetSlot() == SID_IMPORT_DIALOG))
+ pCurWin->ExecuteCommand(rReq);
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/basidesh.cxx b/basctl/source/basicide/basidesh.cxx
new file mode 100644
index 000000000..0e8521982
--- /dev/null
+++ b/basctl/source/basicide/basidesh.cxx
@@ -0,0 +1,952 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_options.h>
+
+#include <tools/diagnose_ex.h>
+#include <basic/basmgr.hxx>
+#include <svx/svxids.hrc>
+#include <iderid.hxx>
+#include <strings.hrc>
+#include "baside2.hxx"
+#include <baside3.hxx>
+#include "basdoc.hxx"
+#include <IDEComboBox.hxx>
+#include <editeng/sizeitem.hxx>
+#include "iderdll2.hxx"
+#include <basidectrlr.hxx>
+#include <basidesh.hxx>
+#include <basobj.hxx>
+#include <localizationmgr.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dinfdlg.hxx>
+#include <sfx2/infobar.hxx>
+#include <sfx2/minfitem.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/srchitem.hxx>
+#include <tools/debug.hxx>
+
+#if defined(DISABLE_DYNLOADING) || ENABLE_MERGELIBS
+/* Avoid clash with the ones from svx/source/form/typemap.cxx */
+#define aSfxDocumentInfoItem_Impl basctl_source_basicide_basidesh_aSfxDocumentInfoItem_Impl
+#define aSfxUnoAnyItem_Impl basctl_source_basicide_basidesh_aSfxUnoAnyItem_Impl
+#endif
+
+#define ShellClass_basctl_Shell
+#define SFX_TYPEMAP
+#include <basslots.hxx>
+
+#if defined(DISABLE_DYNLOADING) || ENABLE_MERGELIBS
+#undef aSfxDocumentInfoItem_Impl
+#undef aSfxUnoAnyItem_Impl
+#endif
+
+#include <iderdll.hxx>
+#include <svx/pszctrl.hxx>
+#include <svx/insctrl.hxx>
+#include <svx/srchdlg.hxx>
+#include <com/sun/star/script/XLibraryContainerPassword.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <svx/xmlsecctrl.hxx>
+#include <sfx2/viewfac.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <cppuhelper/implbase.hxx>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star;
+
+class ContainerListenerImpl : public ::cppu::WeakImplHelper< container::XContainerListener >
+{
+ Shell* mpShell;
+public:
+ explicit ContainerListenerImpl(Shell* pShell)
+ : mpShell(pShell)
+ {
+ }
+
+ void addContainerListener( const ScriptDocument& rScriptDocument, const OUString& aLibName )
+ {
+ try
+ {
+ uno::Reference< container::XContainer > xContainer( rScriptDocument.getLibrary( E_SCRIPTS, aLibName, false ), uno::UNO_QUERY );
+ if ( xContainer.is() )
+ {
+ uno::Reference< container::XContainerListener > xContainerListener( this );
+ xContainer->addContainerListener( xContainerListener );
+ }
+ }
+ catch(const uno::Exception& ) {}
+ }
+ void removeContainerListener( const ScriptDocument& rScriptDocument, const OUString& aLibName )
+ {
+ try
+ {
+ uno::Reference< container::XContainer > xContainer( rScriptDocument.getLibrary( E_SCRIPTS, aLibName, false ), uno::UNO_QUERY );
+ if ( xContainer.is() )
+ {
+ uno::Reference< container::XContainerListener > xContainerListener( this );
+ xContainer->removeContainerListener( xContainerListener );
+ }
+ }
+ catch(const uno::Exception& ) {}
+ }
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const lang::EventObject& ) override {}
+
+ // XContainerListener
+ virtual void SAL_CALL elementInserted( const container::ContainerEvent& Event ) override
+ {
+ OUString sModuleName;
+ if( mpShell && ( Event.Accessor >>= sModuleName ) )
+ mpShell->FindBasWin( mpShell->m_aCurDocument, mpShell->m_aCurLibName, sModuleName, true );
+ }
+ virtual void SAL_CALL elementReplaced( const container::ContainerEvent& ) override { }
+ virtual void SAL_CALL elementRemoved( const container::ContainerEvent& Event ) override
+ {
+ OUString sModuleName;
+ if( mpShell && ( Event.Accessor >>= sModuleName ) )
+ {
+ VclPtr<ModulWindow> pWin = mpShell->FindBasWin(mpShell->m_aCurDocument, mpShell->m_aCurLibName, sModuleName, false, true);
+ if( pWin )
+ mpShell->RemoveWindow( pWin, true );
+ }
+ }
+
+};
+
+SFX_IMPL_NAMED_VIEWFACTORY( Shell, "Default" )
+{
+ SFX_VIEW_REGISTRATION( DocShell );
+}
+
+SFX_IMPL_INTERFACE(basctl_Shell, SfxViewShell)
+
+void basctl_Shell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterChildWindow(SID_SEARCH_DLG);
+ GetStaticInterface()->RegisterChildWindow(SID_SHOW_PROPERTYBROWSER, false, SfxShellFeature::BasicShowBrowser);
+ GetStaticInterface()->RegisterChildWindow(SfxInfoBarContainerChild::GetChildWindowId());
+
+ GetStaticInterface()->RegisterPopupMenu("dialog");
+}
+
+unsigned Shell::nShellCount = 0;
+
+Shell::Shell( SfxViewFrame* pFrame_, SfxViewShell* /* pOldShell */ ) :
+ SfxViewShell( pFrame_, SfxViewShellFlags::NO_NEWWINDOW ),
+ m_aCurDocument( ScriptDocument::getApplicationScriptDocument() ),
+ aHScrollBar( VclPtr<ScrollBar>::Create(&GetViewFrame()->GetWindow(), WinBits( WB_HSCROLL | WB_DRAG )) ),
+ aVScrollBar( VclPtr<ScrollBar>::Create(&GetViewFrame()->GetWindow(), WinBits( WB_VSCROLL | WB_DRAG )) ),
+ aScrollBarBox( VclPtr<ScrollBarBox>::Create(&GetViewFrame()->GetWindow(), WinBits( WB_SIZEABLE )) ),
+ pLayout(nullptr),
+ aObjectCatalog(VclPtr<ObjectCatalog>::Create(&GetViewFrame()->GetWindow())),
+ m_bAppBasicModified( false ),
+ m_aNotifier( *this )
+{
+ m_xLibListener = new ContainerListenerImpl( this );
+ Init();
+ nShellCount++;
+}
+
+void Shell::Init()
+{
+ SvxPosSizeStatusBarControl::RegisterControl();
+ SvxInsertStatusBarControl::RegisterControl();
+ XmlSecStatusBarControl::RegisterControl( SID_SIGNATURE );
+
+ SvxSearchDialogWrapper::RegisterChildWindow();
+
+ GetExtraData()->ShellInCriticalSection() = true;
+
+ SetName( "BasicIDE" );
+
+ LibBoxControl::RegisterControl( SID_BASICIDE_LIBSELECTOR );
+ LanguageBoxControl::RegisterControl( SID_BASICIDE_CURRENT_LANG );
+
+ GetViewFrame()->GetWindow().SetBackground(
+ GetViewFrame()->GetWindow().GetSettings().GetStyleSettings().GetWindowColor()
+ );
+
+ pCurWin = nullptr;
+ m_aCurDocument = ScriptDocument::getApplicationScriptDocument();
+ bCreatingWindow = false;
+
+ pTabBar.reset(VclPtr<TabBar>::Create(&GetViewFrame()->GetWindow()));
+
+ nCurKey = 100;
+ InitScrollBars();
+ InitTabBar();
+
+ SetCurLib( ScriptDocument::getApplicationScriptDocument(), "Standard", false, false );
+
+ ShellCreated(this);
+
+ GetExtraData()->ShellInCriticalSection() = false;
+
+ // It's enough to create the controller ...
+ // It will be public by using magic :-)
+ new Controller(this);
+
+ // Force updating the title ! Because it must be set to the controller
+ // it has to be called directly after creating those controller.
+ SetMDITitle ();
+
+ UpdateWindows();
+}
+
+Shell::~Shell()
+{
+ m_aNotifier.dispose();
+
+ ShellDestroyed(this);
+
+ // so that on a basic saving error, the shell doesn't pop right up again
+ GetExtraData()->ShellInCriticalSection() = true;
+
+ SetWindow( nullptr );
+ SetCurWindow( nullptr );
+
+ aObjectCatalog.disposeAndClear();
+ aScrollBarBox.disposeAndClear();
+ aVScrollBar.disposeAndClear();
+ aHScrollBar.disposeAndClear();
+
+ for (auto & window : aWindowTable)
+ {
+ // no store; does already happen when the BasicManagers are destroyed
+ window.second.disposeAndClear();
+ }
+
+ // no store; does already happen when the BasicManagers are destroyed
+ aWindowTable.clear();
+
+ // Destroy all ContainerListeners for Basic Container.
+ if (ContainerListenerImpl* pListener = static_cast<ContainerListenerImpl*>(m_xLibListener.get()))
+ pListener->removeContainerListener(m_aCurDocument, m_aCurLibName);
+
+ GetExtraData()->ShellInCriticalSection() = false;
+
+ nShellCount--;
+
+ pDialogLayout.disposeAndClear();
+ pModulLayout.disposeAndClear();
+ pTabBar.disposeAndClear();
+}
+
+void Shell::onDocumentCreated( const ScriptDocument& /*_rDocument*/ )
+{
+ if (pCurWin)
+ pCurWin->OnNewDocument();
+
+ UpdateWindows();
+}
+
+void Shell::onDocumentOpened( const ScriptDocument& /*_rDocument*/ )
+{
+ if (pCurWin)
+ pCurWin->OnNewDocument();
+ UpdateWindows();
+}
+
+void Shell::onDocumentSave( const ScriptDocument& /*_rDocument*/ )
+{
+ StoreAllWindowData();
+}
+
+void Shell::onDocumentSaveDone( const ScriptDocument& /*_rDocument*/ )
+{
+ // #i115671: Update SID_SAVEDOC after saving is completed
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_SAVEDOC );
+}
+
+void Shell::onDocumentSaveAs( const ScriptDocument& /*_rDocument*/ )
+{
+ StoreAllWindowData();
+}
+
+void Shell::onDocumentSaveAsDone( const ScriptDocument& /*_rDocument*/ )
+{
+ // not interested in
+}
+
+void Shell::onDocumentClosed( const ScriptDocument& _rDocument )
+{
+ if ( !_rDocument.isValid() )
+ return;
+
+ bool bSetCurWindow = false;
+ bool bSetCurLib = ( _rDocument == m_aCurDocument );
+ std::vector<VclPtr<BaseWindow> > aDeleteVec;
+
+ // remove all windows which belong to this document
+ for (auto const& window : aWindowTable)
+ {
+ BaseWindow* pWin = window.second;
+ if ( pWin->IsDocument( _rDocument ) )
+ {
+ if ( pWin->GetStatus() & (BASWIN_RUNNINGBASIC|BASWIN_INRESCHEDULE) )
+ {
+ pWin->AddStatus( BASWIN_TOBEKILLED );
+ pWin->Hide();
+ StarBASIC::Stop();
+ // there's no notify
+ pWin->BasicStopped();
+ }
+ else
+ aDeleteVec.emplace_back(pWin );
+ }
+ }
+ // delete windows outside main loop so we don't invalidate the original iterator
+ for (VclPtr<BaseWindow> const & pWin : aDeleteVec)
+ {
+ pWin->StoreData();
+ if ( pWin == pCurWin )
+ bSetCurWindow = true;
+ RemoveWindow( pWin, true, false );
+ }
+
+ // remove lib info
+ if (ExtraData* pData = GetExtraData())
+ pData->GetLibInfo().RemoveInfoFor( _rDocument );
+
+ if ( bSetCurLib )
+ SetCurLib( ScriptDocument::getApplicationScriptDocument(), "Standard", true, false );
+ else if ( bSetCurWindow )
+ SetCurWindow( FindApplicationWindow(), true );
+}
+
+void Shell::onDocumentTitleChanged( const ScriptDocument& /*_rDocument*/ )
+{
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_BASICIDE_LIBSELECTOR, true );
+ SetMDITitle();
+}
+
+void Shell::onDocumentModeChanged( const ScriptDocument& _rDocument )
+{
+ for (auto const& window : aWindowTable)
+ {
+ BaseWindow* pWin = window.second;
+ if ( pWin->IsDocument( _rDocument ) && _rDocument.isDocument() )
+ pWin->SetReadOnly( _rDocument.isReadOnly() );
+ }
+}
+
+void Shell::StoreAllWindowData( bool bPersistent )
+{
+ for (auto const& window : aWindowTable)
+ {
+ BaseWindow* pWin = window.second;
+ DBG_ASSERT( pWin, "PrepareClose: NULL-Pointer in Table?" );
+ if ( !pWin->IsSuspended() )
+ pWin->StoreData();
+ }
+
+ if ( bPersistent )
+ {
+ SfxGetpApp()->SaveBasicAndDialogContainer();
+ SetAppBasicModified(false);
+
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate( SID_SAVEDOC );
+ pBindings->Update( SID_SAVEDOC );
+ }
+ }
+}
+
+
+bool Shell::PrepareClose( bool bUI )
+{
+ // reset here because it's modified after printing etc. (DocInfo)
+ GetViewFrame()->GetObjectShell()->SetModified(false);
+
+ if ( StarBASIC::IsRunning() )
+ {
+ if( bUI )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetViewFrame()->GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ IDEResId(RID_STR_CANNOTCLOSE)));
+ xInfoBox->run();
+ }
+ return false;
+ }
+ else
+ {
+ StoreAllWindowData( false ); // don't write on the disk, that will be done later automatically
+ return true;
+ }
+}
+
+void Shell::InitScrollBars()
+{
+ aVScrollBar->SetLineSize( 300 );
+ aVScrollBar->SetPageSize( 2000 );
+ aHScrollBar->SetLineSize( 300 );
+ aHScrollBar->SetPageSize( 2000 );
+ aHScrollBar->Enable();
+ aVScrollBar->Enable();
+ aVScrollBar->Show();
+ aHScrollBar->Show();
+ aScrollBarBox->Show();
+}
+
+
+void Shell::InitTabBar()
+{
+ pTabBar->Enable();
+ pTabBar->Show();
+ pTabBar->SetSelectHdl( LINK( this, Shell, TabBarHdl ) );
+}
+
+
+void Shell::OuterResizePixel( const Point &rPos, const Size &rSize )
+{
+ AdjustPosSizePixel( rPos, rSize );
+}
+
+
+IMPL_LINK( Shell, TabBarHdl, ::TabBar *, pCurTabBar, void )
+{
+ sal_uInt16 nCurId = pCurTabBar->GetCurPageId();
+ BaseWindow* pWin = aWindowTable[ nCurId ].get();
+ DBG_ASSERT( pWin, "Entry in TabBar is not matching a window!" );
+ SetCurWindow( pWin );
+}
+
+
+bool Shell::NextPage( bool bPrev )
+{
+ bool bRet = false;
+ sal_uInt16 nPos = pTabBar->GetPagePos( pTabBar->GetCurPageId() );
+
+ if ( bPrev )
+ --nPos;
+ else
+ ++nPos;
+
+ if ( nPos < pTabBar->GetPageCount() )
+ {
+ VclPtr<BaseWindow> pWin = aWindowTable[ pTabBar->GetPageId( nPos ) ];
+ SetCurWindow( pWin, true );
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+SfxUndoManager* Shell::GetUndoManager()
+{
+ SfxUndoManager* pMgr = nullptr;
+ if( pCurWin )
+ pMgr = pCurWin->GetUndoManager();
+
+ return pMgr;
+}
+
+
+void Shell::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if (!GetShell())
+ return;
+
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ EndListening( rBC, true /* log off all */ );
+ aObjectCatalog->UpdateEntries();
+ }
+
+ SbxHint const* pSbxHint = dynamic_cast<SbxHint const*>(&rHint);
+ if (!pSbxHint)
+ return;
+
+ const SfxHintId nHintId = pSbxHint->GetId();
+ if ( ( nHintId != SfxHintId::BasicStart ) &&
+ ( nHintId != SfxHintId::BasicStop ) )
+ return;
+
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate( SID_BASICRUN );
+ pBindings->Update( SID_BASICRUN );
+ pBindings->Invalidate( SID_BASICCOMPILE );
+ pBindings->Update( SID_BASICCOMPILE );
+ pBindings->Invalidate( SID_BASICSTEPOVER );
+ pBindings->Update( SID_BASICSTEPOVER );
+ pBindings->Invalidate( SID_BASICSTEPINTO );
+ pBindings->Update( SID_BASICSTEPINTO );
+ pBindings->Invalidate( SID_BASICSTEPOUT );
+ pBindings->Update( SID_BASICSTEPOUT );
+ pBindings->Invalidate( SID_BASICSTOP );
+ pBindings->Update( SID_BASICSTOP );
+ pBindings->Invalidate( SID_BASICIDE_TOGGLEBRKPNT );
+ pBindings->Update( SID_BASICIDE_TOGGLEBRKPNT );
+ pBindings->Invalidate( SID_BASICIDE_MANAGEBRKPNTS );
+ pBindings->Update( SID_BASICIDE_MANAGEBRKPNTS );
+ pBindings->Invalidate( SID_BASICIDE_MODULEDLG );
+ pBindings->Update( SID_BASICIDE_MODULEDLG );
+ pBindings->Invalidate( SID_BASICLOAD );
+ pBindings->Update( SID_BASICLOAD );
+ }
+
+ if ( nHintId == SfxHintId::BasicStop )
+ {
+ // not only at error/break or explicit stoppage,
+ // if the update is turned off due to a programming bug
+ BasicStopped();
+ if (pLayout)
+ pLayout->UpdateDebug(true); // clear...
+ if( m_pCurLocalizationMgr )
+ m_pCurLocalizationMgr->handleBasicStopped();
+ }
+ else if( m_pCurLocalizationMgr )
+ {
+ m_pCurLocalizationMgr->handleBasicStarted();
+ }
+
+ for (auto const& window : aWindowTable)
+ {
+ BaseWindow* pWin = window.second;
+ if ( nHintId == SfxHintId::BasicStart )
+ pWin->BasicStarted();
+ else
+ pWin->BasicStopped();
+ }
+}
+
+
+void Shell::CheckWindows()
+{
+ bool bSetCurWindow = false;
+ std::vector<VclPtr<BaseWindow> > aDeleteVec;
+ for (auto const& window : aWindowTable)
+ {
+ BaseWindow* pWin = window.second;
+ if ( pWin->GetStatus() & BASWIN_TOBEKILLED )
+ aDeleteVec.emplace_back(pWin );
+ }
+ for ( VclPtr<BaseWindow> const & pWin : aDeleteVec )
+ {
+ pWin->StoreData();
+ if ( pWin == pCurWin )
+ bSetCurWindow = true;
+ RemoveWindow( pWin, true, false );
+ }
+ if ( bSetCurWindow )
+ SetCurWindow( FindApplicationWindow(), true );
+}
+
+
+void Shell::RemoveWindows( const ScriptDocument& rDocument, std::u16string_view rLibName )
+{
+ bool bChangeCurWindow = pCurWin;
+ std::vector<VclPtr<BaseWindow> > aDeleteVec;
+ for (auto const& window : aWindowTable)
+ {
+ BaseWindow* pWin = window.second;
+ if ( pWin->IsDocument( rDocument ) && pWin->GetLibName() == rLibName )
+ aDeleteVec.emplace_back(pWin );
+ }
+ for ( VclPtr<BaseWindow> const & pWin : aDeleteVec )
+ {
+ if ( pWin == pCurWin )
+ bChangeCurWindow = true;
+ pWin->StoreData();
+ RemoveWindow( pWin, true/*bDestroy*/, false );
+ }
+ if ( bChangeCurWindow )
+ SetCurWindow( FindApplicationWindow(), true );
+}
+
+
+void Shell::UpdateWindows()
+{
+ // remove all windows that may not be displayed
+ bool bChangeCurWindow = pCurWin == nullptr;
+ if ( !m_aCurLibName.isEmpty() )
+ {
+ std::vector<VclPtr<BaseWindow> > aDeleteVec;
+ for (auto const& window : aWindowTable)
+ {
+ BaseWindow* pWin = window.second;
+ if ( !pWin->IsDocument( m_aCurDocument ) || pWin->GetLibName() != m_aCurLibName )
+ {
+ if ( pWin == pCurWin )
+ bChangeCurWindow = true;
+ pWin->StoreData();
+ // The request of RUNNING prevents the crash when in reschedule.
+ // Window is frozen at first, later the windows should be changed
+ // anyway to be marked as hidden instead of being deleted.
+ if ( !(pWin->GetStatus() & ( BASWIN_TOBEKILLED | BASWIN_RUNNINGBASIC | BASWIN_SUSPENDED ) ) )
+ aDeleteVec.emplace_back(pWin );
+ }
+ }
+ for (auto const& elem : aDeleteVec)
+ {
+ RemoveWindow( elem, false, false );
+ }
+ }
+
+ if ( bCreatingWindow )
+ return;
+
+ BaseWindow* pNextActiveWindow = nullptr;
+
+ // show all windows that are to be shown
+ ScriptDocuments aDocuments( ScriptDocument::getAllScriptDocuments( ScriptDocument::AllWithApplication ) );
+ for (auto const& doc : aDocuments)
+ {
+ StartListening(*doc.getBasicManager(), DuplicateHandling::Prevent /* log on only once */);
+
+ // libraries
+ Sequence< OUString > aLibNames( doc.getLibraryNames() );
+ sal_Int32 nLibCount = aLibNames.getLength();
+ const OUString* pLibNames = aLibNames.getConstArray();
+
+ for ( sal_Int32 i = 0 ; i < nLibCount ; i++ )
+ {
+ OUString aLibName = pLibNames[ i ];
+
+ if ( m_aCurLibName.isEmpty() || ( doc == m_aCurDocument && aLibName == m_aCurLibName ) )
+ {
+ // check, if library is password protected and not verified
+ bool bProtected = false;
+ Reference< script::XLibraryContainer > xModLibContainer( doc.getLibraryContainer( E_SCRIPTS ) );
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) )
+ {
+ Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
+ if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) && !xPasswd->isLibraryPasswordVerified( aLibName ) )
+ {
+ bProtected = true;
+ }
+ }
+
+ if ( !bProtected )
+ {
+ LibInfo::Item const* pLibInfoItem = nullptr;
+ if (ExtraData* pData = GetExtraData())
+ pLibInfoItem = pData->GetLibInfo().GetInfo(doc, aLibName);
+
+ // modules
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) )
+ {
+ StarBASIC* pLib = doc.getBasicManager()->GetLib( aLibName );
+ if ( pLib )
+ StartListening(pLib->GetBroadcaster(), DuplicateHandling::Prevent /* log on only once */);
+
+ try
+ {
+ Sequence< OUString > aModNames( doc.getObjectNames( E_SCRIPTS, aLibName ) );
+ sal_Int32 nModCount = aModNames.getLength();
+ const OUString* pModNames = aModNames.getConstArray();
+
+ for ( sal_Int32 j = 0 ; j < nModCount ; j++ )
+ {
+ OUString aModName = pModNames[ j ];
+ VclPtr<ModulWindow> pWin = FindBasWin( doc, aLibName, aModName );
+ if ( !pWin )
+ pWin = CreateBasWin( doc, aLibName, aModName );
+ if ( !pNextActiveWindow && pLibInfoItem && pLibInfoItem->GetCurrentName() == aModName &&
+ pLibInfoItem->GetCurrentType() == TYPE_MODULE )
+ {
+ pNextActiveWindow = pWin;
+ }
+ }
+ }
+ catch (const container::NoSuchElementException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+
+ // dialogs
+ Reference< script::XLibraryContainer > xDlgLibContainer( doc.getLibraryContainer( E_DIALOGS ) );
+ if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) )
+ {
+ try
+ {
+ Sequence< OUString > aDlgNames = doc.getObjectNames( E_DIALOGS, aLibName );
+ sal_Int32 nDlgCount = aDlgNames.getLength();
+ const OUString* pDlgNames = aDlgNames.getConstArray();
+
+ for ( sal_Int32 j = 0 ; j < nDlgCount ; j++ )
+ {
+ OUString aDlgName = pDlgNames[ j ];
+ // this find only looks for non-suspended windows;
+ // suspended windows are handled in CreateDlgWin
+ VclPtr<DialogWindow> pWin = FindDlgWin( doc, aLibName, aDlgName );
+ if ( !pWin )
+ pWin = CreateDlgWin( doc, aLibName, aDlgName );
+ if ( !pNextActiveWindow && pLibInfoItem && pLibInfoItem->GetCurrentName() == aDlgName &&
+ pLibInfoItem->GetCurrentType() == TYPE_DIALOG )
+ {
+ pNextActiveWindow = pWin;
+ }
+ }
+ }
+ catch (const container::NoSuchElementException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( bChangeCurWindow )
+ {
+ if ( !pNextActiveWindow )
+ {
+ pNextActiveWindow = FindApplicationWindow().get();
+ }
+ SetCurWindow( pNextActiveWindow, true );
+ }
+}
+
+void Shell::RemoveWindow( BaseWindow* pWindow_, bool bDestroy, bool bAllowChangeCurWindow )
+{
+ VclPtr<BaseWindow> pWindowTmp( pWindow_ );
+
+ DBG_ASSERT( pWindow_, "Cannot delete NULL-Pointer!" );
+ sal_uInt16 nKey = GetWindowId( pWindow_ );
+ pTabBar->RemovePage( nKey );
+ aWindowTable.erase( nKey );
+ if ( pWindow_ == pCurWin )
+ {
+ if ( bAllowChangeCurWindow )
+ {
+ SetCurWindow( FindApplicationWindow(), true );
+ }
+ else
+ {
+ SetCurWindow( nullptr );
+ }
+ }
+ if ( bDestroy )
+ {
+ if ( !( pWindow_->GetStatus() & BASWIN_INRESCHEDULE ) )
+ {
+ pWindowTmp.disposeAndClear();
+ }
+ else
+ {
+ pWindow_->AddStatus( BASWIN_TOBEKILLED );
+ pWindow_->Hide();
+ // In normal mode stop basic in windows to be deleted
+ // In VBA stop basic only if the running script is trying to delete
+ // its parent module
+ bool bStop = true;
+ if ( pWindow_->GetDocument().isInVBAMode() )
+ {
+ SbModule* pMod = StarBASIC::GetActiveModule();
+ if ( !pMod || pMod->GetName() != pWindow_->GetName() )
+ {
+ bStop = false;
+ }
+ }
+ if ( bStop )
+ {
+ StarBASIC::Stop();
+ // there will be no notify...
+ pWindow_->BasicStopped();
+ }
+ aWindowTable[ nKey ] = pWindow_; // jump in again
+ }
+ }
+ else
+ {
+ pWindow_->AddStatus( BASWIN_SUSPENDED );
+ pWindow_->Deactivating();
+ aWindowTable[ nKey ] = pWindow_; // jump in again
+ }
+
+}
+
+
+sal_uInt16 Shell::InsertWindowInTable( BaseWindow* pNewWin )
+{
+ nCurKey++;
+ aWindowTable[ nCurKey ] = pNewWin;
+ return nCurKey;
+}
+
+
+void Shell::InvalidateBasicIDESlots()
+{
+ // only those that have an optic effect...
+
+ if (!GetShell())
+ return;
+
+ SfxBindings* pBindings = GetBindingsPtr();
+ if (!pBindings)
+ return;
+
+ pBindings->Invalidate( SID_COPY );
+ pBindings->Invalidate( SID_CUT );
+ pBindings->Invalidate( SID_PASTE );
+ pBindings->Invalidate( SID_UNDO );
+ pBindings->Invalidate( SID_REDO );
+ pBindings->Invalidate( SID_SAVEDOC );
+ pBindings->Invalidate( SID_SIGNATURE );
+ pBindings->Invalidate( SID_BASICIDE_CHOOSEMACRO );
+ pBindings->Invalidate( SID_BASICIDE_MODULEDLG );
+ pBindings->Invalidate( SID_BASICIDE_OBJCAT );
+ pBindings->Invalidate( SID_BASICSTOP );
+ pBindings->Invalidate( SID_BASICRUN );
+ pBindings->Invalidate( SID_BASICCOMPILE );
+ pBindings->Invalidate( SID_BASICLOAD );
+ pBindings->Invalidate( SID_BASICSAVEAS );
+ pBindings->Invalidate( SID_BASICIDE_MATCHGROUP );
+ pBindings->Invalidate( SID_BASICSTEPINTO );
+ pBindings->Invalidate( SID_BASICSTEPOVER );
+ pBindings->Invalidate( SID_BASICSTEPOUT );
+ pBindings->Invalidate( SID_BASICIDE_TOGGLEBRKPNT );
+ pBindings->Invalidate( SID_BASICIDE_MANAGEBRKPNTS );
+ pBindings->Invalidate( SID_BASICIDE_ADDWATCH );
+ pBindings->Invalidate( SID_BASICIDE_REMOVEWATCH );
+
+ pBindings->Invalidate( SID_PRINTDOC );
+ pBindings->Invalidate( SID_PRINTDOCDIRECT );
+ pBindings->Invalidate( SID_SETUPPRINTER );
+ pBindings->Invalidate( SID_DIALOG_TESTMODE );
+
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+ pBindings->Invalidate( SID_BASICIDE_STAT_TITLE );
+ pBindings->Invalidate( SID_BASICIDE_STAT_POS );
+ pBindings->Invalidate( SID_ATTR_INSERT );
+ pBindings->Invalidate( SID_ATTR_SIZE );
+}
+
+void Shell::InvalidateControlSlots()
+{
+ if (!GetShell())
+ return;
+
+ SfxBindings* pBindings = GetBindingsPtr();
+ if (!pBindings)
+ return;
+
+ pBindings->Invalidate( SID_INSERT_FORM_RADIO );
+ pBindings->Invalidate( SID_INSERT_FORM_CHECK );
+ pBindings->Invalidate( SID_INSERT_FORM_LIST );
+ pBindings->Invalidate( SID_INSERT_FORM_COMBO );
+ pBindings->Invalidate( SID_INSERT_FORM_VSCROLL );
+ pBindings->Invalidate( SID_INSERT_FORM_HSCROLL );
+ pBindings->Invalidate( SID_INSERT_FORM_SPIN );
+
+ pBindings->Invalidate( SID_INSERT_SELECT );
+ pBindings->Invalidate( SID_INSERT_PUSHBUTTON );
+ pBindings->Invalidate( SID_INSERT_RADIOBUTTON );
+ pBindings->Invalidate( SID_INSERT_CHECKBOX );
+ pBindings->Invalidate( SID_INSERT_LISTBOX );
+ pBindings->Invalidate( SID_INSERT_COMBOBOX );
+ pBindings->Invalidate( SID_INSERT_GROUPBOX );
+ pBindings->Invalidate( SID_INSERT_EDIT );
+ pBindings->Invalidate( SID_INSERT_FIXEDTEXT );
+ pBindings->Invalidate( SID_INSERT_IMAGECONTROL );
+ pBindings->Invalidate( SID_INSERT_PROGRESSBAR );
+ pBindings->Invalidate( SID_INSERT_HSCROLLBAR );
+ pBindings->Invalidate( SID_INSERT_VSCROLLBAR );
+ pBindings->Invalidate( SID_INSERT_HFIXEDLINE );
+ pBindings->Invalidate( SID_INSERT_VFIXEDLINE );
+ pBindings->Invalidate( SID_INSERT_DATEFIELD );
+ pBindings->Invalidate( SID_INSERT_TIMEFIELD );
+ pBindings->Invalidate( SID_INSERT_NUMERICFIELD );
+ pBindings->Invalidate( SID_INSERT_CURRENCYFIELD );
+ pBindings->Invalidate( SID_INSERT_FORMATTEDFIELD );
+ pBindings->Invalidate( SID_INSERT_PATTERNFIELD );
+ pBindings->Invalidate( SID_INSERT_FILECONTROL );
+ pBindings->Invalidate( SID_INSERT_SPINBUTTON );
+ pBindings->Invalidate( SID_INSERT_GRIDCONTROL );
+ pBindings->Invalidate( SID_INSERT_HYPERLINKCONTROL );
+ pBindings->Invalidate( SID_INSERT_TREECONTROL );
+ pBindings->Invalidate( SID_CHOOSE_CONTROLS );
+}
+
+void Shell::EnableScrollbars( bool bEnable )
+{
+ aHScrollBar->Enable(bEnable);
+ aVScrollBar->Enable(bEnable);
+}
+
+void Shell::SetCurLib( const ScriptDocument& rDocument, const OUString& aLibName, bool bUpdateWindows, bool bCheck )
+{
+ if ( bCheck && rDocument == m_aCurDocument && aLibName == m_aCurLibName )
+ return;
+
+ ContainerListenerImpl* pListener = static_cast< ContainerListenerImpl* >( m_xLibListener.get() );
+
+ if (pListener)
+ pListener->removeContainerListener(m_aCurDocument, m_aCurLibName);
+
+ m_aCurDocument = rDocument;
+ m_aCurLibName = aLibName;
+
+ if ( pListener )
+ pListener->addContainerListener( m_aCurDocument, aLibName );
+
+ if ( bUpdateWindows )
+ UpdateWindows();
+
+ SetMDITitle();
+
+ SetCurLibForLocalization( rDocument, aLibName );
+
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate( SID_BASICIDE_LIBSELECTOR );
+ pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG );
+ pBindings->Invalidate( SID_BASICIDE_MANAGE_LANG );
+ }
+}
+
+void Shell::SetCurLibForLocalization( const ScriptDocument& rDocument, const OUString& aLibName )
+{
+ // Create LocalizationMgr
+ Reference< resource::XStringResourceManager > xStringResourceManager;
+ try
+ {
+ if( !aLibName.isEmpty() )
+ {
+ Reference< container::XNameContainer > xDialogLib( rDocument.getLibrary( E_DIALOGS, aLibName, true ) );
+ xStringResourceManager = LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib );
+ }
+ }
+ catch (const container::NoSuchElementException& )
+ {}
+
+ m_pCurLocalizationMgr = std::make_shared<LocalizationMgr>(this, rDocument, aLibName, xStringResourceManager);
+ m_pCurLocalizationMgr->handleTranslationbar();
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/basobj2.cxx b/basctl/source/basicide/basobj2.cxx
new file mode 100644
index 000000000..8a656bf08
--- /dev/null
+++ b/basctl/source/basicide/basobj2.cxx
@@ -0,0 +1,440 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <basidesh.hxx>
+#include <iderdll.hxx>
+#include "iderdll2.hxx"
+#include "macrodlg.hxx"
+#include "moduldlg.hxx"
+#include <iderid.hxx>
+#include <strings.hrc>
+#include "baside2.hxx"
+
+#include <com/sun/star/document/XScriptInvocationContext.hpp>
+
+#include <basic/sbmeth.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/sequence.hxx>
+#include <framework/documentundoguard.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <unotools/moduleoptions.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <memory>
+#include <vector>
+#include <algorithm>
+#include <basic/basmgr.hxx>
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+
+extern "C" {
+ SAL_DLLPUBLIC_EXPORT rtl_uString* basicide_choose_macro(void* pParent, void* pOnlyInDocument_AsXModel, void* pDocFrame_AsXFrame, sal_Bool bChooseOnly )
+ {
+ Reference< frame::XModel > aDocument( static_cast< frame::XModel* >( pOnlyInDocument_AsXModel ) );
+ Reference< frame::XFrame > aDocFrame( static_cast< frame::XFrame* >( pDocFrame_AsXFrame ) );
+ OUString aScriptURL = basctl::ChooseMacro(static_cast<weld::Window*>(pParent), aDocument, aDocFrame, bChooseOnly);
+ rtl_uString* pScriptURL = aScriptURL.pData;
+ rtl_uString_acquire( pScriptURL );
+
+ return pScriptURL;
+ }
+ SAL_DLLPUBLIC_EXPORT void basicide_macro_organizer(void *pParent, sal_Int16 nTabId)
+ {
+ SAL_INFO("basctl.basicide","in basicide_macro_organizer");
+ basctl::Organize(static_cast<weld::Window*>(pParent), nTabId);
+ }
+}
+
+void Organize(weld::Window* pParent, sal_Int16 tabId)
+{
+ EnsureIde();
+
+ auto xDlg(std::make_shared<OrganizeDialog>(pParent, tabId));
+ weld::DialogController::runAsync(xDlg, [](int) {});
+}
+
+bool IsValidSbxName( const OUString& rName )
+{
+ for ( sal_Int32 nChar = 0; nChar < rName.getLength(); nChar++ )
+ {
+ sal_Unicode c = rName[nChar];
+ bool bValid = (
+ ( c >= 'A' && c <= 'Z' ) ||
+ ( c >= 'a' && c <= 'z' ) ||
+ ( c >= '0' && c <= '9' && nChar ) ||
+ ( c == '_' )
+ );
+ if ( !bValid )
+ return false;
+ }
+ return true;
+}
+
+Sequence< OUString > GetMergedLibraryNames( const Reference< script::XLibraryContainer >& xModLibContainer, const Reference< script::XLibraryContainer >& xDlgLibContainer )
+{
+ // create a list of module library names
+ std::vector<OUString> aLibList;
+ if ( xModLibContainer.is() )
+ {
+ const Sequence< OUString > aModLibNames = xModLibContainer->getElementNames();
+ aLibList.insert( aLibList.end(), aModLibNames.begin(), aModLibNames.end() );
+ }
+
+ // create a list of dialog library names
+ if ( xDlgLibContainer.is() )
+ {
+ const Sequence< OUString > aDlgLibNames = xDlgLibContainer->getElementNames();
+ aLibList.insert( aLibList.end(), aDlgLibNames.begin(), aDlgLibNames.end() );
+ }
+
+ // sort list
+ auto const sort = comphelper::string::NaturalStringSorter(
+ comphelper::getProcessComponentContext(),
+ Application::GetSettings().GetUILanguageTag().getLocale());
+ std::sort(aLibList.begin(), aLibList.end(),
+ [&sort](const OUString& rLHS, const OUString& rRHS) {
+ return sort.compare(rLHS, rRHS) < 0;
+ });
+ // remove duplicates
+ std::vector<OUString>::iterator aIterEnd = std::unique( aLibList.begin(), aLibList.end() );
+ aLibList.erase( aIterEnd, aLibList.end() );
+
+ return comphelper::containerToSequence(aLibList);
+}
+
+bool RenameModule (
+ weld::Widget* pErrorParent,
+ const ScriptDocument& rDocument,
+ const OUString& rLibName,
+ const OUString& rOldName,
+ const OUString& rNewName
+)
+{
+ if ( !rDocument.hasModule( rLibName, rOldName ) )
+ {
+ SAL_WARN( "basctl.basicide","basctl::RenameModule: old module name is invalid!" );
+ return false;
+ }
+
+ if ( rDocument.hasModule( rLibName, rNewName ) )
+ {
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pErrorParent,
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED2)));
+ xError->run();
+ return false;
+ }
+
+ // #i74440
+ if ( rNewName.isEmpty() )
+ {
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pErrorParent,
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
+ xError->run();
+ return false;
+ }
+
+ if ( !rDocument.renameModule( rLibName, rOldName, rNewName ) )
+ return false;
+
+ Shell* pShell = GetShell();
+ if (!pShell)
+ return true;
+ VclPtr<ModulWindow> pWin = pShell->FindBasWin(rDocument, rLibName, rNewName, false, true);
+ if (!pWin)
+ return true;
+
+ // set new name in window
+ pWin->SetName( rNewName );
+
+ // set new module in module window
+ pWin->SetSbModule( pWin->GetBasic()->FindModule( rNewName ) );
+
+ // update tabwriter
+ sal_uInt16 nId = pShell->GetWindowId( pWin );
+ SAL_WARN_IF( nId == 0 , "basctl.basicide", "No entry in Tabbar!");
+ if ( nId )
+ {
+ TabBar& rTabBar = pShell->GetTabBar();
+ rTabBar.SetPageText(nId, rNewName);
+ rTabBar.Sort();
+ rTabBar.MakeVisible(rTabBar.GetCurPageId());
+ }
+ return true;
+}
+
+namespace
+{
+ struct MacroExecutionData
+ {
+ ScriptDocument aDocument;
+ SbMethodRef xMethod;
+
+ MacroExecutionData()
+ :aDocument( ScriptDocument::NoDocument )
+ {
+ }
+ };
+
+ class MacroExecution
+ {
+ public:
+ DECL_STATIC_LINK( MacroExecution, ExecuteMacroEvent, void*, void );
+ };
+
+ IMPL_STATIC_LINK( MacroExecution, ExecuteMacroEvent, void*, p, void )
+ {
+ MacroExecutionData* i_pData = static_cast<MacroExecutionData*>(p);
+ ENSURE_OR_RETURN_VOID( i_pData, "wrong MacroExecutionData" );
+ // take ownership of the data
+ std::unique_ptr< MacroExecutionData > pData( i_pData );
+
+ SAL_WARN_IF( (pData->xMethod->GetParent()->GetFlags() & SbxFlagBits::ExtSearch) == SbxFlagBits::NONE, "basctl.basicide","No EXTSEARCH!" );
+
+ // in case this is a document-local macro, try to protect the document's Undo Manager from
+ // flawed scripts
+ std::optional< ::framework::DocumentUndoGuard > pUndoGuard;
+ if ( pData->aDocument.isDocument() )
+ pUndoGuard.emplace( pData->aDocument.getDocument() );
+
+ RunMethod( pData->xMethod.get() );
+ }
+}
+
+OUString ChooseMacro(weld::Window* pParent,
+ const uno::Reference< frame::XModel >& rxLimitToDocument,
+ const uno::Reference< frame::XFrame >& xDocFrame,
+ bool bChooseOnly)
+{
+ EnsureIde();
+
+ GetExtraData()->ChoosingMacro() = true;
+
+ OUString aScriptURL;
+ SbMethod* pMethod = nullptr;
+
+ MacroChooser aChooser(pParent, xDocFrame);
+ if ( bChooseOnly || !SvtModuleOptions::IsBasicIDE() )
+ aChooser.SetMode(MacroChooser::ChooseOnly);
+
+ if ( !bChooseOnly && rxLimitToDocument.is() )
+ {
+ // Hack!
+ aChooser.SetMode(MacroChooser::Recording);
+ }
+
+ short nRetValue = aChooser.run();
+
+ GetExtraData()->ChoosingMacro() = false;
+
+ switch ( nRetValue )
+ {
+ case Macro_OkRun:
+ {
+ bool bError = false;
+
+ pMethod = aChooser.GetMacro();
+ if ( !pMethod && aChooser.GetMode() == MacroChooser::Recording )
+ pMethod = aChooser.CreateMacro();
+
+ if ( !pMethod )
+ break;
+
+ SbModule* pModule = pMethod->GetModule();
+ if ( !pModule )
+ {
+ SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Module found!" );
+ break;
+ }
+
+ StarBASIC* pBasic = dynamic_cast<StarBASIC*>(pModule->GetParent());
+ if ( !pBasic )
+ {
+ SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Basic found!" );
+ break;
+ }
+
+ BasicManager* pBasMgr = FindBasicManager( pBasic );
+ if ( !pBasMgr )
+ {
+ SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No BasicManager found!" );
+ break;
+ }
+
+ // name
+ OUString aName = pBasic->GetName() + "." + pModule->GetName() + "." + pMethod->GetName();
+
+ // location
+ OUString aLocation;
+ ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
+ if ( aDocument.isDocument() )
+ {
+ // document basic
+ aLocation = "document" ;
+
+ if ( rxLimitToDocument.is() )
+ {
+ uno::Reference< frame::XModel > xLimitToDocument( rxLimitToDocument );
+
+ uno::Reference< document::XEmbeddedScripts > xScripts( rxLimitToDocument, UNO_QUERY );
+ if ( !xScripts.is() )
+ { // the document itself does not support embedding scripts
+ uno::Reference< document::XScriptInvocationContext > xContext( rxLimitToDocument, UNO_QUERY );
+ if ( xContext.is() )
+ xScripts = xContext->getScriptContainer();
+ if ( xScripts.is() )
+ { // but it is able to refer to a document which actually does support this
+ xLimitToDocument.set( xScripts, UNO_QUERY );
+ if ( !xLimitToDocument.is() )
+ {
+ SAL_WARN_IF(!xLimitToDocument.is(), "basctl.basicide", "basctl::ChooseMacro: a script container which is no document!?" );
+ xLimitToDocument = rxLimitToDocument;
+ }
+ }
+ }
+
+ if ( xLimitToDocument != aDocument.getDocument() )
+ {
+ // error
+ bError = true;
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_ERRORCHOOSEMACRO)));
+ xError->run();
+ }
+ }
+ }
+ else
+ {
+ // application basic
+ aLocation = "application" ;
+ }
+
+ // script URL
+ if ( !bError )
+ {
+ aScriptURL = "vnd.sun.star.script:" + aName + "?language=Basic&location=" + aLocation;
+ }
+
+ if ( !rxLimitToDocument.is() )
+ {
+ MacroExecutionData* pExecData = new MacroExecutionData;
+ pExecData->aDocument = aDocument;
+ pExecData->xMethod = pMethod; // keep alive until the event has been processed
+ Application::PostUserEvent( LINK( nullptr, MacroExecution, ExecuteMacroEvent ), pExecData );
+ }
+ }
+ break;
+ }
+
+ return aScriptURL;
+}
+
+Sequence< OUString > GetMethodNames( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName )
+{
+ Sequence< OUString > aSeqMethods;
+
+ // get module
+ OUString aOUSource;
+ if ( rDocument.getModule( rLibName, rModName, aOUSource ) )
+ {
+ BasicManager* pBasMgr = rDocument.getBasicManager();
+ StarBASIC* pSb = pBasMgr ? pBasMgr->GetLib( rLibName ) : nullptr;
+ SbModule* pMod = pSb ? pSb->FindModule( rModName ) : nullptr;
+
+ SbModuleRef xModule;
+ // Only reparse modules if ScriptDocument source is out of sync
+ // with basic's Module
+ if ( !pMod || pMod->GetSource32() != aOUSource )
+ {
+ xModule = new SbModule( rModName );
+ xModule->SetSource32( aOUSource );
+ pMod = xModule.get();
+ }
+
+ sal_uInt32 nCount = pMod->GetMethods()->Count();
+ sal_uInt32 nRealCount = nCount;
+ for ( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ SbMethod* pMethod = static_cast<SbMethod*>(pMod->GetMethods()->Get(i));
+ if( pMethod->IsHidden() )
+ --nRealCount;
+ }
+ aSeqMethods.realloc( nRealCount );
+
+ sal_uInt32 iTarget = 0;
+ for ( sal_uInt32 i = 0 ; i < nCount; ++i )
+ {
+ SbMethod* pMethod = static_cast<SbMethod*>(pMod->GetMethods()->Get(i));
+ if( pMethod->IsHidden() )
+ continue;
+ SAL_WARN_IF( !pMethod, "basctl.basicide","Method not found! (NULL)" );
+ aSeqMethods.getArray()[ iTarget++ ] = pMethod->GetName();
+ }
+ }
+
+ return aSeqMethods;
+}
+
+bool HasMethod (
+ ScriptDocument const& rDocument,
+ OUString const& rLibName,
+ OUString const& rModName,
+ OUString const& rMethName
+)
+{
+ bool bHasMethod = false;
+
+ OUString aOUSource;
+ if ( rDocument.hasModule( rLibName, rModName ) && rDocument.getModule( rLibName, rModName, aOUSource ) )
+ {
+ // Check if we really need to scan the source ( again )
+ BasicManager* pBasMgr = rDocument.getBasicManager();
+ StarBASIC* pSb = pBasMgr ? pBasMgr->GetLib( rLibName ) : nullptr;
+ SbModule* pMod = pSb ? pSb->FindModule( rModName ) : nullptr;
+ SbModuleRef xModule;
+ // Only reparse modules if ScriptDocument source is out of sync
+ // with basic's Module
+ if ( !pMod || pMod->GetSource32() != aOUSource )
+ {
+ xModule = new SbModule( rModName );
+ xModule->SetSource32( aOUSource );
+ pMod = xModule.get();
+ }
+ SbxArray* pMethods = pMod->GetMethods().get();
+ if ( pMethods )
+ {
+ SbMethod* pMethod = static_cast<SbMethod*>(pMethods->Find( rMethName, SbxClassType::Method ));
+ if ( pMethod && !pMethod->IsHidden() )
+ bHasMethod = true;
+ }
+ }
+
+ return bHasMethod;
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/basobj3.cxx b/basctl/source/basicide/basobj3.cxx
new file mode 100644
index 000000000..26de81e35
--- /dev/null
+++ b/basctl/source/basicide/basobj3.cxx
@@ -0,0 +1,466 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/errinf.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <basic/basmgr.hxx>
+#include <basic/sbmeth.hxx>
+#include <unotools/moduleoptions.hxx>
+
+#include <iderdll.hxx>
+#include "iderdll2.hxx"
+#include "basdoc.hxx"
+#include <iderid.hxx>
+#include <strings.hrc>
+
+#include <baside3.hxx>
+#include <basidesh.hxx>
+#include <basobj.hxx>
+#include <localizationmgr.hxx>
+#include <dlged.hxx>
+#include <com/sun/star/script/XLibraryContainerPassword.hpp>
+#include <sfx2/app.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <tools/debug.hxx>
+
+namespace basctl
+{
+
+using namespace comphelper;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+
+extern "C" {
+ SAL_DLLPUBLIC_EXPORT tools::Long basicide_handle_basic_error( void const * pPtr )
+ {
+ return HandleBasicError( static_cast<StarBASIC const *>(pPtr) );
+ }
+}
+
+SbMethod* CreateMacro( SbModule* pModule, const OUString& rMacroName )
+{
+ SfxDispatcher* pDispatcher = GetDispatcher();
+ if( pDispatcher )
+ {
+ pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES );
+ }
+
+ if ( pModule->FindMethod( rMacroName, SbxClassType::Method ) )
+ return nullptr;
+
+ OUString aMacroName( rMacroName );
+ if ( aMacroName.isEmpty() )
+ {
+ if (!pModule->GetMethods()->Count())
+ aMacroName = "Main" ;
+ else
+ {
+ bool bValid = false;
+ sal_Int32 nMacro = 1;
+ while ( !bValid )
+ {
+ aMacroName = "Macro" + OUString::number( nMacro );
+ // test whether existing...
+ bValid = pModule->FindMethod( aMacroName, SbxClassType::Method ) == nullptr;
+ nMacro++;
+ }
+ }
+ }
+
+ OUString aOUSource( pModule->GetSource32() );
+
+ // don't produce too many empty lines...
+ sal_Int32 nSourceLen = aOUSource.getLength();
+ if ( nSourceLen > 2 )
+ {
+ const sal_Unicode* pStr = aOUSource.getStr();
+ if ( pStr[ nSourceLen - 1 ] != LINE_SEP )
+ aOUSource += "\n\n" ;
+ else if ( pStr[ nSourceLen - 2 ] != LINE_SEP )
+ aOUSource += "\n" ;
+ else if ( pStr[ nSourceLen - 3 ] == LINE_SEP )
+ aOUSource = aOUSource.copy( 0, nSourceLen-1 );
+ }
+
+ OUString aSubStr = "Sub " + aMacroName + "\n\nEnd Sub";
+
+ aOUSource += aSubStr;
+
+ // update module in library
+ StarBASIC* pBasic = dynamic_cast<StarBASIC*>(pModule->GetParent());
+ BasicManager* pBasMgr = pBasic ? FindBasicManager(pBasic) : nullptr;
+ SAL_WARN_IF(!pBasMgr, "basctl.basicide", "No BasicManager found!");
+ ScriptDocument aDocument = pBasMgr
+ ? ScriptDocument::getDocumentForBasicManager(pBasMgr)
+ : ScriptDocument(ScriptDocument::NoDocument);
+
+ if (aDocument.isValid())
+ {
+ const OUString& aLibName = pBasic->GetName();
+ const OUString& aModName = pModule->GetName();
+ OSL_VERIFY( aDocument.updateModule( aLibName, aModName, aOUSource ) );
+ }
+
+ SbMethod* pMethod = pModule->FindMethod( aMacroName, SbxClassType::Method );
+
+ if( pDispatcher )
+ {
+ pDispatcher->Execute( SID_BASICIDE_UPDATEALLMODULESOURCES );
+ }
+
+ if (aDocument.isAlive())
+ MarkDocumentModified(aDocument);
+
+ return pMethod;
+}
+
+bool RenameDialog (
+ weld::Widget* pErrorParent,
+ ScriptDocument const& rDocument,
+ OUString const& rLibName,
+ OUString const& rOldName,
+ OUString const& rNewName
+)
+{
+ if ( !rDocument.hasDialog( rLibName, rOldName ) )
+ {
+ OSL_FAIL( "basctl::RenameDialog: old module name is invalid!" );
+ return false;
+ }
+
+ if ( rDocument.hasDialog( rLibName, rNewName ) )
+ {
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pErrorParent,
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED2)));
+ xError->run();
+ return false;
+ }
+
+ // #i74440
+ if ( rNewName.isEmpty() )
+ {
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pErrorParent,
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
+ xError->run();
+ return false;
+ }
+
+ Shell* pShell = GetShell();
+ VclPtr<DialogWindow> pWin = pShell ? pShell->FindDlgWin(rDocument, rLibName, rOldName) : nullptr;
+ Reference< XNameContainer > xExistingDialog;
+ if ( pWin )
+ xExistingDialog = pWin->GetEditor().GetDialog();
+
+ if ( xExistingDialog.is() )
+ LocalizationMgr::renameStringResourceIDs( rDocument, rLibName, rNewName, xExistingDialog );
+
+ if ( !rDocument.renameDialog( rLibName, rOldName, rNewName, xExistingDialog ) )
+ return false;
+
+ if (!pWin || !pShell)
+ return true;
+
+ // set new name in window
+ pWin->SetName( rNewName );
+
+ // update property browser
+ pWin->UpdateBrowser();
+
+ // update tabwriter
+ sal_uInt16 nId = pShell->GetWindowId( pWin );
+ DBG_ASSERT( nId, "No entry in Tabbar!" );
+ if ( nId )
+ {
+ TabBar& rTabBar = pShell->GetTabBar();
+ rTabBar.SetPageText( nId, rNewName );
+ rTabBar.Sort();
+ rTabBar.MakeVisible( rTabBar.GetCurPageId() );
+ }
+ return true;
+}
+
+bool RemoveDialog( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rDlgName )
+{
+ if (Shell* pShell = GetShell())
+ {
+ if (VclPtr<DialogWindow> pDlgWin = pShell->FindDlgWin(rDocument, rLibName, rDlgName))
+ {
+ Reference< container::XNameContainer > xDialogModel = pDlgWin->GetDialog();
+ LocalizationMgr::removeResourceForDialog( rDocument, rLibName, rDlgName, xDialogModel );
+ }
+ }
+
+ return rDocument.removeDialog( rLibName, rDlgName );
+}
+
+StarBASIC* FindBasic( const SbxVariable* pVar )
+{
+ SbxVariable const* pSbx = pVar;
+ while (pSbx && !dynamic_cast<StarBASIC const*>(pSbx))
+ pSbx = pSbx->GetParent();
+ return const_cast<StarBASIC*>(static_cast<const StarBASIC*>(pSbx));
+}
+
+BasicManager* FindBasicManager( StarBASIC const * pLib )
+{
+ ScriptDocuments aDocuments( ScriptDocument::getAllScriptDocuments( ScriptDocument::AllWithApplication ) );
+ for (auto const& doc : aDocuments)
+ {
+ BasicManager* pBasicMgr = doc.getBasicManager();
+ OSL_ENSURE( pBasicMgr, "basctl::FindBasicManager: no basic manager for the document!" );
+ if ( !pBasicMgr )
+ continue;
+
+ Sequence< OUString > aLibNames( doc.getLibraryNames() );
+ sal_Int32 nLibCount = aLibNames.getLength();
+ const OUString* pLibNames = aLibNames.getConstArray();
+
+ for ( sal_Int32 i = 0 ; i < nLibCount ; i++ )
+ {
+ StarBASIC* pL = pBasicMgr->GetLib( pLibNames[ i ] );
+ if ( pL == pLib )
+ return pBasicMgr;
+ }
+ }
+ return nullptr;
+}
+
+void MarkDocumentModified( const ScriptDocument& rDocument )
+{
+ Shell* pShell = GetShell();
+
+ // does not have to come from a document...
+ if ( rDocument.isApplication() )
+ {
+ if (pShell)
+ pShell->SetAppBasicModified(true);
+ }
+ else
+ {
+ rDocument.setDocumentModified();
+ }
+
+ // tdf#130161 in all cases call UpdateObjectCatalog
+ if (pShell)
+ pShell->UpdateObjectCatalog();
+
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate( SID_SIGNATURE );
+ pBindings->Invalidate( SID_SAVEDOC );
+ pBindings->Update( SID_SAVEDOC );
+ }
+}
+
+void RunMethod( SbMethod const * pMethod )
+{
+ SbxValues aRes;
+ aRes.eType = SbxVOID;
+ pMethod->Get( aRes );
+}
+
+void StopBasic()
+{
+ StarBASIC::Stop();
+ if (Shell* pShell = GetShell())
+ {
+ Shell::WindowTable& rWindows = pShell->GetWindowTable();
+ for (auto const& window : rWindows)
+ {
+ BaseWindow* pWin = window.second;
+ // call BasicStopped manually because the Stop-Notify
+ // might not get through otherwise
+ pWin->BasicStopped();
+ }
+ }
+ BasicStopped();
+}
+
+void BasicStopped(
+ bool* pbAppWindowDisabled,
+ bool* pbDispatcherLocked,
+ sal_uInt16* pnWaitCount,
+ SfxUInt16Item** ppSWActionCount, SfxUInt16Item** ppSWLockViewCount
+)
+{
+ // maybe there are some locks to be removed after an error
+ // or an explicit cancelling of the basic...
+ if ( pbAppWindowDisabled )
+ *pbAppWindowDisabled = false;
+ if ( pbDispatcherLocked )
+ *pbDispatcherLocked = false;
+ if ( pnWaitCount )
+ *pnWaitCount = 0;
+ if ( ppSWActionCount )
+ *ppSWActionCount = nullptr;
+ if ( ppSWLockViewCount )
+ *ppSWLockViewCount = nullptr;
+
+ // AppWait?
+ if (Shell* pShell = GetShell())
+ {
+ sal_uInt16 nWait = 0;
+ while ( pShell->GetViewFrame()->GetWindow().IsWait() )
+ {
+ pShell->GetViewFrame()->GetWindow().LeaveWait();
+ nWait++;
+ }
+ if ( pnWaitCount )
+ *pnWaitCount = nWait;
+ }
+
+ weld::Window* pDefParent = Application::GetDefDialogParent();
+ if (pDefParent && !pDefParent->get_sensitive())
+ {
+ pDefParent->set_sensitive(true);
+ if ( pbAppWindowDisabled )
+ *pbAppWindowDisabled = true;
+ }
+
+}
+
+void InvalidateDebuggerSlots()
+{
+ SfxBindings* pBindings = GetBindingsPtr();
+ if (!pBindings)
+ return;
+
+ pBindings->Invalidate( SID_BASICSTOP );
+ pBindings->Update( SID_BASICSTOP );
+ pBindings->Invalidate( SID_BASICRUN );
+ pBindings->Update( SID_BASICRUN );
+ pBindings->Invalidate( SID_BASICCOMPILE );
+ pBindings->Update( SID_BASICCOMPILE );
+ pBindings->Invalidate( SID_BASICSTEPOVER );
+ pBindings->Update( SID_BASICSTEPOVER );
+ pBindings->Invalidate( SID_BASICSTEPINTO );
+ pBindings->Update( SID_BASICSTEPINTO );
+ pBindings->Invalidate( SID_BASICSTEPOUT );
+ pBindings->Update( SID_BASICSTEPOUT );
+ pBindings->Invalidate( SID_BASICIDE_TOGGLEBRKPNT );
+ pBindings->Update( SID_BASICIDE_TOGGLEBRKPNT );
+ pBindings->Invalidate( SID_BASICIDE_STAT_POS );
+ pBindings->Update( SID_BASICIDE_STAT_POS );
+ pBindings->Invalidate( SID_BASICIDE_STAT_TITLE );
+ pBindings->Update( SID_BASICIDE_STAT_TITLE );
+}
+
+tools::Long HandleBasicError( StarBASIC const * pBasic )
+{
+ EnsureIde();
+ BasicStopped();
+
+ // no error output during macro choosing
+ if (GetExtraData()->ChoosingMacro())
+ return 1;
+ if (GetExtraData()->ShellInCriticalSection())
+ return 2;
+
+ tools::Long nRet = 0;
+ Shell* pShell = nullptr;
+ if ( SvtModuleOptions::IsBasicIDE() )
+ {
+ BasicManager* pBasMgr = FindBasicManager( pBasic );
+ if ( pBasMgr )
+ {
+ bool bProtected = false;
+ ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
+ OSL_ENSURE( aDocument.isValid(), "basctl::HandleBasicError: no document for the given BasicManager!" );
+ if ( aDocument.isValid() )
+ {
+ const OUString& aOULibName( pBasic->GetName() );
+ Reference< script::XLibraryContainer > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) );
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) )
+ {
+ Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
+ if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aOULibName ) && !xPasswd->isLibraryPasswordVerified( aOULibName ) )
+ {
+ bProtected = true;
+ }
+ }
+ }
+
+ if ( !bProtected )
+ {
+ pShell = GetShell();
+ if ( !pShell )
+ {
+ SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
+ SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs );
+ SfxGetpApp()->ExecuteSlot( aRequest );
+ pShell = GetShell();
+ }
+ }
+ }
+ }
+
+ if ( pShell )
+ nRet = tools::Long(pShell->CallBasicErrorHdl( pBasic ));
+ else
+ ErrorHandler::HandleError( StarBASIC::GetErrorCode() );
+
+ return nRet;
+}
+
+SfxBindings* GetBindingsPtr()
+{
+ SfxBindings* pBindings = nullptr;
+
+ SfxViewFrame* pFrame = nullptr;
+ if (Shell* pShell = GetShell())
+ {
+ pFrame = pShell->GetViewFrame();
+ }
+ else
+ {
+ SfxViewFrame* pView = SfxViewFrame::GetFirst();
+ while ( pView )
+ {
+ if (dynamic_cast<DocShell*>(pView->GetObjectShell()))
+ {
+ pFrame = pView;
+ break;
+ }
+ pView = SfxViewFrame::GetNext( *pView );
+ }
+ }
+ if ( pFrame != nullptr )
+ pBindings = &pFrame->GetBindings();
+
+ return pBindings;
+}
+
+SfxDispatcher* GetDispatcher ()
+{
+ if (Shell* pShell = GetShell())
+ if (SfxViewFrame* pViewFrame = pShell->GetViewFrame())
+ if (SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher())
+ return pDispatcher;
+ return nullptr;
+}
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/bastype2.cxx b/basctl/source/basicide/bastype2.cxx
new file mode 100644
index 000000000..6f6eaa26d
--- /dev/null
+++ b/basctl/source/basicide/bastype2.cxx
@@ -0,0 +1,864 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <basobj.hxx>
+#include <bastypes.hxx>
+#include <bastype2.hxx>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <iderid.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/diagnose_ex.h>
+#include <svtools/imagemgr.hxx>
+#include <com/sun/star/script/XLibraryContainerPassword.hpp>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <comphelper/processfactory.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/sfxsids.hrc>
+
+#include <initializer_list>
+#include <memory>
+#include <string_view>
+
+#include <com/sun/star/script/ModuleType.hpp>
+#include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <utility>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star;
+
+void ModuleInfoHelper::getObjectName( const uno::Reference< container::XNameContainer >& rLib, const OUString& rModName, OUString& rObjName )
+{
+ try
+ {
+ uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( rLib, uno::UNO_QUERY );
+ if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo( rModName ) )
+ {
+ script::ModuleInfo aModuleInfo = xVBAModuleInfo->getModuleInfo( rModName );
+ uno::Any aObject( aModuleInfo.ModuleObject );
+ uno::Reference< lang::XServiceInfo > xServiceInfo( aObject, uno::UNO_QUERY );
+ if( xServiceInfo.is() && xServiceInfo->supportsService( "ooo.vba.excel.Worksheet" ) )
+ {
+ uno::Reference< container::XNamed > xNamed( aObject, uno::UNO_QUERY );
+ if( xNamed.is() )
+ rObjName = xNamed->getName();
+ }
+ }
+ }
+ catch(const uno::Exception& )
+ {
+ }
+}
+
+sal_Int32 ModuleInfoHelper::getModuleType( const uno::Reference< container::XNameContainer >& rLib, const OUString& rModName )
+{
+ sal_Int32 nType = script::ModuleType::NORMAL;
+ uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( rLib, uno::UNO_QUERY );
+ if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo( rModName ) )
+ {
+ script::ModuleInfo aModuleInfo = xVBAModuleInfo->getModuleInfo( rModName );
+ nType = aModuleInfo.ModuleType;
+ }
+ return nType;
+}
+
+Entry::~Entry()
+{ }
+
+DocumentEntry::DocumentEntry (
+ ScriptDocument aDocument,
+ LibraryLocation eLocation,
+ EntryType eType
+) :
+ Entry(eType),
+ m_aDocument(std::move(aDocument)),
+ m_eLocation(eLocation)
+{
+ OSL_ENSURE( m_aDocument.isValid(), "DocumentEntry::DocumentEntry: illegal document!" );
+}
+
+DocumentEntry::~DocumentEntry()
+{ }
+
+LibEntry::LibEntry (
+ ScriptDocument const& rDocument,
+ LibraryLocation eLocation,
+ OUString aLibName
+) :
+ DocumentEntry(rDocument, eLocation, OBJ_TYPE_LIBRARY),
+ m_aLibName(std::move(aLibName))
+{ }
+
+LibEntry::~LibEntry()
+{ }
+
+EntryDescriptor::EntryDescriptor () :
+ m_aDocument(ScriptDocument::getApplicationScriptDocument()),
+ m_eLocation(LIBRARY_LOCATION_UNKNOWN),
+ m_eType(OBJ_TYPE_UNKNOWN)
+{ }
+
+EntryDescriptor::EntryDescriptor (
+ ScriptDocument aDocument,
+ LibraryLocation eLocation,
+ OUString aLibName,
+ OUString aLibSubName,
+ OUString aName,
+ EntryType eType
+) :
+ m_aDocument(std::move(aDocument)),
+ m_eLocation(eLocation),
+ m_aLibName(std::move(aLibName)),
+ m_aLibSubName(std::move(aLibSubName)),
+ m_aName(std::move(aName)),
+ m_eType(eType)
+{
+ OSL_ENSURE( m_aDocument.isValid(), "EntryDescriptor::EntryDescriptor: invalid document!" );
+}
+
+EntryDescriptor::EntryDescriptor (
+ ScriptDocument aDocument,
+ LibraryLocation eLocation,
+ OUString aLibName,
+ OUString aLibSubName,
+ OUString aName,
+ OUString aMethodName,
+ EntryType eType
+) :
+ m_aDocument(std::move(aDocument)),
+ m_eLocation(eLocation),
+ m_aLibName(std::move(aLibName)),
+ m_aLibSubName(std::move(aLibSubName)),
+ m_aName(std::move(aName)),
+ m_aMethodName(std::move(aMethodName)),
+ m_eType(eType)
+{
+ OSL_ENSURE( m_aDocument.isValid(), "EntryDescriptor::EntryDescriptor: invalid document!" );
+}
+
+SbTreeListBox::SbTreeListBox(std::unique_ptr<weld::TreeView> xControl, weld::Window* pTopLevel)
+ : m_xControl(std::move(xControl))
+ , m_xScratchIter(m_xControl->make_iterator())
+ , m_pTopLevel(pTopLevel)
+ , m_bFreezeOnFirstAddRemove(false)
+ , m_aNotifier(*this)
+{
+ m_xControl->connect_row_activated(LINK(this, SbTreeListBox, OpenCurrentHdl));
+ m_xControl->connect_expanding(LINK(this, SbTreeListBox, RequestingChildrenHdl));
+ nMode = BrowseMode::All; // everything
+}
+
+SbTreeListBox::~SbTreeListBox()
+{
+ m_aNotifier.dispose();
+
+ bool bValidIter = m_xControl->get_iter_first(*m_xScratchIter);
+ while (bValidIter)
+ {
+ Entry* pBasicEntry = weld::fromId<Entry*>(m_xControl->get_id(*m_xScratchIter));
+ delete pBasicEntry;
+ bValidIter = m_xControl->iter_next(*m_xScratchIter);
+ }
+}
+
+void SbTreeListBox::ScanEntry( const ScriptDocument& rDocument, LibraryLocation eLocation )
+{
+ OSL_ENSURE( rDocument.isAlive(), "TreeListBox::ScanEntry: illegal document!" );
+ if ( !rDocument.isAlive() )
+ return;
+
+ // can be called multiple times for updating!
+
+ // actually test if basic's in the tree already?!
+ // level 1: BasicManager (application, document, ...)
+ bool bDocumentRootEntry = FindRootEntry(rDocument, eLocation, *m_xScratchIter);
+ if (bDocumentRootEntry && m_xControl->get_row_expanded(*m_xScratchIter))
+ ImpCreateLibEntries(*m_xScratchIter, rDocument, eLocation);
+ if (!bDocumentRootEntry)
+ {
+ OUString aRootName(GetRootEntryName(rDocument, eLocation));
+ OUString aImage(GetRootEntryBitmaps(rDocument));
+ AddEntry(aRootName, aImage, nullptr, true, std::make_unique<DocumentEntry>(rDocument, eLocation));
+ }
+}
+
+void SbTreeListBox::ImpCreateLibEntries(const weld::TreeIter& rIter, const ScriptDocument& rDocument, LibraryLocation eLocation)
+{
+ // get a sorted list of library names
+ Sequence< OUString > aLibNames( rDocument.getLibraryNames() );
+ sal_Int32 nLibCount = aLibNames.getLength();
+ const OUString* pLibNames = aLibNames.getConstArray();
+
+ for ( sal_Int32 i = 0 ; i < nLibCount ; i++ )
+ {
+ OUString aLibName = pLibNames[ i ];
+
+ if ( eLocation == rDocument.getLibraryLocation( aLibName ) )
+ {
+ // check, if the module library is loaded
+ bool bModLibLoaded = false;
+ Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) );
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryLoaded( aLibName ) )
+ bModLibLoaded = true;
+
+ // check, if the dialog library is loaded
+ bool bDlgLibLoaded = false;
+ Reference< script::XLibraryContainer > xDlgLibContainer( rDocument.getLibraryContainer( E_DIALOGS ) );
+ if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryLoaded( aLibName ) )
+ bDlgLibLoaded = true;
+
+ bool bLoaded = bModLibLoaded || bDlgLibLoaded;
+
+ // if only one of the libraries is loaded, load also the other
+ if ( bLoaded )
+ {
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && !xModLibContainer->isLibraryLoaded( aLibName ) )
+ xModLibContainer->loadLibrary( aLibName );
+
+ if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && !xDlgLibContainer->isLibraryLoaded( aLibName ) )
+ xDlgLibContainer->loadLibrary( aLibName );
+ }
+
+ // create tree list box entry
+ OUString sId;
+ if ( ( nMode & BrowseMode::Dialogs ) && !( nMode & BrowseMode::Modules ) )
+ sId = bLoaded ? OUString(RID_BMP_DLGLIB) : OUString(RID_BMP_DLGLIBNOTLOADED);
+ else
+ sId = bLoaded ? OUString(RID_BMP_MODLIB) : OUString(RID_BMP_MODLIBNOTLOADED);
+ std::unique_ptr<weld::TreeIter> xLibRootEntry(m_xControl->make_iterator(&rIter));
+ bool bLibRootEntry = FindEntry(aLibName, OBJ_TYPE_LIBRARY, *xLibRootEntry);
+ if (bLibRootEntry)
+ {
+ SetEntryBitmaps(*xLibRootEntry, sId);
+ bool bRowExpanded = m_xControl->get_row_expanded(*xLibRootEntry);
+ bool bRowExpandAttempted = !m_xControl->get_children_on_demand(*xLibRootEntry);
+ if (bRowExpanded || bRowExpandAttempted)
+ ImpCreateLibSubEntries(*xLibRootEntry, rDocument, aLibName);
+ }
+ else
+ {
+ AddEntry(aLibName, sId, &rIter, true, std::make_unique<Entry>(OBJ_TYPE_LIBRARY));
+ }
+ }
+ }
+}
+
+void SbTreeListBox::ImpCreateLibSubEntries(const weld::TreeIter& rLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName)
+{
+ // modules
+ if ( nMode & BrowseMode::Modules )
+ {
+ Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) );
+
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( rLibName ) && xModLibContainer->isLibraryLoaded( rLibName ) )
+ {
+ try
+ {
+ if( rDocument.isInVBAMode() )
+ {
+ ImpCreateLibSubEntriesInVBAMode(rLibRootEntry, rDocument, rLibName);
+ }
+ else
+ {
+ // get a sorted list of module names
+ Sequence< OUString > aModNames = rDocument.getObjectNames( E_SCRIPTS, rLibName );
+ sal_Int32 nModCount = aModNames.getLength();
+ const OUString* pModNames = aModNames.getConstArray();
+
+ auto xTreeIter = m_xControl->make_iterator();
+
+ for ( sal_Int32 i = 0 ; i < nModCount ; i++ )
+ {
+ OUString aModName = pModNames[ i ];
+ m_xControl->copy_iterator(rLibRootEntry, *xTreeIter);
+ bool bModuleEntry = FindEntry(aModName, OBJ_TYPE_MODULE, *xTreeIter);
+ if (!bModuleEntry)
+ {
+ AddEntry(aModName, RID_BMP_MODULE, &rLibRootEntry, false, std::make_unique<Entry>(OBJ_TYPE_MODULE), xTreeIter.get());
+ }
+
+ // methods
+ if ( nMode & BrowseMode::Subs )
+ {
+ Sequence< OUString > aNames = GetMethodNames( rDocument, rLibName, aModName );
+ sal_Int32 nCount = aNames.getLength();
+ const OUString* pNames = aNames.getConstArray();
+
+ auto xSubTreeIter = m_xControl->make_iterator();
+
+ for ( sal_Int32 j = 0 ; j < nCount ; j++ )
+ {
+ OUString aName = pNames[ j ];
+ m_xControl->copy_iterator(*xTreeIter, *xSubTreeIter);
+ bool bEntry = FindEntry(aName, OBJ_TYPE_METHOD, *xSubTreeIter);
+ if (!bEntry)
+ {
+ AddEntry(aName, RID_BMP_MACRO, xTreeIter.get(), false, std::make_unique<Entry>(OBJ_TYPE_METHOD));
+ }
+ }
+ }
+ }
+ }
+ }
+ catch ( const container::NoSuchElementException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+ }
+
+ // dialogs
+ if ( !(nMode & BrowseMode::Dialogs) )
+ return;
+
+ Reference< script::XLibraryContainer > xDlgLibContainer( rDocument.getLibraryContainer( E_DIALOGS ) );
+
+ if ( !(xDlgLibContainer.is() && xDlgLibContainer->hasByName( rLibName ) && xDlgLibContainer->isLibraryLoaded( rLibName )) )
+ return;
+
+ try
+ {
+ // get a sorted list of dialog names
+ Sequence< OUString > aDlgNames( rDocument.getObjectNames( E_DIALOGS, rLibName ) );
+ sal_Int32 nDlgCount = aDlgNames.getLength();
+ const OUString* pDlgNames = aDlgNames.getConstArray();
+
+ auto xTreeIter = m_xControl->make_iterator();
+
+ for ( sal_Int32 i = 0 ; i < nDlgCount ; i++ )
+ {
+ OUString aDlgName = pDlgNames[ i ];
+ m_xControl->copy_iterator(rLibRootEntry, *xTreeIter);
+ bool bDialogEntry = FindEntry(aDlgName, OBJ_TYPE_DIALOG, *xTreeIter);
+ if (!bDialogEntry)
+ {
+ AddEntry(aDlgName, RID_BMP_DIALOG, &rLibRootEntry, false, std::make_unique<Entry>(OBJ_TYPE_DIALOG));
+ }
+ }
+ }
+ catch (const container::NoSuchElementException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+}
+
+void SbTreeListBox::ImpCreateLibSubEntriesInVBAMode(const weld::TreeIter& rLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName )
+{
+ auto const aEntries = {
+ std::make_pair( OBJ_TYPE_DOCUMENT_OBJECTS, IDEResId(RID_STR_DOCUMENT_OBJECTS) ),
+ std::make_pair( OBJ_TYPE_USERFORMS, IDEResId(RID_STR_USERFORMS) ),
+ std::make_pair( OBJ_TYPE_NORMAL_MODULES, IDEResId(RID_STR_NORMAL_MODULES) ),
+ std::make_pair( OBJ_TYPE_CLASS_MODULES, IDEResId(RID_STR_CLASS_MODULES) ) };
+ for( auto const & iter: aEntries )
+ {
+ EntryType eType = iter.first;
+ OUString const & aEntryName = iter.second;
+ std::unique_ptr<weld::TreeIter> xLibSubRootEntry(m_xControl->make_iterator(&rLibRootEntry));
+ bool bLibSubRootEntry = FindEntry(aEntryName, eType, *xLibSubRootEntry);
+ if (bLibSubRootEntry)
+ {
+ SetEntryBitmaps(*xLibSubRootEntry, RID_BMP_MODLIB);
+ if (m_xControl->get_row_expanded(*xLibSubRootEntry))
+ ImpCreateLibSubSubEntriesInVBAMode(*xLibSubRootEntry, rDocument, rLibName);
+ }
+ else
+ {
+ m_xControl->copy_iterator(rLibRootEntry, *xLibSubRootEntry);
+ AddEntry(aEntryName, RID_BMP_MODLIB, xLibSubRootEntry.get(), true, std::make_unique<Entry>(eType));
+ }
+ }
+}
+
+void SbTreeListBox::ImpCreateLibSubSubEntriesInVBAMode(const weld::TreeIter& rLibSubRootEntry, const ScriptDocument& rDocument, const OUString& rLibName)
+{
+ uno::Reference< container::XNameContainer > xLib = rDocument.getOrCreateLibrary( E_SCRIPTS, rLibName );
+ if( !xLib.is() )
+ return;
+
+ try
+ {
+ // get a sorted list of module names
+ Sequence< OUString > aModNames = rDocument.getObjectNames( E_SCRIPTS, rLibName );
+ sal_Int32 nModCount = aModNames.getLength();
+ const OUString* pModNames = aModNames.getConstArray();
+
+ EntryDescriptor aDesc(GetEntryDescriptor(&rLibSubRootEntry));
+ EntryType eCurrentType(aDesc.GetType());
+
+ for ( sal_Int32 i = 0 ; i < nModCount ; i++ )
+ {
+ OUString aModName = pModNames[ i ];
+ EntryType eType = OBJ_TYPE_UNKNOWN;
+ switch( ModuleInfoHelper::getModuleType( xLib, aModName ) )
+ {
+ case script::ModuleType::DOCUMENT:
+ eType = OBJ_TYPE_DOCUMENT_OBJECTS;
+ break;
+ case script::ModuleType::FORM:
+ eType = OBJ_TYPE_USERFORMS;
+ break;
+ case script::ModuleType::NORMAL:
+ eType = OBJ_TYPE_NORMAL_MODULES;
+ break;
+ case script::ModuleType::CLASS:
+ eType = OBJ_TYPE_CLASS_MODULES;
+ break;
+ }
+ if( eType != eCurrentType )
+ continue;
+
+ // display a nice friendly name in the ObjectModule tab,
+ // combining the objectname and module name, e.g. Sheet1 ( Financials )
+ OUString aEntryName = aModName;
+ if( eType == OBJ_TYPE_DOCUMENT_OBJECTS )
+ {
+ OUString sObjName;
+ ModuleInfoHelper::getObjectName( xLib, aModName, sObjName );
+ if( !sObjName.isEmpty() )
+ {
+ aEntryName += " (" + sObjName + ")";
+ }
+ }
+ std::unique_ptr<weld::TreeIter> xModuleEntry(m_xControl->make_iterator(&rLibSubRootEntry));
+ bool bModuleEntry = FindEntry(aEntryName, OBJ_TYPE_MODULE, *xModuleEntry);
+ if (!bModuleEntry)
+ {
+ m_xControl->copy_iterator(rLibSubRootEntry, *xModuleEntry);
+ AddEntry(aEntryName, RID_BMP_MODULE, xModuleEntry.get(), false,
+ std::make_unique<Entry>(OBJ_TYPE_MODULE));
+ }
+
+ // methods
+ if ( nMode & BrowseMode::Subs )
+ {
+ Sequence< OUString > aNames = GetMethodNames( rDocument, rLibName, aModName );
+ sal_Int32 nCount = aNames.getLength();
+ const OUString* pNames = aNames.getConstArray();
+
+ for ( sal_Int32 j = 0 ; j < nCount ; j++ )
+ {
+ OUString aName = pNames[ j ];
+ std::unique_ptr<weld::TreeIter> xEntry(m_xControl->make_iterator(xModuleEntry.get()));
+ bool bEntry = FindEntry(aName, OBJ_TYPE_METHOD, *xEntry);
+ if (!bEntry)
+ {
+ AddEntry(aName, RID_BMP_MACRO, xModuleEntry.get(), false, std::make_unique<Entry>(OBJ_TYPE_METHOD));
+ }
+ }
+ }
+ }
+ }
+ catch ( const container::NoSuchElementException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+}
+
+bool SbTreeListBox::ImpFindEntry(weld::TreeIter& rIter, std::u16string_view rText)
+{
+ bool bValidIter = m_xControl->iter_children(rIter);
+ while (bValidIter)
+ {
+ if (rText == m_xControl->get_text(rIter))
+ return true;
+ bValidIter = m_xControl->iter_next_sibling(rIter);
+ }
+ return false;
+}
+
+void SbTreeListBox::onDocumentCreated( const ScriptDocument& /*_rDocument*/ )
+{
+ UpdateEntries();
+}
+
+void SbTreeListBox::onDocumentOpened( const ScriptDocument& /*_rDocument*/ )
+{
+ UpdateEntries();
+}
+
+void SbTreeListBox::onDocumentSave( const ScriptDocument& /*_rDocument*/ )
+{
+ // not interested in
+}
+
+void SbTreeListBox::onDocumentSaveDone( const ScriptDocument& /*_rDocument*/ )
+{
+ // not interested in
+}
+
+void SbTreeListBox::onDocumentSaveAs( const ScriptDocument& /*_rDocument*/ )
+{
+ // not interested in
+}
+
+void SbTreeListBox::onDocumentSaveAsDone( const ScriptDocument& /*_rDocument*/ )
+{
+ UpdateEntries();
+}
+
+void SbTreeListBox::onDocumentClosed( const ScriptDocument& rDocument )
+{
+ UpdateEntries();
+ // The document is not yet actually deleted, so we need to remove its entry
+ // manually.
+ RemoveEntry(rDocument);
+}
+
+void SbTreeListBox::onDocumentTitleChanged( const ScriptDocument& /*_rDocument*/ )
+{
+ // not interested in
+}
+
+void SbTreeListBox::onDocumentModeChanged( const ScriptDocument& /*_rDocument*/ )
+{
+ // not interested in
+}
+
+void SbTreeListBox::UpdateEntries()
+{
+ bool bValidIter = m_xControl->get_selected(m_xScratchIter.get());
+ EntryDescriptor aCurDesc(GetEntryDescriptor(bValidIter ? m_xScratchIter.get() : nullptr));
+
+ // removing the invalid entries
+ std::unique_ptr<weld::TreeIter> xLastValid(m_xControl->make_iterator(nullptr));
+ bool bLastValid = false;
+ bValidIter = m_xControl->get_iter_first(*m_xScratchIter);
+ while (bValidIter)
+ {
+ if (IsValidEntry(*m_xScratchIter))
+ {
+ m_xControl->copy_iterator(*m_xScratchIter, *xLastValid);
+ bLastValid = true;
+ }
+ else
+ RemoveEntry(*m_xScratchIter);
+ if (bLastValid)
+ {
+ m_xControl->copy_iterator(*xLastValid, *m_xScratchIter);
+ bValidIter = m_xControl->iter_next(*m_xScratchIter);
+ }
+ else
+ bValidIter = m_xControl->get_iter_first(*m_xScratchIter);
+ }
+
+ ScanAllEntries();
+
+ SetCurrentEntry( aCurDesc );
+}
+
+// Removes the entry from the tree.
+void SbTreeListBox::RemoveEntry(const weld::TreeIter& rIter)
+{
+ if (m_bFreezeOnFirstAddRemove)
+ {
+ m_xControl->freeze();
+ m_bFreezeOnFirstAddRemove = false;
+ }
+
+ // removing the associated user data
+ Entry* pBasicEntry = weld::fromId<Entry*>(m_xControl->get_id(rIter));
+ delete pBasicEntry;
+ // removing the entry
+ m_xControl->remove(rIter);
+}
+
+// Removes the entry of rDocument.
+void SbTreeListBox::RemoveEntry (ScriptDocument const& rDocument)
+{
+ // finding the entry of rDocument
+ bool bValidIter = m_xControl->get_iter_first(*m_xScratchIter);
+ while (bValidIter)
+ {
+ if (rDocument == GetEntryDescriptor(m_xScratchIter.get()).GetDocument())
+ {
+ RemoveEntry(*m_xScratchIter);
+ break;
+ }
+ bValidIter = m_xControl->iter_next(*m_xScratchIter);
+ }
+}
+
+bool SbTreeListBox::FindEntry(std::u16string_view rText, EntryType eType, weld::TreeIter& rIter)
+{
+ bool bValidIter = m_xControl->iter_children(rIter);
+ while (bValidIter)
+ {
+ Entry* pBasicEntry = weld::fromId<Entry*>(m_xControl->get_id(rIter));
+ assert(pBasicEntry && "FindEntry: no Entry ?!");
+ if (pBasicEntry->GetType() == eType && rText == m_xControl->get_text(rIter))
+ return true;
+ bValidIter = m_xControl->iter_next_sibling(rIter);
+ }
+ return false;
+}
+
+bool SbTreeListBox::IsEntryProtected(const weld::TreeIter* pEntry)
+{
+ bool bProtected = false;
+ if (pEntry && m_xControl->get_iter_depth(*pEntry) == 1)
+ {
+ EntryDescriptor aDesc(GetEntryDescriptor(pEntry));
+ const ScriptDocument& rDocument( aDesc.GetDocument() );
+ OSL_ENSURE( rDocument.isAlive(), "TreeListBox::IsEntryProtected: no document, or document is dead!" );
+ if ( rDocument.isAlive() )
+ {
+ const OUString& aOULibName( aDesc.GetLibName() );
+ Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) );
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) )
+ {
+ Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
+ if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aOULibName ) && !xPasswd->isLibraryPasswordVerified( aOULibName ) )
+ {
+ bProtected = true;
+ }
+ }
+ }
+ }
+ return bProtected;
+}
+
+void SbTreeListBox::AddEntry(
+ const OUString& rText,
+ const OUString& rImage,
+ const weld::TreeIter* pParent,
+ bool bChildrenOnDemand,
+ std::unique_ptr<Entry>&& rUserData,
+ weld::TreeIter* pRet)
+{
+ if (m_bFreezeOnFirstAddRemove)
+ {
+ m_xControl->freeze();
+ m_bFreezeOnFirstAddRemove= false;
+ }
+ std::unique_ptr<weld::TreeIter> xScratch = pRet ? nullptr : m_xControl->make_iterator();
+ if (!pRet)
+ pRet = xScratch.get();
+ OUString sId(weld::toId(rUserData.release()));
+ m_xControl->insert(pParent, -1, &rText, &sId, nullptr, nullptr, bChildrenOnDemand, pRet);
+ m_xControl->set_image(*pRet, rImage);
+}
+
+void SbTreeListBox::SetEntryBitmaps(const weld::TreeIter& rIter, const OUString& rImage)
+{
+ m_xControl->set_image(rIter, rImage, -1);
+}
+
+LibraryType SbTreeListBox::GetLibraryType() const
+{
+ LibraryType eType = LibraryType::All;
+ if ( ( nMode & BrowseMode::Modules ) && !( nMode & BrowseMode::Dialogs ) )
+ eType = LibraryType::Module;
+ else if ( !( nMode & BrowseMode::Modules ) && ( nMode & BrowseMode::Dialogs ) )
+ eType = LibraryType::Dialog;
+ return eType;
+}
+
+OUString SbTreeListBox::GetRootEntryName( const ScriptDocument& rDocument, LibraryLocation eLocation ) const
+{
+ return rDocument.getTitle( eLocation, GetLibraryType() );
+}
+
+OUString SbTreeListBox::GetRootEntryBitmaps(const ScriptDocument& rDocument)
+{
+ OSL_ENSURE( rDocument.isValid(), "TreeListBox::GetRootEntryBitmaps: illegal document!" );
+ if (!rDocument.isValid())
+ return OUString();
+
+ if ( rDocument.isDocument() )
+ {
+ OUString sFactoryURL;
+ Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
+ Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xContext) );
+ try
+ {
+ OUString sModule( xModuleManager->identify( rDocument.getDocument() ) );
+ Sequence< beans::PropertyValue > aModuleDescr;
+ xModuleManager->getByName( sModule ) >>= aModuleDescr;
+ sal_Int32 nCount = aModuleDescr.getLength();
+ const beans::PropertyValue* pModuleDescr = aModuleDescr.getConstArray();
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ if ( pModuleDescr[ i ].Name == "ooSetupFactoryEmptyDocumentURL" )
+ {
+ pModuleDescr[ i ].Value >>= sFactoryURL;
+ break;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+
+ if ( !sFactoryURL.isEmpty() )
+ {
+ return SvFileInformationManager::GetFileImageId(INetURLObject(sFactoryURL));
+ }
+ else
+ {
+ // default icon
+ return RID_BMP_DOCUMENT;
+ }
+ }
+ return RID_BMP_INSTALLATION;
+}
+
+void SbTreeListBox::SetCurrentEntry (EntryDescriptor const & rDesc)
+{
+ bool bCurEntry = false;
+ auto xCurIter = m_xControl->make_iterator();
+ EntryDescriptor aDesc = rDesc;
+ if ( aDesc.GetType() == OBJ_TYPE_UNKNOWN )
+ {
+ aDesc = EntryDescriptor(
+ ScriptDocument::getApplicationScriptDocument(),
+ LIBRARY_LOCATION_USER, "Standard",
+ OUString(), ".", OBJ_TYPE_UNKNOWN
+ );
+ }
+ ScriptDocument aDocument = aDesc.GetDocument();
+ OSL_ENSURE( aDocument.isValid(), "TreeListBox::SetCurrentEntry: invalid document!" );
+ LibraryLocation eLocation = aDesc.GetLocation();
+ bool bRootEntry = FindRootEntry(aDocument, eLocation, *m_xScratchIter);
+ if (bRootEntry)
+ {
+ m_xControl->copy_iterator(*m_xScratchIter, *xCurIter);
+ bCurEntry = true;
+ const OUString& aLibName( aDesc.GetLibName() );
+ if ( !aLibName.isEmpty() )
+ {
+ m_xControl->expand_row(*m_xScratchIter);
+ auto xLibIter = m_xControl->make_iterator(m_xScratchIter.get());
+ bool bLibEntry = FindEntry(aLibName, OBJ_TYPE_LIBRARY, *xLibIter);
+ if (bLibEntry)
+ {
+ m_xControl->copy_iterator(*xLibIter, *xCurIter);
+ const OUString& aLibSubName( aDesc.GetLibSubName() );
+ if( !aLibSubName.isEmpty() )
+ {
+ m_xControl->expand_row(*xLibIter);
+ auto xSubLibIter = m_xControl->make_iterator(xLibIter.get());
+ bool bSubLibEntry = ImpFindEntry(*xSubLibIter, aLibSubName);
+ if (bSubLibEntry)
+ {
+ m_xControl->copy_iterator(*xSubLibIter, *xCurIter);
+ }
+ }
+ const OUString& aName( aDesc.GetName() );
+ if ( !aName.isEmpty() )
+ {
+ m_xControl->expand_row(*xCurIter);
+ EntryType eType = OBJ_TYPE_MODULE;
+ if ( aDesc.GetType() == OBJ_TYPE_DIALOG )
+ eType = OBJ_TYPE_DIALOG;
+ auto xEntryIter = m_xControl->make_iterator(xCurIter.get());
+ bool bEntry = FindEntry(aName, eType, *xEntryIter);
+ if (bEntry)
+ {
+ m_xControl->copy_iterator(*xEntryIter, *xCurIter);
+ const OUString& aMethodName( aDesc.GetMethodName() );
+ if (!aMethodName.isEmpty())
+ {
+ m_xControl->expand_row(*xCurIter);
+ auto xSubEntryIter = m_xControl->make_iterator(xCurIter.get());
+ bool bSubEntry = FindEntry(aMethodName, OBJ_TYPE_METHOD, *xSubEntryIter);
+ if (bSubEntry)
+ {
+ m_xControl->copy_iterator(*xSubEntryIter, *xCurIter);
+ }
+ else
+ {
+ m_xControl->copy_iterator(*xCurIter, *xSubEntryIter);
+ if (m_xControl->iter_children(*xSubEntryIter))
+ m_xControl->copy_iterator(*xSubEntryIter, *xCurIter);
+ }
+ }
+ }
+ else
+ {
+ auto xSubEntryIter = m_xControl->make_iterator(xCurIter.get());
+ if (m_xControl->iter_children(*xSubEntryIter))
+ m_xControl->copy_iterator(*xSubEntryIter, *xCurIter);
+ }
+ }
+ }
+ else
+ {
+ auto xSubLibIter = m_xControl->make_iterator(m_xScratchIter.get());
+ if (m_xControl->iter_children(*xSubLibIter))
+ m_xControl->copy_iterator(*xLibIter, *xCurIter);
+ }
+ }
+ }
+ else
+ {
+ bCurEntry = m_xControl->get_iter_first(*xCurIter);
+ }
+
+ if (!bCurEntry)
+ return;
+
+ m_xControl->set_cursor(*xCurIter);
+}
+
+IMPL_LINK_NOARG(SbTreeListBox, OpenCurrentHdl, weld::TreeView&, bool)
+{
+ bool bValidIter = m_xControl->get_cursor(m_xScratchIter.get());
+ if (!bValidIter)
+ return true;
+ if (!m_xControl->get_row_expanded(*m_xScratchIter))
+ m_xControl->expand_row(*m_xScratchIter);
+ else
+ m_xControl->collapse_row(*m_xScratchIter);
+
+ EntryDescriptor aDesc = GetEntryDescriptor(m_xScratchIter.get());
+ switch (aDesc.GetType())
+ {
+ case OBJ_TYPE_METHOD:
+ case OBJ_TYPE_MODULE:
+ case OBJ_TYPE_DIALOG:
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ {
+ SbxItem aSbxItem(
+ SID_BASICIDE_ARG_SBX, aDesc.GetDocument(),
+ aDesc.GetLibName(), aDesc.GetName(), aDesc.GetMethodName(),
+ ConvertType(aDesc.GetType())
+ );
+ pDispatcher->ExecuteList(
+ SID_BASICIDE_SHOWSBX, SfxCallMode::SYNCHRON,
+ { &aSbxItem }
+ );
+ }
+ break;
+
+ default:
+ break;
+ }
+ return true;
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/bastype3.cxx b/basctl/source/basicide/bastype3.cxx
new file mode 100644
index 000000000..43f1b9702
--- /dev/null
+++ b/basctl/source/basicide/bastype3.cxx
@@ -0,0 +1,440 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <basic/basmgr.hxx>
+#include <basic/sbmod.hxx>
+#include <basobj.hxx>
+#include <bastype2.hxx>
+#include <bitmaps.hlst>
+#include <bastypes.hxx>
+#include <com/sun/star/script/XLibraryContainer.hpp>
+#include <com/sun/star/script/XLibraryContainerPassword.hpp>
+#include <string_view>
+#include <osl/diagnose.h>
+#include <tools/debug.hxx>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star;
+
+IMPL_LINK(SbTreeListBox, RequestingChildrenHdl, const weld::TreeIter&, rEntry, bool)
+{
+ EntryDescriptor aDesc = GetEntryDescriptor(&rEntry);
+ const ScriptDocument& aDocument = aDesc.GetDocument();
+ OSL_ENSURE( aDocument.isAlive(), "basctl::TreeListBox::RequestingChildren: invalid document!" );
+ if (!aDocument.isAlive())
+ return false;
+
+ LibraryLocation eLocation = aDesc.GetLocation();
+ EntryType eType = aDesc.GetType();
+
+ if ( eType == OBJ_TYPE_DOCUMENT )
+ {
+ ImpCreateLibEntries( rEntry, aDocument, eLocation );
+ }
+ else if ( eType == OBJ_TYPE_LIBRARY )
+ {
+ const OUString& aOULibName( aDesc.GetLibName() );
+
+ // check password
+ bool bOK = true;
+ Reference< script::XLibraryContainer > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) );
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) )
+ {
+ Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
+ if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aOULibName ) && !xPasswd->isLibraryPasswordVerified( aOULibName ) )
+ {
+ OUString aPassword;
+ bOK = QueryPassword(m_pTopLevel, xModLibContainer, aOULibName, aPassword);
+ }
+ }
+
+ if ( bOK )
+ {
+ // load module library
+ bool bModLibLoaded = false;
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) )
+ {
+ if ( !xModLibContainer->isLibraryLoaded( aOULibName ) )
+ {
+ weld::WaitObject aWait(m_pTopLevel);
+ xModLibContainer->loadLibrary( aOULibName );
+ }
+ bModLibLoaded = xModLibContainer->isLibraryLoaded( aOULibName );
+ }
+
+ // load dialog library
+ bool bDlgLibLoaded = false;
+ Reference< script::XLibraryContainer > xDlgLibContainer = aDocument.getLibraryContainer( E_DIALOGS );
+ if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aOULibName ) )
+ {
+ if ( !xDlgLibContainer->isLibraryLoaded( aOULibName ) )
+ {
+ weld::WaitObject aWait(m_pTopLevel);
+ xDlgLibContainer->loadLibrary( aOULibName );
+ }
+ bDlgLibLoaded = xDlgLibContainer->isLibraryLoaded( aOULibName );
+ }
+
+ if ( bModLibLoaded || bDlgLibLoaded )
+ {
+ // create the sub entries
+ ImpCreateLibSubEntries( rEntry, aDocument, aOULibName );
+
+ // exchange image
+ const bool bDlgMode = (nMode & BrowseMode::Dialogs) && !(nMode & BrowseMode::Modules);
+ auto const aImage(bDlgMode ? OUString(RID_BMP_DLGLIB) : OUString(RID_BMP_MODLIB));
+ SetEntryBitmaps(rEntry, aImage);
+ }
+ else
+ {
+ OSL_FAIL( "basctl::TreeListBox::RequestingChildren: Error loading library!" );
+ }
+ }
+ }
+ else if ( eType == OBJ_TYPE_DOCUMENT_OBJECTS
+ || eType == OBJ_TYPE_USERFORMS
+ || eType == OBJ_TYPE_NORMAL_MODULES
+ || eType == OBJ_TYPE_CLASS_MODULES )
+ {
+ const OUString& aLibName( aDesc.GetLibName() );
+ ImpCreateLibSubSubEntriesInVBAMode( rEntry, aDocument, aLibName );
+ }
+
+ return true;
+}
+
+void SbTreeListBox::ScanAllEntries()
+{
+ // instead of always freezing, freeze on the first add/remove, which keeps gtk
+ // from relayouting the tree if it's not necessary
+ m_bFreezeOnFirstAddRemove = true;
+
+ ScanEntry( ScriptDocument::getApplicationScriptDocument(), LIBRARY_LOCATION_USER );
+ ScanEntry( ScriptDocument::getApplicationScriptDocument(), LIBRARY_LOCATION_SHARE );
+
+ ScriptDocuments aDocuments( ScriptDocument::getAllScriptDocuments( ScriptDocument::DocumentsSorted ) );
+ for (auto const& doc : aDocuments)
+ {
+ if ( doc.isAlive() )
+ ScanEntry(doc, LIBRARY_LOCATION_DOCUMENT);
+ }
+
+ if (!m_bFreezeOnFirstAddRemove)
+ m_xControl->thaw(); // m_bFreezeOnFirstAddRemove was changed, so control was frozen
+ else
+ m_bFreezeOnFirstAddRemove = false;
+}
+
+SbxVariable* SbTreeListBox::FindVariable(const weld::TreeIter* pEntry)
+{
+ if ( !pEntry )
+ return nullptr;
+
+ ScriptDocument aDocument( ScriptDocument::getApplicationScriptDocument() );
+ std::unique_ptr<weld::TreeIter> xIter(m_xControl->make_iterator(pEntry));
+ std::vector<std::pair<Entry*, OUString>> aEntries;
+ bool bValidIter = true;
+ do
+ {
+ sal_uInt16 nDepth = m_xControl->get_iter_depth(*xIter);
+ Entry* pBE = weld::fromId<Entry*>(m_xControl->get_id(*xIter));
+ switch (nDepth)
+ {
+ case 4:
+ case 3:
+ case 2:
+ case 1:
+ {
+ aEntries.emplace_back(pBE, m_xControl->get_text(*xIter));
+ }
+ break;
+ case 0:
+ {
+ aDocument = static_cast<DocumentEntry*>(pBE)->GetDocument();
+ }
+ break;
+ }
+ bValidIter = m_xControl->iter_parent(*xIter);
+ } while (bValidIter);
+
+ SbxVariable* pVar = nullptr;
+ if (!aEntries.empty())
+ {
+ std::reverse(aEntries.begin(), aEntries.end());
+ bool bDocumentObjects = false;
+ for (const auto& pair : aEntries)
+ {
+ Entry* pBE = pair.first;
+ assert(pBE && "No data found in entry!");
+ OUString aName(pair.second);
+
+ switch ( pBE->GetType() )
+ {
+ case OBJ_TYPE_LIBRARY:
+ if (BasicManager* pBasMgr = aDocument.getBasicManager())
+ pVar = pBasMgr->GetLib( aName );
+ break;
+ case OBJ_TYPE_MODULE:
+ DBG_ASSERT(dynamic_cast<StarBASIC*>(pVar), "FindVariable: invalid Basic");
+ if(!pVar)
+ {
+ break;
+ }
+ // extract the module name from the string like "Sheet1 (Example1)"
+ if( bDocumentObjects )
+ {
+ aName = aName.getToken( 0, ' ' );
+ }
+ pVar = static_cast<StarBASIC*>(pVar)->FindModule( aName );
+ break;
+ case OBJ_TYPE_METHOD:
+ DBG_ASSERT(dynamic_cast<SbxObject*>(pVar), "FindVariable: invalid module/object");
+ if(!pVar)
+ {
+ break;
+ }
+ pVar = static_cast<SbxObject*>(pVar)->GetMethods()->Find(aName, SbxClassType::Method);
+ break;
+ case OBJ_TYPE_DIALOG:
+ // sbx dialogs removed
+ break;
+ case OBJ_TYPE_DOCUMENT_OBJECTS:
+ bDocumentObjects = true;
+ [[fallthrough]];
+ case OBJ_TYPE_USERFORMS:
+ case OBJ_TYPE_NORMAL_MODULES:
+ case OBJ_TYPE_CLASS_MODULES:
+ // skip, to find the child entry.
+ continue;
+ default:
+ OSL_FAIL( "FindVariable: unknown type" );
+ pVar = nullptr;
+ break;
+ }
+ if ( !pVar )
+ break;
+ }
+ }
+ return pVar;
+}
+
+EntryDescriptor SbTreeListBox::GetEntryDescriptor(const weld::TreeIter* pEntry)
+{
+ ScriptDocument aDocument( ScriptDocument::getApplicationScriptDocument() );
+ LibraryLocation eLocation = LIBRARY_LOCATION_UNKNOWN;
+ OUString aLibName;
+ OUString aLibSubName;
+ OUString aName;
+ OUString aMethodName;
+ EntryType eType = OBJ_TYPE_UNKNOWN;
+
+ if ( !pEntry )
+ return EntryDescriptor( aDocument, eLocation, aLibName, aLibSubName, aName, aMethodName, eType );
+
+ std::vector<std::pair<Entry*, OUString>> aEntries;
+
+ std::unique_ptr<weld::TreeIter> xIter(m_xControl->make_iterator(pEntry));
+ bool bValidIter = true;
+ do
+ {
+ sal_uInt16 nDepth = m_xControl->get_iter_depth(*xIter);
+ Entry* pBE = weld::fromId<Entry*>(m_xControl->get_id(*xIter));
+ switch (nDepth)
+ {
+ case 4:
+ case 3:
+ case 2:
+ case 1:
+ {
+ aEntries.emplace_back(pBE, m_xControl->get_text(*xIter));
+ }
+ break;
+ case 0:
+ {
+ if (DocumentEntry* pDocumentEntry = static_cast<DocumentEntry*>(pBE))
+ {
+ aDocument = pDocumentEntry->GetDocument();
+ eLocation = pDocumentEntry->GetLocation();
+ eType = OBJ_TYPE_DOCUMENT;
+ }
+ }
+ break;
+ }
+ bValidIter = m_xControl->iter_parent(*xIter);
+ } while (bValidIter);
+
+ if ( !aEntries.empty() )
+ {
+ std::reverse(aEntries.begin(), aEntries.end());
+ for (const auto& pair : aEntries)
+ {
+ Entry* pBE = pair.first;
+ assert(pBE && "No data found in entry!");
+
+ switch ( pBE->GetType() )
+ {
+ case OBJ_TYPE_LIBRARY:
+ {
+ aLibName = pair.second;
+ eType = pBE->GetType();
+ }
+ break;
+ case OBJ_TYPE_MODULE:
+ {
+ aName = pair.second;
+ eType = pBE->GetType();
+ }
+ break;
+ case OBJ_TYPE_METHOD:
+ {
+ aMethodName = pair.second;
+ eType = pBE->GetType();
+ }
+ break;
+ case OBJ_TYPE_DIALOG:
+ {
+ aName = pair.second;
+ eType = pBE->GetType();
+ }
+ break;
+ case OBJ_TYPE_DOCUMENT_OBJECTS:
+ case OBJ_TYPE_USERFORMS:
+ case OBJ_TYPE_NORMAL_MODULES:
+ case OBJ_TYPE_CLASS_MODULES:
+ {
+ aLibSubName = pair.second;
+ eType = pBE->GetType();
+ }
+ break;
+ default:
+ {
+ OSL_FAIL( "GetEntryDescriptor: unknown type" );
+ eType = OBJ_TYPE_UNKNOWN;
+ }
+ break;
+ }
+
+ if ( eType == OBJ_TYPE_UNKNOWN )
+ break;
+ }
+ }
+
+ return EntryDescriptor( aDocument, eLocation, aLibName, aLibSubName, aName, aMethodName, eType );
+}
+
+ItemType SbTreeListBox::ConvertType (EntryType eType)
+{
+ switch (eType)
+ {
+ case OBJ_TYPE_DOCUMENT: return TYPE_SHELL;
+ case OBJ_TYPE_LIBRARY: return TYPE_LIBRARY;
+ case OBJ_TYPE_MODULE: return TYPE_MODULE;
+ case OBJ_TYPE_DIALOG: return TYPE_DIALOG;
+ case OBJ_TYPE_METHOD: return TYPE_METHOD;
+ default:
+ return static_cast<ItemType>(OBJ_TYPE_UNKNOWN);
+ }
+}
+
+bool SbTreeListBox::IsValidEntry(const weld::TreeIter& rEntry)
+{
+ bool bIsValid = false;
+
+ EntryDescriptor aDesc(GetEntryDescriptor(&rEntry));
+ const ScriptDocument& aDocument( aDesc.GetDocument() );
+ LibraryLocation eLocation( aDesc.GetLocation() );
+ const OUString& aLibName( aDesc.GetLibName() );
+ const OUString& aName( aDesc.GetName() );
+ const OUString& aMethodName( aDesc.GetMethodName() );
+ EntryType eType( aDesc.GetType() );
+
+ switch ( eType )
+ {
+ case OBJ_TYPE_DOCUMENT:
+ {
+ bIsValid = aDocument.isAlive()
+ && (aDocument.isApplication()
+ || GetRootEntryName(aDocument, eLocation) == m_xControl->get_text(rEntry));
+ }
+ break;
+ case OBJ_TYPE_LIBRARY:
+ {
+ bIsValid = aDocument.hasLibrary( E_SCRIPTS, aLibName ) || aDocument.hasLibrary( E_DIALOGS, aLibName );
+ }
+ break;
+ case OBJ_TYPE_MODULE:
+ {
+ bIsValid = aDocument.hasModule( aLibName, aName );
+ }
+ break;
+ case OBJ_TYPE_DIALOG:
+ {
+ bIsValid = aDocument.hasDialog( aLibName, aName );
+ }
+ break;
+ case OBJ_TYPE_METHOD:
+ {
+ bIsValid = HasMethod( aDocument, aLibName, aName, aMethodName );
+ }
+ break;
+ case OBJ_TYPE_DOCUMENT_OBJECTS:
+ case OBJ_TYPE_USERFORMS:
+ case OBJ_TYPE_NORMAL_MODULES:
+ case OBJ_TYPE_CLASS_MODULES:
+ {
+ bIsValid = true;
+ }
+ break;
+ default: ;
+ }
+
+ return bIsValid;
+}
+
+SbModule* SbTreeListBox::FindModule(const weld::TreeIter* pEntry)
+{
+ return dynamic_cast<SbModule*>(FindVariable(pEntry));
+}
+
+bool SbTreeListBox::FindRootEntry( const ScriptDocument& rDocument, LibraryLocation eLocation, weld::TreeIter& rIter)
+{
+ OSL_ENSURE( rDocument.isValid(), "basctl::TreeListBox::FindRootEntry: invalid document!" );
+ bool bValidIter = m_xControl->get_iter_first(rIter);
+ while (bValidIter)
+ {
+ DocumentEntry* pBDEntry = weld::fromId<DocumentEntry*>(m_xControl->get_id(rIter));
+ if (pBDEntry && pBDEntry->GetDocument() == rDocument && pBDEntry->GetLocation() == eLocation)
+ return true;
+ bValidIter = m_xControl->iter_next_sibling(rIter);
+ }
+ return false;
+}
+
+OUString CreateMgrAndLibStr( std::u16string_view rMgrName, std::u16string_view rLibName )
+{
+ return OUString::Concat("[") + rMgrName + "]." + rLibName;
+}
+
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/bastypes.cxx b/basctl/source/basicide/bastypes.cxx
new file mode 100644
index 000000000..4ebe98580
--- /dev/null
+++ b/basctl/source/basicide/bastypes.cxx
@@ -0,0 +1,781 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <strings.hrc>
+#include <helpids.h>
+#include <iderid.hxx>
+
+#include "baside2.hxx"
+#include <baside3.hxx>
+#include <basidesh.hxx>
+#include <basobj.hxx>
+#include <iderdll.hxx>
+#include "iderdll2.hxx"
+
+#include <com/sun/star/script/XLibraryContainerPassword.hpp>
+#include <sal/log.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/passwd.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/srchdefs.hxx>
+#include <utility>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <tools/stream.hxx>
+#include <o3tl/hash_combine.hxx>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star;
+
+BaseWindow::BaseWindow( vcl::Window* pParent, ScriptDocument aDocument, OUString aLibName, OUString aName )
+ :Window( pParent, WinBits( WB_3DLOOK ) )
+ ,pShellHScrollBar( nullptr)
+ ,pShellVScrollBar( nullptr)
+ ,nStatus( 0)
+ ,m_aDocument(std::move( aDocument ))
+ ,m_aLibName(std::move( aLibName ))
+ ,m_aName(std::move( aName ))
+{
+}
+
+BaseWindow::~BaseWindow()
+{
+ disposeOnce();
+}
+
+void BaseWindow::dispose()
+{
+ if ( pShellVScrollBar )
+ pShellVScrollBar->SetScrollHdl( Link<ScrollBar*,void>() );
+ if ( pShellHScrollBar )
+ pShellHScrollBar->SetScrollHdl( Link<ScrollBar*,void>() );
+ pShellVScrollBar.clear();
+ pShellHScrollBar.clear();
+ vcl::Window::dispose();
+}
+
+
+void BaseWindow::Init()
+{
+ if ( pShellVScrollBar )
+ pShellVScrollBar->SetScrollHdl( LINK( this, BaseWindow, ScrollHdl ) );
+ if ( pShellHScrollBar )
+ pShellHScrollBar->SetScrollHdl( LINK( this, BaseWindow, ScrollHdl ) );
+ DoInit(); // virtual...
+}
+
+
+void BaseWindow::DoInit()
+{ }
+
+
+void BaseWindow::GrabScrollBars( ScrollBar* pHScroll, ScrollBar* pVScroll )
+{
+ pShellHScrollBar = pHScroll;
+ pShellVScrollBar = pVScroll;
+// Init(); // does not make sense, leads to flickering and errors...
+}
+
+
+IMPL_LINK( BaseWindow, ScrollHdl, ScrollBar *, pCurScrollBar, void )
+{
+ DoScroll( pCurScrollBar );
+}
+
+void BaseWindow::ExecuteCommand (SfxRequest&)
+{ }
+
+void BaseWindow::ExecuteGlobal (SfxRequest&)
+{ }
+
+
+bool BaseWindow::EventNotify( NotifyEvent& rNEvt )
+{
+ bool bDone = false;
+
+ if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
+ {
+ KeyEvent aKEvt = *rNEvt.GetKeyEvent();
+ vcl::KeyCode aCode = aKEvt.GetKeyCode();
+ sal_uInt16 nCode = aCode.GetCode();
+
+ switch ( nCode )
+ {
+ case KEY_PAGEUP:
+ case KEY_PAGEDOWN:
+ {
+ if ( aCode.IsMod1() )
+ {
+ if (Shell* pShell = GetShell())
+ pShell->NextPage( nCode == KEY_PAGEUP );
+ bDone = true;
+ }
+ }
+ break;
+ }
+ }
+
+ return bDone || Window::EventNotify( rNEvt );
+}
+
+
+void BaseWindow::DoScroll( ScrollBar* )
+{
+}
+
+
+void BaseWindow::StoreData()
+{
+}
+
+bool BaseWindow::AllowUndo()
+{
+ return true;
+}
+
+
+void BaseWindow::UpdateData()
+{
+}
+
+OUString BaseWindow::GetTitle()
+{
+ return OUString();
+}
+
+OUString BaseWindow::CreateQualifiedName()
+{
+ OUString aName;
+ if ( !m_aLibName.isEmpty() )
+ {
+ LibraryLocation eLocation = m_aDocument.getLibraryLocation( m_aLibName );
+ aName = m_aDocument.getTitle(eLocation) + "." + m_aLibName + "." +
+ GetTitle();
+ }
+ return aName;
+}
+
+void BaseWindow::SetReadOnly (bool)
+{
+}
+
+bool BaseWindow::IsReadOnly ()
+{
+ return false;
+}
+
+void BaseWindow::BasicStarted()
+{
+}
+
+void BaseWindow::BasicStopped()
+{
+}
+
+bool BaseWindow::IsModified ()
+{
+ return true;
+}
+
+SfxUndoManager* BaseWindow::GetUndoManager()
+{
+ return nullptr;
+}
+
+SearchOptionFlags BaseWindow::GetSearchOptions()
+{
+ return SearchOptionFlags::NONE;
+}
+
+sal_uInt16 BaseWindow::StartSearchAndReplace (SvxSearchItem const&, bool)
+{
+ return 0;
+}
+
+void BaseWindow::OnNewDocument ()
+{ }
+
+void BaseWindow::InsertLibInfo () const
+{
+ if (ExtraData* pData = GetExtraData())
+ pData->GetLibInfo().InsertInfo(m_aDocument, m_aLibName, m_aName, GetType());
+}
+
+bool BaseWindow::Is (
+ ScriptDocument const& rDocument,
+ std::u16string_view rLibName, std::u16string_view rName,
+ ItemType eType, bool bFindSuspended
+)
+{
+ if (bFindSuspended || !IsSuspended())
+ {
+ // any non-suspended window is ok
+ if (rLibName.empty() || rName.empty() || eType == TYPE_UNKNOWN)
+ return true;
+ // ok if the parameters match
+ if (m_aDocument == rDocument && m_aLibName == rLibName && m_aName == rName && GetType() == eType)
+ return true;
+ }
+ return false;
+}
+
+bool BaseWindow::HasActiveEditor () const
+{
+ return false;
+}
+
+
+// DockingWindow
+
+
+// style bits for DockingWindow
+WinBits const DockingWindow::StyleBits =
+ WB_BORDER | WB_3DLOOK | WB_CLIPCHILDREN |
+ WB_MOVEABLE | WB_SIZEABLE | WB_DOCKABLE;
+
+DockingWindow::DockingWindow(vcl::Window* pParent, const OUString& rUIXMLDescription, const OString& rID)
+ : ResizableDockingWindow(pParent)
+ , m_xBuilder(Application::CreateInterimBuilder(m_xBox.get(), rUIXMLDescription, true))
+ , pLayout(nullptr)
+ , nShowCount(0)
+{
+ m_xContainer = m_xBuilder->weld_container(rID);
+}
+
+DockingWindow::DockingWindow (Layout* pParent)
+ : ResizableDockingWindow(pParent, StyleBits)
+ , pLayout(pParent)
+ , nShowCount(0)
+{ }
+
+DockingWindow::~DockingWindow()
+{
+ disposeOnce();
+}
+
+void DockingWindow::dispose()
+{
+ m_xContainer.reset();
+ m_xBuilder.reset();
+ pLayout.clear();
+ ResizableDockingWindow::dispose();
+}
+
+// Sets the position and the size of the docking window. This property is saved
+// when the window is floating. Called by Layout.
+void DockingWindow::ResizeIfDocking (Point const& rPos, Size const& rSize)
+{
+ tools::Rectangle const rRect(rPos, rSize);
+ if (rRect != aDockingRect)
+ {
+ // saving the position and the size
+ aDockingRect = rRect;
+ // resizing if actually docking
+ if (!IsFloatingMode())
+ SetPosSizePixel(rPos, rSize);
+ }
+}
+void DockingWindow::ResizeIfDocking (Size const& rSize)
+{
+ ResizeIfDocking(aDockingRect.TopLeft(), rSize);
+}
+
+// Sets the parent Layout window.
+// The physical parent is set only when the window is docking.
+void DockingWindow::SetLayoutWindow (Layout* pLayout_)
+{
+ pLayout = pLayout_;
+ if (!IsFloatingMode())
+ SetParent(pLayout);
+
+}
+
+// Increases the "show" reference count.
+// The window is shown when the reference count is positive.
+void DockingWindow::Show (bool bShow) // = true
+{
+ if (bShow)
+ {
+ if (++nShowCount == 1)
+ ResizableDockingWindow::Show();
+ }
+ else
+ {
+ if (--nShowCount == 0)
+ ResizableDockingWindow::Hide();
+ }
+}
+
+// Decreases the "show" reference count.
+// The window is hidden when the reference count reaches zero.
+void DockingWindow::Hide ()
+{
+ Show(false);
+}
+
+bool DockingWindow::Docking( const Point& rPos, tools::Rectangle& rRect )
+{
+ if (aDockingRect.Contains(rPos))
+ {
+ rRect.SetSize(aDockingRect.GetSize());
+ return false; // dock
+ }
+ else // adjust old size
+ {
+ if (!aFloatingRect.IsEmpty())
+ rRect.SetSize(aFloatingRect.GetSize());
+ return true; // float
+ }
+}
+
+void DockingWindow::EndDocking( const tools::Rectangle& rRect, bool bFloatMode )
+{
+ if ( bFloatMode )
+ ResizableDockingWindow::EndDocking( rRect, bFloatMode );
+ else
+ {
+ SetFloatingMode(false);
+ DockThis();
+ }
+}
+
+void DockingWindow::ToggleFloatingMode()
+{
+ if (IsFloatingMode())
+ {
+ if (!aFloatingRect.IsEmpty())
+ SetPosSizePixel(
+ GetParent()->ScreenToOutputPixel(aFloatingRect.TopLeft()),
+ aFloatingRect.GetSize()
+ );
+ }
+ DockThis();
+}
+
+bool DockingWindow::PrepareToggleFloatingMode()
+{
+ if (IsFloatingMode())
+ {
+ // memorize position and size on the desktop...
+ aFloatingRect = tools::Rectangle(
+ GetParent()->OutputToScreenPixel(GetPosPixel()),
+ GetSizePixel()
+ );
+ }
+ return true;
+}
+
+void DockingWindow::StartDocking()
+{
+ if (IsFloatingMode())
+ {
+ aFloatingRect = tools::Rectangle(
+ GetParent()->OutputToScreenPixel(GetPosPixel()),
+ GetSizePixel()
+ );
+ }
+}
+
+void DockingWindow::DockThis ()
+{
+ // resizing when floating -> docking
+ if (!IsFloatingMode())
+ {
+ Point const aPos = aDockingRect.TopLeft();
+ Size const aSize = aDockingRect.GetSize();
+ if (aSize != GetSizePixel() || aPos != GetPosPixel())
+ SetPosSizePixel(aPos, aSize);
+ }
+
+ if (pLayout)
+ {
+ if (!IsFloatingMode() && GetParent() != pLayout)
+ SetParent(pLayout);
+ pLayout->ArrangeWindows();
+ }
+}
+
+TabBar::TabBar( vcl::Window* pParent ) :
+ ::TabBar( pParent, WinBits( WB_3DLOOK | WB_SCROLL | WB_BORDER | WB_DRAG ) )
+{
+ EnableEditMode();
+
+ SetHelpId( HID_BASICIDE_TABBAR );
+}
+
+void TabBar::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.IsLeft() && ( rMEvt.GetClicks() == 2 ) && !IsInEditMode() )
+ {
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ pDispatcher->Execute( SID_BASICIDE_MODULEDLG );
+ }
+ else
+ {
+ ::TabBar::MouseButtonDown( rMEvt ); // base class version
+ }
+}
+
+void TabBar::Command( const CommandEvent& rCEvt )
+{
+ if ( ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) && !IsInEditMode() )
+ {
+ Point aPos( rCEvt.IsMouseEvent() ? rCEvt.GetMousePosPixel() : Point(1,1) );
+ if ( rCEvt.IsMouseEvent() ) // select right tab
+ {
+ Point aP = PixelToLogic( aPos );
+ MouseEvent aMouseEvent( aP, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT );
+ ::TabBar::MouseButtonDown( aMouseEvent ); // base class
+ }
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ pDispatcher->ExecutePopup("tabbar", this, &aPos);
+ }
+}
+
+TabBarAllowRenamingReturnCode TabBar::AllowRenaming()
+{
+ bool const bValid = IsValidSbxName(GetEditText());
+
+ if ( !bValid )
+ {
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
+ xError->run();
+ }
+
+ return bValid ? TABBAR_RENAMING_YES : TABBAR_RENAMING_NO;
+}
+
+
+void TabBar::EndRenaming()
+{
+ if ( !IsEditModeCanceled() )
+ {
+ SfxUInt16Item aID( SID_BASICIDE_ARG_TABID, GetEditPageId() );
+ SfxStringItem aNewName( SID_BASICIDE_ARG_MODULENAME, GetEditText() );
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ pDispatcher->ExecuteList( SID_BASICIDE_NAMECHANGEDONTAB,
+ SfxCallMode::SYNCHRON, { &aID, &aNewName });
+ }
+}
+
+
+namespace
+{
+
+// helper class for sorting TabBar
+struct TabBarSortHelper
+{
+ sal_uInt16 nPageId;
+ OUString aPageText;
+
+ bool operator < (TabBarSortHelper const& rComp) const
+ {
+ return aPageText.compareToIgnoreAsciiCase(rComp.aPageText) < 0;
+ }
+};
+
+} // namespace
+
+void TabBar::Sort()
+{
+ Shell* pShell = GetShell();
+ if (!pShell)
+ return;
+
+ Shell::WindowTable& aWindowTable = pShell->GetWindowTable();
+ TabBarSortHelper aTabBarSortHelper;
+ std::vector<TabBarSortHelper> aModuleList;
+ std::vector<TabBarSortHelper> aDialogList;
+ sal_uInt16 nPageCount = GetPageCount();
+ sal_uInt16 i;
+
+ // create module and dialog lists for sorting
+ for ( i = 0; i < nPageCount; i++)
+ {
+ sal_uInt16 nId = GetPageId( i );
+ aTabBarSortHelper.nPageId = nId;
+ aTabBarSortHelper.aPageText = GetPageText( nId );
+ BaseWindow* pWin = aWindowTable[ nId ].get();
+
+ if (dynamic_cast<ModulWindow*>(pWin))
+ {
+ aModuleList.push_back( aTabBarSortHelper );
+ }
+ else if (dynamic_cast<DialogWindow*>(pWin))
+ {
+ aDialogList.push_back( aTabBarSortHelper );
+ }
+ }
+
+ // sort module and dialog lists by page text
+ std::sort( aModuleList.begin() , aModuleList.end() );
+ std::sort( aDialogList.begin() , aDialogList.end() );
+
+
+ sal_uInt16 nModules = sal::static_int_cast<sal_uInt16>( aModuleList.size() );
+ sal_uInt16 nDialogs = sal::static_int_cast<sal_uInt16>( aDialogList.size() );
+
+ // move module pages to new positions
+ for (i = 0; i < nModules; i++)
+ {
+ MovePage( aModuleList[i].nPageId , i );
+ }
+
+ // move dialog pages to new positions
+ for (i = 0; i < nDialogs; i++)
+ {
+ MovePage( aDialogList[i].nPageId , nModules + i );
+ }
+}
+
+void CutLines( OUString& rStr, sal_Int32 nStartLine, sal_Int32 nLines )
+{
+ sal_Int32 nStartPos = 0;
+ sal_Int32 nLine = 0;
+ while ( nLine < nStartLine )
+ {
+ nStartPos = searchEOL( rStr, nStartPos );
+ if( nStartPos == -1 )
+ break;
+ nStartPos++; // not the \n.
+ nLine++;
+ }
+
+ SAL_WARN_IF( nStartPos == -1, "basctl.basicide", "CutLines: Start line not found!" );
+
+ if ( nStartPos == -1 )
+ return;
+
+ sal_Int32 nEndPos = nStartPos;
+
+ for ( sal_Int32 i = 0; i < nLines; i++ )
+ nEndPos = searchEOL( rStr, nEndPos+1 );
+
+ if ( nEndPos == -1 ) // might happen at the last line
+ nEndPos = rStr.getLength();
+ else
+ nEndPos++;
+
+ OUString aEndStr = rStr.copy( nEndPos );
+ rStr = rStr.copy( 0, nStartPos );
+ rStr += aEndStr;
+
+ // erase trailing empty lines
+ {
+ sal_Int32 n = nStartPos;
+ sal_Int32 nLen = rStr.getLength();
+ while ( ( n < nLen ) && ( rStr[ n ] == LINE_SEP ||
+ rStr[ n ] == LINE_SEP_CR ) )
+ {
+ n++;
+ }
+
+ if ( n > nStartPos )
+ {
+ aEndStr = rStr.copy( n );
+ rStr = rStr.copy( 0, nStartPos );
+ rStr += aEndStr;
+ }
+ }
+}
+
+sal_uInt32 CalcLineCount( SvStream& rStream )
+{
+ sal_uInt32 nLFs = 0;
+ sal_uInt32 nCRs = 0;
+ char c;
+
+ rStream.Seek( 0 );
+ rStream.ReadChar( c );
+ while ( !rStream.eof() )
+ {
+ if ( c == '\n' )
+ nLFs++;
+ else if ( c == '\r' )
+ nCRs++;
+ rStream.ReadChar( c );
+ }
+
+ rStream.Seek( 0 );
+ if ( nLFs > nCRs )
+ return nLFs;
+ return nCRs;
+}
+
+
+// LibInfo
+
+
+LibInfo::LibInfo ()
+{ }
+
+LibInfo::~LibInfo ()
+{ }
+
+void LibInfo::InsertInfo (
+ ScriptDocument const& rDocument,
+ OUString const& rLibName,
+ OUString const& rCurrentName,
+ ItemType eCurrentType
+)
+{
+ Key aKey(rDocument, rLibName);
+ m_aMap.erase(aKey);
+ m_aMap.emplace(aKey, Item(rCurrentName, eCurrentType));
+}
+
+void LibInfo::RemoveInfoFor (ScriptDocument const& rDocument)
+{
+ Map::iterator it = std::find_if(m_aMap.begin(), m_aMap.end(),
+ [&rDocument](Map::reference rEntry) { return rEntry.first.GetDocument() == rDocument; });
+ if (it != m_aMap.end())
+ m_aMap.erase(it);
+}
+
+LibInfo::Item const* LibInfo::GetInfo (
+ ScriptDocument const& rDocument, OUString const& rLibName
+)
+{
+ Map::iterator it = m_aMap.find(Key(rDocument, rLibName));
+ return it != m_aMap.end() ? &it->second : nullptr;
+}
+
+LibInfo::Key::Key (ScriptDocument aDocument, OUString aLibName) :
+ m_aDocument(std::move(aDocument)), m_aLibName(std::move(aLibName))
+{ }
+
+bool LibInfo::Key::operator == (Key const& rKey) const
+{
+ return m_aDocument == rKey.m_aDocument && m_aLibName == rKey.m_aLibName;
+}
+
+size_t LibInfo::Key::Hash::operator () (Key const& rKey) const
+{
+ std::size_t seed = 0;
+ o3tl::hash_combine(seed, rKey.m_aDocument.hashCode());
+ o3tl::hash_combine(seed, rKey.m_aLibName.hashCode());
+ return seed;
+}
+
+LibInfo::Item::Item (
+ OUString aCurrentName,
+ ItemType eCurrentType
+) :
+ m_aCurrentName(std::move(aCurrentName)),
+ m_eCurrentType(eCurrentType)
+{ }
+
+static bool QueryDel(std::u16string_view rName, const OUString &rStr, weld::Widget* pParent)
+{
+ OUString aName = OUString::Concat("\'") + rName + "\'";
+ OUString aQuery = rStr.replaceAll("XX", aName);
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pParent,
+ VclMessageType::Question, VclButtonsType::YesNo, aQuery));
+ return (xQueryBox->run() == RET_YES);
+}
+
+bool QueryDelMacro( std::u16string_view rName, weld::Widget* pParent )
+{
+ return QueryDel( rName, IDEResId( RID_STR_QUERYDELMACRO ), pParent );
+}
+
+bool QueryReplaceMacro( std::u16string_view rName, weld::Widget* pParent )
+{
+ return QueryDel( rName, IDEResId( RID_STR_QUERYREPLACEMACRO ), pParent );
+}
+
+bool QueryDelDialog( std::u16string_view rName, weld::Widget* pParent )
+{
+ return QueryDel( rName, IDEResId( RID_STR_QUERYDELDIALOG ), pParent );
+}
+
+bool QueryDelLib( std::u16string_view rName, bool bRef, weld::Widget* pParent )
+{
+ return QueryDel( rName, IDEResId( bRef ? RID_STR_QUERYDELLIBREF : RID_STR_QUERYDELLIB ), pParent );
+}
+
+bool QueryDelModule( std::u16string_view rName, weld::Widget* pParent )
+{
+ 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)
+{
+ bool bOK = false;
+ sal_uInt16 nRet = 0;
+
+ do
+ {
+ // password dialog
+ SfxPasswordDialog aDlg(pDialogParent);
+ aDlg.SetMinLen(1);
+
+ // set new title
+ if ( bNewTitle )
+ {
+ OUString aTitle(IDEResId(RID_STR_ENTERPASSWORD));
+ aTitle = aTitle.replaceAll("XX", rLibName);
+ aDlg.set_title(aTitle);
+ }
+
+ // execute dialog
+ nRet = aDlg.run();
+
+ // verify password
+ if ( nRet == RET_OK )
+ {
+ if ( xLibContainer.is() && xLibContainer->hasByName( rLibName ) )
+ {
+ Reference< script::XLibraryContainerPassword > xPasswd( xLibContainer, UNO_QUERY );
+ if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( rLibName ) && !xPasswd->isLibraryPasswordVerified( rLibName ) )
+ {
+ rPassword = aDlg.GetPassword();
+ bOK = xPasswd->verifyLibraryPassword( rLibName, rPassword );
+
+ if ( !bOK )
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pDialogParent,
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_WRONGPASSWORD)));
+ xErrorBox->run();
+ }
+ }
+ }
+ }
+ }
+ while ( bRepeat && !bOK && nRet == RET_OK );
+
+ return bOK;
+}
+
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/breakpoint.cxx b/basctl/source/basicide/breakpoint.cxx
new file mode 100644
index 000000000..0d0347ace
--- /dev/null
+++ b/basctl/source/basicide/breakpoint.cxx
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "breakpoint.hxx"
+
+#include <basic/sbmod.hxx>
+#include <tools/debug.hxx>
+
+
+namespace basctl
+{
+
+BreakPointList::BreakPointList()
+{}
+
+BreakPointList::BreakPointList(BreakPointList const & rList)
+{
+ for (size_t i = 0; i < rList.size(); ++i)
+ maBreakPoints.push_back( rList.at( i ) );
+}
+
+BreakPointList::~BreakPointList()
+{
+}
+
+void BreakPointList::reset()
+{
+ maBreakPoints.clear();
+}
+
+void BreakPointList::transfer(BreakPointList & rList)
+{
+ maBreakPoints = std::move(rList.maBreakPoints);
+}
+
+void BreakPointList::InsertSorted(BreakPoint aNewBrk)
+{
+ auto it = std::find_if(maBreakPoints.begin(), maBreakPoints.end(),
+ [&aNewBrk](const BreakPoint& rBreakPoint) { return aNewBrk.nLine <= rBreakPoint.nLine; });
+ if (it != maBreakPoints.end())
+ {
+ DBG_ASSERT( it->nLine != aNewBrk.nLine, "BreakPoint exists already!" );
+ maBreakPoints.insert( it, aNewBrk );
+ return;
+ }
+ // no insert position found => LIST_APPEND
+ maBreakPoints.push_back( aNewBrk );
+}
+
+void BreakPointList::SetBreakPointsInBasic(SbModule* pModule)
+{
+ pModule->ClearAllBP();
+
+ for (const BreakPoint& rBrk : maBreakPoints)
+ {
+ if ( rBrk.bEnabled )
+ pModule->SetBP( rBrk.nLine );
+ }
+}
+
+BreakPoint* BreakPointList::FindBreakPoint(sal_uInt16 nLine)
+{
+ for (BreakPoint& rBrk : maBreakPoints)
+ {
+ if ( rBrk.nLine == nLine )
+ return &rBrk;
+ }
+ return nullptr;
+}
+
+void BreakPointList::AdjustBreakPoints(sal_uInt16 nLine, bool bInserted)
+{
+ for ( size_t i = 0; i < maBreakPoints.size(); )
+ {
+ BreakPoint& rBrk = maBreakPoints[ i ];
+ bool bDelBrk = false;
+ if ( rBrk.nLine == nLine )
+ {
+ if ( bInserted )
+ rBrk.nLine++;
+ else
+ bDelBrk = true;
+ }
+ else if ( rBrk.nLine > nLine )
+ {
+ if ( bInserted )
+ rBrk.nLine++;
+ else
+ rBrk.nLine--;
+ }
+
+ if ( bDelBrk )
+ {
+ maBreakPoints.erase(maBreakPoints.begin() + i);
+ }
+ else
+ {
+ ++i;
+ }
+ }
+}
+
+void BreakPointList::ResetHitCount()
+{
+ for (BreakPoint& rBrk : maBreakPoints)
+ {
+ rBrk.nHitCount = 0;
+ }
+}
+
+void BreakPointList::remove(const BreakPoint* ptr)
+{
+ auto i = std::find_if(maBreakPoints.begin(), maBreakPoints.end(),
+ [&ptr](const BreakPoint& rBreakPoint) { return ptr == &rBreakPoint; });
+ if (i != maBreakPoints.end())
+ maBreakPoints.erase( i );
+ return;
+}
+
+void BreakPointList::remove(size_t idx)
+{
+ maBreakPoints.erase( maBreakPoints.begin() + idx );
+}
+
+size_t BreakPointList::size() const
+{
+ return maBreakPoints.size();
+}
+
+BreakPoint& BreakPointList::at(size_t i)
+{
+ return maBreakPoints[ i ];
+}
+
+const BreakPoint& BreakPointList::at(size_t i) const
+{
+ return maBreakPoints[ i ];
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/breakpoint.hxx b/basctl/source/basicide/breakpoint.hxx
new file mode 100644
index 000000000..324564aaa
--- /dev/null
+++ b/basctl/source/basicide/breakpoint.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cstddef>
+#include <vector>
+
+#include <sal/types.h>
+
+class SbModule;
+
+namespace basctl
+{
+struct BreakPoint
+{
+ bool bEnabled;
+ sal_uInt16 nLine;
+ size_t nStopAfter;
+ size_t nHitCount;
+
+ explicit BreakPoint(sal_uInt16 nL)
+ : bEnabled(true)
+ , nLine(nL)
+ , nStopAfter(0)
+ , nHitCount(0)
+ {
+ }
+};
+
+class BreakPointList
+{
+private:
+ BreakPointList& operator=(BreakPointList const&) = delete;
+ std::vector<BreakPoint> maBreakPoints;
+
+public:
+ BreakPointList();
+
+ BreakPointList(BreakPointList const& rList);
+
+ ~BreakPointList();
+
+ void reset();
+
+ void transfer(BreakPointList& rList);
+
+ void InsertSorted(BreakPoint pBrk);
+ BreakPoint* FindBreakPoint(sal_uInt16 nLine);
+ void AdjustBreakPoints(sal_uInt16 nLine, bool bInserted);
+ void SetBreakPointsInBasic(SbModule* pModule);
+ void ResetHitCount();
+
+ size_t size() const;
+ BreakPoint& at(size_t i);
+ const BreakPoint& at(size_t i) const;
+ void remove(const BreakPoint* ptr);
+ void remove(size_t i);
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/brkdlg.cxx b/basctl/source/basicide/brkdlg.cxx
new file mode 100644
index 000000000..37ba1dbb6
--- /dev/null
+++ b/basctl/source/basicide/brkdlg.cxx
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include "breakpoint.hxx"
+#include "brkdlg.hxx"
+#include <basobj.hxx>
+
+#include <sfx2/dispatch.hxx>
+#include <sfx2/sfxsids.hrc>
+
+namespace basctl
+{
+// FIXME Why does BreakPointDialog allow only sal_uInt16 for break-point line
+// numbers, whereas BreakPoint supports sal_uLong?
+
+namespace
+{
+bool lcl_ParseText(OUString const& rText, size_t& rLineNr)
+{
+ // aText should look like "# n" where
+ // n > 0 && n < std::numeric_limits< sal_uInt16 >::max().
+ // All spaces are ignored, so there can even be spaces within the
+ // number n. (Maybe it would be better to ignore all whitespace instead
+ // of just spaces.)
+ OUString aText(rText.replaceAll(" ", ""));
+ if (aText.isEmpty())
+ return false;
+ sal_Unicode cFirst = aText[0];
+ if (cFirst != '#' && (cFirst < '0' || cFirst > '9'))
+ return false;
+ if (cFirst == '#')
+ aText = aText.copy(1);
+ // XXX Assumes that sal_uInt16 is contained within sal_Int32:
+ sal_Int32 n = aText.toInt32();
+ if (n <= 0)
+ return false;
+ rLineNr = static_cast<size_t>(n);
+ return true;
+}
+
+} // namespace
+
+BreakPointDialog::BreakPointDialog(weld::Window* pParent, BreakPointList& rBrkPntList)
+ : GenericDialogController(pParent, "modules/BasicIDE/ui/managebreakpoints.ui",
+ "ManageBreakpointsDialog")
+ , m_rOriginalBreakPointList(rBrkPntList)
+ , m_aModifiedBreakPointList(rBrkPntList)
+ , m_xComboBox(m_xBuilder->weld_entry_tree_view("entriesgrid", "entries", "entrieslist"))
+ , m_xOKButton(m_xBuilder->weld_button("ok"))
+ , m_xNewButton(m_xBuilder->weld_button("new"))
+ , m_xDelButton(m_xBuilder->weld_button("delete"))
+ , m_xCheckBox(m_xBuilder->weld_check_button("active"))
+ , m_xNumericField(m_xBuilder->weld_spin_button("pass"))
+{
+ m_xComboBox->set_size_request(m_xComboBox->get_approximate_digit_width() * 20, -1);
+ m_xComboBox->set_height_request_by_rows(12);
+
+ m_xComboBox->freeze();
+ for (size_t i = 0, n = m_aModifiedBreakPointList.size(); i < n; ++i)
+ {
+ BreakPoint& rBrk = m_aModifiedBreakPointList.at(i);
+ OUString aEntryStr("# " + OUString::number(rBrk.nLine));
+ m_xComboBox->append_text(aEntryStr);
+ }
+ m_xComboBox->thaw();
+
+ m_xOKButton->connect_clicked(LINK(this, BreakPointDialog, ButtonHdl));
+ m_xNewButton->connect_clicked(LINK(this, BreakPointDialog, ButtonHdl));
+ m_xDelButton->connect_clicked(LINK(this, BreakPointDialog, ButtonHdl));
+
+ m_xCheckBox->connect_toggled(LINK(this, BreakPointDialog, CheckBoxHdl));
+ m_xComboBox->connect_changed(LINK(this, BreakPointDialog, EditModifyHdl));
+ m_xComboBox->connect_row_activated(LINK(this, BreakPointDialog, TreeModifyHdl));
+ m_xComboBox->grab_focus();
+
+ m_xNumericField->set_range(0, 0x7FFFFFFF);
+ m_xNumericField->set_increments(1, 10);
+ m_xNumericField->connect_value_changed(LINK(this, BreakPointDialog, FieldModifyHdl));
+
+ if (m_xComboBox->get_count())
+ m_xComboBox->set_active(0);
+
+ if (m_aModifiedBreakPointList.size())
+ UpdateFields(m_aModifiedBreakPointList.at(0));
+
+ CheckButtons();
+}
+
+BreakPointDialog::~BreakPointDialog() {}
+
+void BreakPointDialog::SetCurrentBreakPoint(BreakPoint const& rBrk)
+{
+ OUString aStr("# " + OUString::number(rBrk.nLine));
+ m_xComboBox->set_entry_text(aStr);
+ UpdateFields(rBrk);
+}
+
+void BreakPointDialog::CheckButtons()
+{
+ // "New" button is enabled if the combo box edit contains a valid line
+ // number that is not already present in the combo box list; otherwise
+ // "OK" and "Delete" buttons are enabled:
+ size_t nLine;
+ if (lcl_ParseText(m_xComboBox->get_active_text(), nLine)
+ && m_aModifiedBreakPointList.FindBreakPoint(nLine) == nullptr)
+ {
+ m_xNewButton->set_sensitive(true);
+ m_xOKButton->set_sensitive(false);
+ m_xDelButton->set_sensitive(false);
+ m_xDialog->change_default_widget(m_xDelButton.get(), m_xNewButton.get());
+ }
+ else
+ {
+ m_xNewButton->set_sensitive(false);
+ m_xOKButton->set_sensitive(true);
+ m_xDelButton->set_sensitive(true);
+ m_xDialog->change_default_widget(m_xNewButton.get(), m_xDelButton.get());
+ }
+}
+
+IMPL_LINK(BreakPointDialog, CheckBoxHdl, weld::Toggleable&, rButton, void)
+{
+ BreakPoint* pBrk = GetSelectedBreakPoint();
+ if (pBrk)
+ pBrk->bEnabled = rButton.get_active();
+}
+
+IMPL_LINK(BreakPointDialog, EditModifyHdl, weld::ComboBox&, rBox, void)
+{
+ CheckButtons();
+
+ int nEntry = rBox.find_text(rBox.get_active_text());
+ if (nEntry == -1)
+ return;
+ BreakPoint& rBrk = m_aModifiedBreakPointList.at(nEntry);
+ UpdateFields(rBrk);
+}
+
+IMPL_LINK(BreakPointDialog, FieldModifyHdl, weld::SpinButton&, rEdit, void)
+{
+ BreakPoint* pBrk = GetSelectedBreakPoint();
+ if (pBrk)
+ pBrk->nStopAfter = rEdit.get_value();
+}
+
+IMPL_LINK_NOARG(BreakPointDialog, TreeModifyHdl, weld::TreeView&, bool)
+{
+ if (m_xDelButton->get_sensitive())
+ ButtonHdl(*m_xDelButton);
+ return true;
+}
+
+IMPL_LINK(BreakPointDialog, ButtonHdl, weld::Button&, rButton, void)
+{
+ if (&rButton == m_xOKButton.get())
+ {
+ m_rOriginalBreakPointList.transfer(m_aModifiedBreakPointList);
+ m_xDialog->response(RET_OK);
+ }
+ else if (&rButton == m_xNewButton.get())
+ {
+ // keep checkbox in mind!
+ OUString aText(m_xComboBox->get_active_text());
+ size_t nLine;
+ bool bValid = lcl_ParseText(aText, nLine);
+ if (bValid)
+ {
+ BreakPoint aBrk(nLine);
+ aBrk.bEnabled = m_xCheckBox->get_active();
+ aBrk.nStopAfter = static_cast<size_t>(m_xNumericField->get_value());
+ m_aModifiedBreakPointList.InsertSorted(aBrk);
+ OUString aEntryStr("# " + OUString::number(aBrk.nLine));
+ m_xComboBox->append_text(aEntryStr);
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ pDispatcher->Execute(SID_BASICIDE_BRKPNTSCHANGED);
+ }
+ else
+ {
+ m_xComboBox->set_active_text(aText);
+ m_xComboBox->grab_focus();
+ }
+ CheckButtons();
+ }
+ else if (&rButton == m_xDelButton.get())
+ {
+ int nEntry = m_xComboBox->find_text(m_xComboBox->get_active_text());
+ if (nEntry != -1)
+ {
+ m_aModifiedBreakPointList.remove(nEntry);
+ m_xComboBox->remove(nEntry);
+ if (nEntry && nEntry >= m_xComboBox->get_count())
+ nEntry--;
+ m_xComboBox->set_active_text(m_xComboBox->get_text(nEntry));
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ pDispatcher->Execute(SID_BASICIDE_BRKPNTSCHANGED);
+ CheckButtons();
+ }
+ }
+}
+
+void BreakPointDialog::UpdateFields(BreakPoint const& rBrk)
+{
+ m_xCheckBox->set_active(rBrk.bEnabled);
+ m_xNumericField->set_value(rBrk.nStopAfter);
+}
+
+BreakPoint* BreakPointDialog::GetSelectedBreakPoint()
+{
+ int nEntry = m_xComboBox->find_text(m_xComboBox->get_active_text());
+ if (nEntry == -1)
+ return nullptr;
+ return &m_aModifiedBreakPointList.at(nEntry);
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/brkdlg.hxx b/basctl/source/basicide/brkdlg.hxx
new file mode 100644
index 000000000..89406d2c0
--- /dev/null
+++ b/basctl/source/basicide/brkdlg.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include "breakpoint.hxx"
+
+namespace basctl
+{
+class BreakPointDialog final : public weld::GenericDialogController
+{
+ BreakPointList& m_rOriginalBreakPointList;
+ BreakPointList m_aModifiedBreakPointList;
+
+ std::unique_ptr<weld::EntryTreeView> m_xComboBox;
+ std::unique_ptr<weld::Button> m_xOKButton;
+ std::unique_ptr<weld::Button> m_xNewButton;
+ std::unique_ptr<weld::Button> m_xDelButton;
+ std::unique_ptr<weld::CheckButton> m_xCheckBox;
+ std::unique_ptr<weld::SpinButton> m_xNumericField;
+
+ void CheckButtons();
+ DECL_LINK(CheckBoxHdl, weld::Toggleable&, void);
+ DECL_LINK(EditModifyHdl, weld::ComboBox&, void);
+ DECL_LINK(FieldModifyHdl, weld::SpinButton&, void);
+ DECL_LINK(ButtonHdl, weld::Button&, void);
+ DECL_LINK(TreeModifyHdl, weld::TreeView&, bool);
+ void UpdateFields(BreakPoint const& rBrk);
+ BreakPoint* GetSelectedBreakPoint();
+
+public:
+ BreakPointDialog(weld::Window* pParent, BreakPointList& rBrkList);
+ virtual ~BreakPointDialog() override;
+
+ void SetCurrentBreakPoint(BreakPoint const& rBrk);
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/doceventnotifier.cxx b/basctl/source/basicide/doceventnotifier.cxx
new file mode 100644
index 000000000..83d2ea04d
--- /dev/null
+++ b/basctl/source/basicide/doceventnotifier.cxx
@@ -0,0 +1,244 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <doceventnotifier.hxx>
+#include <scriptdocument.hxx>
+
+#include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
+
+#include <vcl/svapp.hxx>
+
+#include <tools/diagnose_ex.h>
+
+#include <comphelper/processfactory.hxx>
+
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+namespace basctl
+{
+
+ using ::com::sun::star::document::XDocumentEventBroadcaster;
+ using ::com::sun::star::document::XDocumentEventListener;
+ using ::com::sun::star::document::DocumentEvent;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::frame::theGlobalEventBroadcaster;
+ using ::com::sun::star::uno::UNO_QUERY;
+
+ // DocumentEventNotifier::Impl
+
+ typedef ::cppu::WeakComponentImplHelper< XDocumentEventListener
+ > DocumentEventNotifier_Impl_Base;
+
+ namespace {
+
+ enum ListenerAction
+ {
+ RegisterListener,
+ RemoveListener
+ };
+
+ }
+
+ /** impl class for DocumentEventNotifier
+ */
+ class DocumentEventNotifier::Impl :public ::cppu::BaseMutex
+ ,public DocumentEventNotifier_Impl_Base
+ {
+ public:
+ // noncopyable
+ Impl(const Impl&) = delete;
+ Impl& operator=(const Impl&) = delete;
+
+ Impl (DocumentEventListener&, Reference<XModel> const& rxDocument);
+ virtual ~Impl () override;
+
+ // XDocumentEventListener
+ virtual void SAL_CALL documentEventOccured( const DocumentEvent& Event ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Event ) override;
+
+ // ComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ private:
+ /// determines whether the instance is already disposed
+ bool impl_isDisposed_nothrow() const { return m_pListener == nullptr; }
+
+ /// disposes the instance
+ void impl_dispose_nothrow();
+
+ /// registers or revokes the instance as listener at the global event broadcaster
+ void impl_listenerAction_nothrow( ListenerAction _eAction );
+
+ private:
+ DocumentEventListener* m_pListener;
+ Reference< XModel > m_xModel;
+ };
+
+ DocumentEventNotifier::Impl::Impl (DocumentEventListener& rListener, Reference<XModel> const& rxDocument) :
+ DocumentEventNotifier_Impl_Base(m_aMutex),
+ m_pListener(&rListener),
+ m_xModel(rxDocument)
+ {
+ osl_atomic_increment( &m_refCount );
+ impl_listenerAction_nothrow( RegisterListener );
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ DocumentEventNotifier::Impl::~Impl ()
+ {
+ if ( !impl_isDisposed_nothrow() )
+ {
+ acquire();
+ dispose();
+ }
+ }
+
+ void SAL_CALL DocumentEventNotifier::Impl::documentEventOccured( const DocumentEvent& _rEvent )
+ {
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ OSL_PRECOND( !impl_isDisposed_nothrow(), "DocumentEventNotifier::Impl::notifyEvent: disposed, but still getting events?" );
+ if ( impl_isDisposed_nothrow() )
+ return;
+
+ Reference< XModel > xDocument( _rEvent.Source, UNO_QUERY );
+ OSL_ENSURE( xDocument.is(), "DocumentEventNotifier::Impl::notifyEvent: illegal source document!" );
+ if ( !xDocument.is() )
+ return;
+
+ struct EventEntry
+ {
+ const char* pEventName;
+ void (DocumentEventListener::*listenerMethod)( const ScriptDocument& _rDocument );
+ };
+ static EventEntry const aEvents[] = {
+ { "OnNew", &DocumentEventListener::onDocumentCreated },
+ { "OnLoad", &DocumentEventListener::onDocumentOpened },
+ { "OnSave", &DocumentEventListener::onDocumentSave },
+ { "OnSaveDone", &DocumentEventListener::onDocumentSaveDone },
+ { "OnSaveAs", &DocumentEventListener::onDocumentSaveAs },
+ { "OnSaveAsDone", &DocumentEventListener::onDocumentSaveAsDone },
+ { "OnUnload", &DocumentEventListener::onDocumentClosed },
+ { "OnTitleChanged", &DocumentEventListener::onDocumentTitleChanged },
+ { "OnModeChanged", &DocumentEventListener::onDocumentModeChanged }
+ };
+
+ for (EventEntry const & aEvent : aEvents)
+ {
+ if ( !_rEvent.EventName.equalsAscii( aEvent.pEventName ) )
+ continue;
+
+ ScriptDocument aDocument( xDocument );
+ {
+ // the listener implementations usually require the SolarMutex, so lock it here.
+ // But ensure the proper order of locking the solar and the own mutex
+ aGuard.clear();
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard2( m_aMutex );
+
+ if ( impl_isDisposed_nothrow() )
+ // somebody took the chance to dispose us -> bail out
+ return;
+
+ (m_pListener->*aEvent.listenerMethod)( aDocument );
+ }
+ break;
+ }
+ }
+
+ void SAL_CALL DocumentEventNotifier::Impl::disposing( const css::lang::EventObject& /*Event*/ )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !impl_isDisposed_nothrow() )
+ impl_dispose_nothrow();
+ }
+
+ void SAL_CALL DocumentEventNotifier::Impl::disposing()
+ {
+ impl_listenerAction_nothrow( RemoveListener );
+ impl_dispose_nothrow();
+ }
+
+ void DocumentEventNotifier::Impl::impl_dispose_nothrow()
+ {
+ m_pListener = nullptr;
+ m_xModel.clear();
+ }
+
+ void DocumentEventNotifier::Impl::impl_listenerAction_nothrow( ListenerAction _eAction )
+ {
+ try
+ {
+ Reference< XDocumentEventBroadcaster > xBroadcaster;
+ if ( m_xModel.is() )
+ xBroadcaster.set( m_xModel, UNO_QUERY_THROW );
+ else
+ {
+ Reference< css::uno::XComponentContext > aContext(
+ comphelper::getProcessComponentContext() );
+ xBroadcaster = theGlobalEventBroadcaster::get(aContext);
+ }
+
+ void ( SAL_CALL XDocumentEventBroadcaster::*listenerAction )( const Reference< XDocumentEventListener >& ) =
+ ( _eAction == RegisterListener ) ? &XDocumentEventBroadcaster::addDocumentEventListener : &XDocumentEventBroadcaster::removeDocumentEventListener;
+ (xBroadcaster.get()->*listenerAction)( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+
+ // DocumentEventNotifier
+
+ DocumentEventNotifier::DocumentEventNotifier (DocumentEventListener& rListener, Reference<XModel> const& rxDocument) :
+ m_pImpl(new Impl(rListener, rxDocument))
+ { }
+
+ DocumentEventNotifier::DocumentEventNotifier (DocumentEventListener& rListener) :
+ m_pImpl(new Impl(rListener, Reference<XModel>()))
+ { }
+
+ DocumentEventNotifier::~DocumentEventNotifier()
+ {
+ }
+
+ void DocumentEventNotifier::dispose()
+ {
+ m_pImpl->dispose();
+ }
+
+ // DocumentEventListener
+
+ DocumentEventListener::~DocumentEventListener()
+ {
+ }
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/docsignature.cxx b/basctl/source/basicide/docsignature.cxx
new file mode 100644
index 000000000..08d7a1ab9
--- /dev/null
+++ b/basctl/source/basicide/docsignature.cxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <docsignature.hxx>
+#include <scriptdocument.hxx>
+
+#include <sfx2/objsh.hxx>
+#include <sfx2/signaturestate.hxx>
+
+#include <osl/diagnose.h>
+
+
+namespace basctl
+{
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::frame::XModel;
+
+ // DocumentSignature
+
+ DocumentSignature::DocumentSignature (ScriptDocument const& rDocument) :
+ m_pShell(nullptr)
+ {
+ if (!rDocument.isDocument())
+ return;
+
+ Reference<XModel> xDocument(rDocument.getDocument());
+ // find object shell for document
+ SfxObjectShell* pShell = SfxObjectShell::GetFirst();
+ while ( pShell )
+ {
+ if ( pShell->GetModel() == xDocument )
+ break;
+ pShell = SfxObjectShell::GetNext( *pShell );
+ }
+ m_pShell = pShell;
+ }
+
+ bool DocumentSignature::supportsSignatures() const
+ {
+ return ( m_pShell != nullptr );
+ }
+
+ void DocumentSignature::signScriptingContent(weld::Window* pDialogParent) const
+ {
+ OSL_PRECOND( supportsSignatures(), "DocumentSignature::signScriptingContent: signatures not supported by this document!" );
+ if ( m_pShell )
+ m_pShell->SignScriptingContent(pDialogParent);
+ }
+
+ SignatureState DocumentSignature::getScriptingSignatureState() const
+ {
+ if ( m_pShell )
+ return m_pShell->GetScriptingSignatureState();
+ return SignatureState::NOSIGNATURES;
+ }
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/documentenumeration.cxx b/basctl/source/basicide/documentenumeration.cxx
new file mode 100644
index 000000000..e3acf9d45
--- /dev/null
+++ b/basctl/source/basicide/documentenumeration.cxx
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <set>
+
+#include "documentenumeration.hxx"
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XModel2.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+
+#include <tools/diagnose_ex.h>
+
+namespace basctl::docs {
+
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::frame::Desktop;
+ using ::com::sun::star::frame::XDesktop2;
+ using ::com::sun::star::container::XEnumeration;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::frame::XFrames;
+ using ::com::sun::star::frame::XController;
+ using ::com::sun::star::frame::XModel2;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::frame::XFrame;
+
+ namespace FrameSearchFlag = ::com::sun::star::frame::FrameSearchFlag;
+
+ // DocumentEnumeration_Data
+ struct DocumentEnumeration_Data
+ {
+ Reference< css::uno::XComponentContext > aContext;
+ const IDocumentDescriptorFilter* pFilter;
+
+ DocumentEnumeration_Data( Reference< css::uno::XComponentContext > const & _rContext, const IDocumentDescriptorFilter* _pFilter )
+ :aContext( _rContext )
+ ,pFilter( _pFilter )
+ {
+ }
+ };
+
+ // DocumentEnumeration
+ DocumentEnumeration::DocumentEnumeration( Reference< css::uno::XComponentContext > const & _rContext, const IDocumentDescriptorFilter* _pFilter )
+ :m_pData( new DocumentEnumeration_Data( _rContext, _pFilter ) )
+ {
+ }
+
+ DocumentEnumeration::~DocumentEnumeration()
+ {
+ }
+
+ namespace
+ {
+ void lcl_getDocumentControllers_nothrow( DocumentDescriptor& _io_rDocDesc )
+ {
+ OSL_PRECOND( _io_rDocDesc.xModel.is(), "lcl_getDocumentControllers_nothrow: illegal model!" );
+
+ _io_rDocDesc.aControllers.clear();
+ try
+ {
+ Reference< XModel2 > xModel2( _io_rDocDesc.xModel, UNO_QUERY );
+ if ( xModel2.is() )
+ {
+ Reference< XEnumeration > xEnum( xModel2->getControllers(), UNO_SET_THROW );
+ while ( xEnum->hasMoreElements() )
+ {
+ Reference< XController > xController( xEnum->nextElement(), UNO_QUERY_THROW );
+ _io_rDocDesc.aControllers.push_back( xController );
+ }
+ }
+ else if ( _io_rDocDesc.xModel.is() )
+ _io_rDocDesc.aControllers.push_back( _io_rDocDesc.xModel->getCurrentController() );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+
+ void lcl_getDocuments_nothrow( const Sequence< Reference< XFrame > >& _rFrames, Documents& _out_rDocuments,
+ const IDocumentDescriptorFilter* _pFilter )
+ {
+ // ensure we don't encounter some models multiple times
+ std::set< Reference< XModel > > aEncounteredModels;
+
+ for ( auto const & rFrame : _rFrames )
+ {
+ try
+ {
+ OSL_ENSURE( rFrame.is(), "lcl_getDocuments_nothrow: illegal frame!" );
+ if ( !rFrame.is() )
+ continue;
+ Reference< XController > xController( rFrame->getController() );
+ if ( !xController.is() )
+ continue;
+
+ Reference< XModel > xModel( xController->getModel() );
+ if ( !xModel.is() )
+ // though it's legal for a controller to not have a model, we're not interested in
+ // those
+ continue;
+
+ if ( !aEncounteredModels.insert( xModel ).second )
+ // there might be multiple frames for the same model
+ // handle it only once
+ continue;
+
+ // create a DocumentDescriptor
+ DocumentDescriptor aDescriptor;
+ aDescriptor.xModel = xModel;
+ lcl_getDocumentControllers_nothrow( aDescriptor );
+
+ // consult filter, if there is one
+ if ( _pFilter && !_pFilter->includeDocument( aDescriptor ) )
+ continue;
+
+ _out_rDocuments.push_back( aDescriptor );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+ }
+ }
+
+ void DocumentEnumeration::getDocuments( Documents& _out_rDocuments ) const
+ {
+ _out_rDocuments.clear();
+
+ try
+ {
+ const Reference< XDesktop2 > xDesktop = Desktop::create( m_pData->aContext );
+ const Reference< XFrames > xFrames( xDesktop->getFrames(), UNO_SET_THROW );
+ const Sequence< Reference< XFrame > > aFrames( xFrames->queryFrames( FrameSearchFlag::ALL ) );
+
+ lcl_getDocuments_nothrow( aFrames, _out_rDocuments, m_pData->pFilter );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+
+} // namespace basctl::docs
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/documentenumeration.hxx b/basctl/source/basicide/documentenumeration.hxx
new file mode 100644
index 000000000..084a4aa0c
--- /dev/null
+++ b/basctl/source/basicide/documentenumeration.hxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/frame/XController.hpp>
+#include <memory>
+#include <vector>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+
+namespace basctl::docs {
+
+
+ typedef std::vector< css::uno::Reference< css::frame::XController > > Controllers;
+
+ struct DocumentDescriptor
+ {
+ css::uno::Reference< css::frame::XModel > xModel;
+ Controllers aControllers;
+ };
+
+ typedef std::vector< DocumentDescriptor > Documents;
+
+
+ /// allows pre-filtering when enumerating document descriptors
+ class SAL_NO_VTABLE IDocumentDescriptorFilter
+ {
+ public:
+ virtual bool includeDocument( const DocumentDescriptor& _rDocument ) const = 0;
+
+ protected:
+ ~IDocumentDescriptorFilter() {}
+ };
+
+
+ struct DocumentEnumeration_Data;
+ /** is a helper class for enumerating documents in OOo
+
+ If you need a list of all open documents in OOo, this is little bit of
+ a hassle: You need to iterate though all components at the desktop, which
+ might or might not be documents.
+
+ Additionally, you need to examine the existing documents' frames
+ for sub frames, which might contain sub documents (e.g. embedded objects
+ edited out-place).
+
+ DocumentEnumeration relieves you from this hassle.
+ */
+ class DocumentEnumeration
+ {
+ public:
+ DocumentEnumeration( css::uno::Reference< css::uno::XComponentContext > const & _rContext, const IDocumentDescriptorFilter* _pFilter );
+ ~DocumentEnumeration();
+
+ /** retrieves a list of all currently known documents in the application
+
+ @param _out_rDocuments
+ output parameter taking the collected document information
+ @
+ */
+ void getDocuments(
+ Documents& _out_rDocuments
+ ) const;
+
+ private:
+ std::unique_ptr< DocumentEnumeration_Data > m_pData;
+ };
+
+
+} // namespace basctl::docs
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/iderdll.cxx b/basctl/source/basicide/iderdll.cxx
new file mode 100644
index 000000000..8e8a3dc3e
--- /dev/null
+++ b/basctl/source/basicide/iderdll.cxx
@@ -0,0 +1,206 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <comphelper/unique_disposing_ptr.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <iderdll.hxx>
+#include "iderdll2.hxx"
+#include <iderid.hxx>
+#include <basidesh.hxx>
+#include <basobj.hxx>
+#include "basdoc.hxx"
+#include "basicmod.hxx"
+
+#include <basic/sbstar.hxx>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/script/XLibraryContainerPassword.hpp>
+#include <unotools/resmgr.hxx>
+#include <sfx2/app.hxx>
+#include <osl/diagnose.h>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+class Dll
+{
+ Shell* m_pShell;
+ std::unique_ptr<ExtraData> m_xExtraData;
+
+public:
+ Dll ();
+
+ Shell* GetShell() const { return m_pShell; }
+ void SetShell (Shell* pShell) { m_pShell = pShell; }
+ ExtraData* GetExtraData ();
+};
+
+// Holds a basctl::Dll and release it on exit, or dispose of the
+//default XComponent, whichever comes first
+class DllInstance : public comphelper::unique_disposing_solar_mutex_reset_ptr<Dll>
+{
+public:
+ DllInstance() : comphelper::unique_disposing_solar_mutex_reset_ptr<Dll>(Reference<lang::XComponent>( frame::Desktop::create(comphelper::getProcessComponentContext()), UNO_QUERY_THROW), new Dll, true)
+ { }
+};
+
+struct theDllInstance : public rtl::Static<DllInstance, theDllInstance> { };
+
+} // namespace
+
+void EnsureIde ()
+{
+ // coverity[side_effect_free : FALSE] - not actually side-effect-free
+ theDllInstance::get();
+}
+
+Shell* GetShell ()
+{
+ if (Dll* pDll = theDllInstance::get().get())
+ return pDll->GetShell();
+ return nullptr;
+}
+
+void ShellCreated (Shell* pShell)
+{
+ Dll* pDll = theDllInstance::get().get();
+ if (pDll && !pDll->GetShell())
+ pDll->SetShell(pShell);
+}
+
+void ShellDestroyed (Shell const * pShell)
+{
+ Dll* pDll = theDllInstance::get().get();
+ if (pDll && pDll->GetShell() == pShell)
+ pDll->SetShell(nullptr);
+}
+
+ExtraData* GetExtraData()
+{
+ if (Dll* pDll = theDllInstance::get().get())
+ return pDll->GetExtraData();
+ return nullptr;
+}
+
+OUString IDEResId(TranslateId aId)
+{
+ return Translate::get(aId, SfxApplication::GetModule(SfxToolsModule::Basic)->GetResLocale());
+}
+
+namespace
+{
+
+Dll::Dll () :
+ m_pShell(nullptr)
+{
+ SfxObjectFactory& rFactory = DocShell::Factory();
+
+ auto pModule = std::make_unique<Module>("basctl", &rFactory);
+ SfxModule* pMod = pModule.get();
+ SfxApplication::SetModule(SfxToolsModule::Basic, std::move(pModule));
+
+ GetExtraData(); // to cause GlobalErrorHdl to be set
+
+ rFactory.SetDocumentServiceName( "com.sun.star.script.BasicIDE" );
+
+ DocShell::RegisterInterface( pMod );
+ Shell::RegisterFactory( SVX_INTERFACE_BASIDE_VIEWSH );
+ Shell::RegisterInterface( pMod );
+}
+
+ExtraData* Dll::GetExtraData ()
+{
+ if (!m_xExtraData)
+ m_xExtraData.reset(new ExtraData);
+ return m_xExtraData.get();
+}
+
+} // namespace
+
+
+// basctl::ExtraData
+
+
+ExtraData::ExtraData () :
+ m_aLastEntryDesc(EntryDescriptor()),
+ bChoosingMacro(false),
+ bShellInCriticalSection(false)
+{
+ StarBASIC::SetGlobalBreakHdl(LINK(this, ExtraData, GlobalBasicBreakHdl));
+}
+
+ExtraData::~ExtraData ()
+{
+ // Resetting ErrorHdl is cleaner indeed but this instance is destroyed
+ // pretty late, after the last Basic, anyway.
+ // Due to the call there is AppData created then though and not
+ // destroyed anymore => MLK's at Purify
+// StarBASIC::SetGlobalErrorHdl( Link() );
+// StarBASIC::SetGlobalBreakHdl( Link() );
+// StarBASIC::setGlobalStarScriptListener( XEngineListenerRef() );
+}
+
+IMPL_STATIC_LINK(ExtraData, GlobalBasicBreakHdl, StarBASIC *, pBasic, BasicDebugFlags)
+{
+ BasicDebugFlags nRet = BasicDebugFlags::NONE;
+ if (Shell* pShell = GetShell())
+ {
+ if (BasicManager* pBasMgr = FindBasicManager(pBasic))
+ {
+ // I do get here twice if Step into protected Basic
+ // => bad, if password query twice, also you don't see
+ // the lib in the PasswordDlg...
+ // => start no password query at this point
+ ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
+ OSL_ENSURE( aDocument.isValid(), "basctl::ExtraData::GlobalBasicBreakHdl: no document for the basic manager!" );
+ if ( aDocument.isValid() )
+ {
+ OUString aOULibName( pBasic->GetName() );
+ Reference< script::XLibraryContainer > xModLibContainer = aDocument.getLibraryContainer( E_SCRIPTS );
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) )
+ {
+ Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
+ if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aOULibName ) && !xPasswd->isLibraryPasswordVerified( aOULibName ) )
+ {
+ // a step-out should get me out of the protected area...
+ nRet = BasicDebugFlags::StepOut;
+ }
+ else
+ {
+ nRet = pShell->CallBasicBreakHdl( pBasic );
+ }
+ }
+ }
+ }
+ }
+
+ return nRet;
+}
+
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/iderdll2.hxx b/basctl/source/basicide/iderdll2.hxx
new file mode 100644
index 000000000..99534119f
--- /dev/null
+++ b/basctl/source/basicide/iderdll2.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+class StarBASIC;
+class SvxSearchItem;
+
+
+#include <bastypes.hxx>
+#include <bastype2.hxx>
+
+namespace basctl
+{
+
+class ExtraData final
+{
+ LibInfo aLibInfo;
+
+ EntryDescriptor m_aLastEntryDesc;
+
+ OUString aAddLibPath;
+ OUString aAddLibFilter;
+
+ bool bChoosingMacro;
+ bool bShellInCriticalSection;
+
+ DECL_STATIC_LINK( ExtraData, GlobalBasicBreakHdl, StarBASIC *, BasicDebugFlags );
+
+public:
+ ExtraData();
+ ~ExtraData();
+
+ LibInfo& GetLibInfo () { return aLibInfo; }
+
+ EntryDescriptor& GetLastEntryDescriptor () { return m_aLastEntryDesc; }
+ void SetLastEntryDescriptor (EntryDescriptor const & rDesc) { m_aLastEntryDesc = rDesc; }
+
+ bool& ChoosingMacro() { return bChoosingMacro; }
+ bool& ShellInCriticalSection() { return bShellInCriticalSection; }
+
+ const OUString& GetAddLibPath() const { return aAddLibPath; }
+ void SetAddLibPath( const OUString& rPath ) { aAddLibPath = rPath; }
+
+ const OUString& GetAddLibFilter() const { return aAddLibFilter; }
+ void SetAddLibFilter( const OUString& rFilter ) { aAddLibFilter = rFilter; }
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/layout.cxx b/basctl/source/basicide/layout.cxx
new file mode 100644
index 000000000..e6b6676ed
--- /dev/null
+++ b/basctl/source/basicide/layout.cxx
@@ -0,0 +1,430 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <layout.hxx>
+
+#include <bastypes.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/event.hxx>
+
+namespace basctl
+{
+
+namespace
+{
+// the thickness of the splitting lines
+tools::Long const nSplitThickness = 3;
+} // namespace
+
+// ctor for derived classes
+// pParent: the parent window (Shell)
+Layout::Layout (vcl::Window* pParent) :
+ Window(pParent, WB_CLIPCHILDREN),
+ pChild(nullptr),
+ bFirstSize(true),
+ aLeftSide(this, SplittedSide::Side::Left),
+ aBottomSide(this, SplittedSide::Side::Bottom)
+{
+ SetBackground(GetSettings().GetStyleSettings().GetWindowColor());
+
+ vcl::Font aFont = GetFont();
+ Size aSz = aFont.GetFontSize();
+ aSz.setHeight( aSz.Height() * 1.5 );
+ aFont.SetFontSize(aSz);
+ aFont.SetWeight(WEIGHT_BOLD);
+ aFont.SetColor(GetSettings().GetStyleSettings().GetWindowTextColor());
+ SetFont(aFont);
+}
+
+Layout::~Layout()
+{
+ disposeOnce();
+}
+
+void Layout::dispose()
+{
+ aLeftSide.dispose();
+ aBottomSide.dispose();
+ pChild.clear();
+ Window::dispose();
+}
+
+// removes a docking window
+void Layout::Remove (DockingWindow* pWin)
+{
+ aLeftSide.Remove(pWin);
+ aBottomSide.Remove(pWin);
+}
+
+// called by Window when resized
+void Layout::Resize()
+{
+ if (IsVisible())
+ ArrangeWindows();
+}
+
+// ArrangeWindows() -- arranges the child windows
+void Layout::ArrangeWindows ()
+{
+ // prevent recursion via OnFirstSize() -> Add() -> ArrangeWindows()
+ static bool bInArrangeWindows = false;
+ if (bInArrangeWindows)
+ return;
+ bInArrangeWindows = true;
+
+ Size const aSize = GetOutputSizePixel();
+ tools::Long const nWidth = aSize.Width(), nHeight = aSize.Height();
+ if (nWidth && nHeight) // non-empty size
+ {
+ // On first call the derived classes initializes the sizes of the
+ // docking windows. This cannot be done at construction because
+ // the Layout has empty size at that point.
+ if (bFirstSize)
+ {
+ bFirstSize = false;
+ OnFirstSize(nWidth, nHeight); // virtual
+ }
+
+ // sides
+ aBottomSide.ArrangeIn(tools::Rectangle(Point(0, 0), aSize));
+ aLeftSide.ArrangeIn(tools::Rectangle(Point(0, 0), Size(nWidth, nHeight - aBottomSide.GetSize())));
+ // child in the middle
+ pChild->SetPosSizePixel(
+ Point(aLeftSide.GetSize(), 0),
+ Size(nWidth - aLeftSide.GetSize(), nHeight - aBottomSide.GetSize())
+ );
+ }
+
+ bInArrangeWindows = false;
+}
+
+void Layout::Activating (BaseWindow& rWindow)
+{
+ // first activation
+ pChild = &rWindow;
+ ArrangeWindows();
+ Show();
+ pChild->Activating();
+}
+
+void Layout::Deactivating ()
+{
+ if (pChild)
+ pChild->Deactivating();
+ Hide();
+ pChild = nullptr;
+}
+
+// virtual
+void Layout::DataChanged (DataChangedEvent const& rDCEvt)
+{
+ Window::DataChanged(rDCEvt);
+ if (!(rDCEvt.GetType() == DataChangedEventType::SETTINGS && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)))
+ return;
+
+ bool bInvalidate = false;
+ Color aColor = GetSettings().GetStyleSettings().GetWindowColor();
+ const AllSettings* pOldSettings = rDCEvt.GetOldSettings();
+ if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetWindowColor())
+ {
+ SetBackground(Wallpaper(aColor));
+ bInvalidate = true;
+ }
+ aColor = GetSettings().GetStyleSettings().GetWindowTextColor();
+ if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetWindowTextColor())
+ {
+ vcl::Font aFont(GetFont());
+ aFont.SetColor(aColor);
+ SetFont(aFont);
+ bInvalidate = true;
+ }
+ if (bInvalidate)
+ Invalidate();
+}
+
+
+// SplittedSide
+
+
+// ctor
+Layout::SplittedSide::SplittedSide (Layout* pParent, Side eSide) :
+ rLayout(*pParent),
+ bVertical(eSide == Side::Left),
+ bLower(eSide == Side::Left),
+ nSize(0),
+ aSplitter(VclPtr<Splitter>::Create(pParent, bVertical ? WB_HSCROLL : WB_VSCROLL))
+{
+ InitSplitter(*aSplitter);
+}
+
+void Layout::SplittedSide::dispose()
+{
+ aSplitter.disposeAndClear();
+ for (auto & item : vItems)
+ {
+ item.pSplit.disposeAndClear();
+ item.pWin.clear();
+ }
+}
+
+// Add() -- adds a new window to the side (after construction)
+void Layout::SplittedSide::Add (DockingWindow* pWin, Size const& rSize)
+{
+ tools::Long const nSize1 = (bVertical ? rSize.Width() : rSize.Height()) + nSplitThickness;
+ tools::Long const nSize2 = bVertical ? rSize.Height() : rSize.Width();
+ // nSize
+ if (nSize1 > nSize)
+ nSize = nSize1;
+ // window
+ Item aItem;
+ aItem.pWin = pWin;
+ aItem.nStartPos = vItems.empty() ? 0 : vItems.back().nEndPos + nSplitThickness;
+ aItem.nEndPos = aItem.nStartPos + nSize2;
+ // splitter
+ if (!vItems.empty())
+ {
+ aItem.pSplit = VclPtr<Splitter>::Create(&rLayout, bVertical ? WB_VSCROLL : WB_HSCROLL);
+ aItem.pSplit->SetSplitPosPixel(aItem.nStartPos - nSplitThickness);
+ InitSplitter(*aItem.pSplit);
+ }
+ vItems.push_back(aItem);
+ // refresh
+ rLayout.ArrangeWindows();
+}
+
+// Remove() -- removes a window from the side (if contains)
+void Layout::SplittedSide::Remove (DockingWindow* pWin)
+{
+ // contains?
+ std::vector<Item>::size_type iWin;
+ for (iWin = 0; iWin != vItems.size(); ++iWin)
+ if (vItems[iWin].pWin == pWin)
+ break;
+ if (iWin == vItems.size())
+ return;
+ // remove
+ vItems[iWin].pSplit.disposeAndClear();
+ vItems[iWin].pWin.clear();
+ vItems.erase(vItems.begin() + iWin);
+ // if that was the first one, remove the first splitter line
+ if (iWin == 0 && !vItems.empty())
+ vItems.front().pSplit.reset();
+}
+
+// creating a Point or a Size object
+// The coordinate order depends on bVertical (reversed if true).
+inline Size Layout::SplittedSide::MakeSize (tools::Long A, tools::Long B) const
+{
+ return bVertical ? Size(B, A) : Size(A, B);
+}
+inline Point Layout::SplittedSide::MakePoint (tools::Long A, tools::Long B) const
+{
+ return bVertical ? Point(B, A) : Point(A, B);
+}
+
+// IsDocking() -- is this window currently docking in the strip?
+bool Layout::SplittedSide::IsDocking (DockingWindow const& rWin)
+{
+ return rWin.IsVisible() && !rWin.IsFloatingMode();
+}
+
+// IsEmpty() -- are there no windows docked in this strip?
+bool Layout::SplittedSide::IsEmpty () const
+{
+ for (auto const & i: vItems)
+ if (IsDocking(*i.pWin))
+ return false;
+ return true;
+}
+
+// GetSize() -- returns the width or height of the strip (depending on the direction)
+tools::Long Layout::SplittedSide::GetSize () const
+{
+ return IsEmpty() ? 0 : nSize;
+}
+
+// Arrange() -- arranges the docking windows
+// rRect: the available space
+void Layout::SplittedSide::ArrangeIn (tools::Rectangle const& rRect)
+{
+ // saving the rectangle
+ aRect = rRect;
+
+ // the length of the side
+ tools::Long const nLength = bVertical ? aRect.GetSize().Height() : aRect.GetSize().Width();
+ tools::Long const nOtherSize = bVertical ? aRect.GetSize().Width() : aRect.GetSize().Height();
+ // bVertical ? horizontal position : vertical position
+ tools::Long const nPos1 = (bVertical ? aRect.Left() : aRect.Top()) +
+ (bLower ? 0 : nOtherSize - (nSize - nSplitThickness));
+ // bVertical ? vertical position : horizontal position
+ tools::Long const nPos2 = bVertical ? aRect.Top() : aRect.Left();
+
+ // main line
+ bool const bEmpty = IsEmpty();
+ // shown if any of the windows is docked
+ if (!bEmpty)
+ {
+ aSplitter->Show();
+ // split position
+ aSplitter->SetSplitPosPixel((bLower ? nSize : nPos1) - nSplitThickness);
+ // the actual position and size
+ aSplitter->SetPosSizePixel(
+ MakePoint(nPos2, aSplitter->GetSplitPosPixel()),
+ MakeSize(nLength, nSplitThickness)
+ );
+ // dragging rectangle
+ aSplitter->SetDragRectPixel(aRect);
+ }
+ else
+ aSplitter->Hide();
+
+ // positioning separator lines and windows
+ bool bPrevDocking = false; // is the previous window docked?
+ tools::Long nStartPos = 0; // window position in the strip
+ std::vector<Item>::size_type iLastWin = vItems.size(); // index of last docking window in the strip
+
+ for (std::vector<Item>::size_type i = 0; i != vItems.size(); ++i)
+ {
+ // window
+ DockingWindow& rWin = *vItems[i].pWin;
+ bool const bDocking = IsDocking(rWin);
+ if (bDocking)
+ iLastWin = i;
+ // sizing window
+ rWin.ResizeIfDocking(
+ MakePoint(nPos2 + nStartPos, nPos1),
+ MakeSize(vItems[i].nEndPos - nStartPos, nSize - nSplitThickness)
+ );
+ // splitting line before the window
+ if (i > 0)
+ {
+ Splitter& rSplit = *vItems[i].pSplit;
+ // If neither of two adjacent windows are docked,
+ // the splitting line is hidden.
+ // If this window is docking but the previous isn't,
+ // then the splitting line is also hidden, because this window
+ // will occupy the space of the previous.
+ if (bPrevDocking)
+ {
+ rSplit.Show();
+ // the actual position and size of the line
+ rSplit.SetPosSizePixel(
+ MakePoint(nPos2 + nStartPos - nSplitThickness, nPos1),
+ MakeSize(nSplitThickness, nSize - nSplitThickness)
+ );
+ // the dragging rectangle
+ rSplit.SetDragRectPixel(tools::Rectangle(
+ MakePoint(nPos2, nPos1),
+ MakeSize(nLength, nSize - nSplitThickness)
+ ));
+ }
+ else
+ rSplit.Hide();
+ }
+ // next
+ bPrevDocking = bDocking;
+ if (bDocking)
+ nStartPos = vItems[i].nEndPos + nSplitThickness;
+ // We only set nStartPos if this window is docking, because otherwise
+ // the next window will occupy also the space of this window.
+ }
+
+ // filling the remaining space with the last docking window
+ if (bEmpty || vItems[iLastWin].nEndPos == nLength)
+ return;
+
+ Item& rItem = vItems[iLastWin];
+ Size aSize = rItem.pWin->GetDockingSize();
+ if (bVertical)
+ aSize.AdjustHeight( nLength - rItem.nEndPos );
+ else
+ aSize.AdjustWidth( nLength - rItem.nEndPos );
+ rItem.pWin->ResizeIfDocking(aSize);
+ // and hiding the split line after the window
+ if (iLastWin < vItems.size() - 1)
+ vItems[iLastWin + 1].pSplit->Hide();
+}
+
+IMPL_LINK(Layout::SplittedSide, SplitHdl, Splitter*, pSplitter, void)
+{
+ // checking margins
+ CheckMarginsFor(pSplitter);
+ // changing stored sizes
+ if (pSplitter == aSplitter.get())
+ {
+ // nSize
+ if (bLower)
+ nSize = pSplitter->GetSplitPosPixel();
+ else
+ nSize = (bVertical ? aRect.Right() : aRect.Bottom()) + 1 - pSplitter->GetSplitPosPixel();
+ }
+ else
+ {
+ // Item::nStartPos, Item::nLength
+ for (size_t i = 1; i < vItems.size(); ++i)
+ {
+ if (vItems[i].pSplit.get() == pSplitter)
+ {
+ // before the line
+ vItems[i - 1].nEndPos = pSplitter->GetSplitPosPixel();
+ // after the line
+ vItems[i].nStartPos = pSplitter->GetSplitPosPixel() + nSplitThickness;
+ }
+ }
+ }
+ // arranging windows
+ rLayout.ArrangeWindows();
+}
+
+void Layout::SplittedSide::CheckMarginsFor (Splitter* pSplitter)
+{
+ // The splitter line cannot be closer to the edges than nMargin pixels.
+ static tools::Long const nMargin = 16;
+ // Checking margins:
+ tools::Long const nLength = pSplitter->IsHorizontal() ?
+ aRect.GetWidth() : aRect.GetHeight();
+ if (!nLength)
+ return;
+
+ // bounds
+ tools::Long const nLower = (pSplitter->IsHorizontal() ? aRect.Left() : aRect.Top()) + nMargin;
+ tools::Long const nUpper = nLower + nLength - 2*nMargin;
+ // split position
+ tools::Long const nPos = pSplitter->GetSplitPosPixel();
+ // checking bounds
+ if (nPos < nLower)
+ pSplitter->SetSplitPosPixel(nLower);
+ if (nPos > nUpper)
+ pSplitter->SetSplitPosPixel(nUpper);
+}
+
+void Layout::SplittedSide::InitSplitter (Splitter& rSplitter)
+{
+ // link
+ rSplitter.SetSplitHdl(LINK(this, SplittedSide, SplitHdl));
+ // color
+ Color aColor = rLayout.GetSettings().GetStyleSettings().GetShadowColor();
+ rSplitter.GetOutDev()->SetLineColor(aColor);
+ rSplitter.GetOutDev()->SetFillColor(aColor);
+}
+
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/linenumberwindow.cxx b/basctl/source/basicide/linenumberwindow.cxx
new file mode 100644
index 000000000..7dcbff0dd
--- /dev/null
+++ b/basctl/source/basicide/linenumberwindow.cxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "baside2.hxx"
+
+#include <vcl/event.hxx>
+#include <vcl/textview.hxx>
+#include <vcl/xtextedt.hxx>
+#include <vcl/settings.hxx>
+
+namespace basctl
+{
+LineNumberWindow::LineNumberWindow(vcl::Window* pParent, ModulWindow* pModulWindow)
+ : Window(pParent, WB_BORDER)
+ , m_pModulWindow(pModulWindow)
+ , m_nCurYOffset(0)
+{
+ SetBackground(Wallpaper(GetSettings().GetStyleSettings().GetWindowColor()));
+ m_FontColor = GetSettings().GetStyleSettings().GetWindowTextColor();
+ m_nBaseWidth = GetTextWidth("8");
+ m_nWidth = m_nBaseWidth * 3 + m_nBaseWidth / 2;
+}
+
+LineNumberWindow::~LineNumberWindow() { disposeOnce(); }
+
+void LineNumberWindow::dispose()
+{
+ m_pModulWindow.clear();
+ Window::dispose();
+}
+
+void LineNumberWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ if (SyncYOffset())
+ return;
+
+ ExtTextEngine* txtEngine = m_pModulWindow->GetEditEngine();
+ if (!txtEngine)
+ return;
+
+ TextView* txtView = m_pModulWindow->GetEditView();
+ if (!txtView)
+ return;
+
+ GetParent()->Resize();
+
+ int windowHeight = rRenderContext.GetOutputSize().Height();
+ int nLineHeight = rRenderContext.GetTextHeight();
+ if (!nLineHeight)
+ {
+ return;
+ }
+
+ int startY = txtView->GetStartDocPos().Y();
+ const sal_uInt32 nStartLine = startY / nLineHeight + 1;
+ sal_uInt32 nEndLine = (startY + windowHeight) / nLineHeight + 1;
+
+ if (txtEngine->GetParagraphCount() + 1 < nEndLine)
+ nEndLine = txtEngine->GetParagraphCount() + 1;
+
+ // FIXME: it would be best if we could get notified of a font change
+ // rather than doing that re-calculation at each Paint event
+ m_nBaseWidth = GetTextWidth("8");
+
+ // reserve enough for 3 digit minimum, with a bit to spare for comfort
+ m_nWidth = m_nBaseWidth * 3 + m_nBaseWidth / 2;
+ auto nMaxLineNumber = std::max(nEndLine, txtEngine->GetParagraphCount() + 1);
+ sal_uInt32 i = (nMaxLineNumber + 1) / 1000;
+ while (i)
+ {
+ i /= 10;
+ m_nWidth += m_nBaseWidth;
+ }
+
+ sal_Int64 y = (nStartLine - 1) * static_cast<sal_Int64>(nLineHeight);
+ rRenderContext.SetTextColor(m_FontColor);
+ for (sal_uInt32 n = nStartLine; n <= nEndLine; ++n, y += nLineHeight)
+ rRenderContext.DrawText(Point(0, y - m_nCurYOffset), OUString::number(n));
+}
+
+void LineNumberWindow::DataChanged(DataChangedEvent const& rDCEvt)
+{
+ Window::DataChanged(rDCEvt);
+ if (rDCEvt.GetType() == DataChangedEventType::SETTINGS
+ && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
+ {
+ Color aColor(GetSettings().GetStyleSettings().GetFieldColor());
+ const AllSettings* pOldSettings = rDCEvt.GetOldSettings();
+ if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFieldColor())
+ {
+ SetBackground(Wallpaper(aColor));
+ Invalidate();
+ }
+ }
+}
+
+void LineNumberWindow::DoScroll(tools::Long nVertScroll)
+{
+ m_nCurYOffset -= nVertScroll;
+ Window::Scroll(0, nVertScroll);
+}
+
+bool LineNumberWindow::SyncYOffset()
+{
+ TextView* pView = m_pModulWindow->GetEditView();
+ if (!pView)
+ return false;
+
+ tools::Long nViewYOffset = pView->GetStartDocPos().Y();
+ if (m_nCurYOffset == nViewYOffset)
+ return false;
+
+ m_nCurYOffset = nViewYOffset;
+ Invalidate();
+ return true;
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/linenumberwindow.hxx b/basctl/source/basicide/linenumberwindow.hxx
new file mode 100644
index 000000000..a2e457f71
--- /dev/null
+++ b/basctl/source/basicide/linenumberwindow.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <vcl/window.hxx>
+
+namespace basctl
+{
+class ModulWindow;
+
+class LineNumberWindow : public vcl::Window
+{
+private:
+ VclPtr<ModulWindow> m_pModulWindow;
+ int m_nWidth;
+ tools::Long m_nCurYOffset;
+ int m_nBaseWidth;
+ Color m_FontColor;
+ virtual void DataChanged(DataChangedEvent const& rDCEvt) override;
+
+protected:
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+
+public:
+ LineNumberWindow(vcl::Window* pParent, ModulWindow* pModulWin);
+ virtual ~LineNumberWindow() override;
+ virtual void dispose() override;
+
+ void DoScroll(tools::Long nVertScroll);
+
+ bool SyncYOffset();
+ tools::Long& GetCurYOffset() { return m_nCurYOffset; }
+
+ int GetWidth() const { return m_nWidth; }
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/localizationmgr.cxx b/basctl/source/basicide/localizationmgr.cxx
new file mode 100644
index 000000000..18a19d6e7
--- /dev/null
+++ b/basctl/source/basicide/localizationmgr.cxx
@@ -0,0 +1,1129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <localizationmgr.hxx>
+
+#include <basidesh.hxx>
+#include <baside3.hxx>
+#include <basobj.hxx>
+#include <iderdll.hxx>
+#include <dlged.hxx>
+#include <managelang.hxx>
+
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/resource/MissingResourceException.hpp>
+#include <com/sun/star/resource/XStringResourceSupplier.hpp>
+#include <sfx2/bindings.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <tools/debug.hxx>
+#include <utility>
+#include <osl/diagnose.h>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::resource;
+
+namespace
+{
+
+constexpr OUStringLiteral aDot(u".");
+constexpr OUStringLiteral aEsc(u"&");
+constexpr OUStringLiteral aSemi(u";");
+
+} // namespace
+
+LocalizationMgr::LocalizationMgr(
+ Shell* pShell,
+ ScriptDocument aDocument,
+ OUString aLibName,
+ Reference<XStringResourceManager> const& xStringResourceManager
+) :
+ m_xStringResourceManager(xStringResourceManager),
+ m_pShell(pShell),
+ m_aDocument(std::move(aDocument)),
+ m_aLibName(std::move(aLibName))
+{ }
+
+bool LocalizationMgr::isLibraryLocalized ()
+{
+ if (m_xStringResourceManager.is())
+ return m_xStringResourceManager->getLocales().hasElements();
+ return false;
+}
+
+void LocalizationMgr::handleTranslationbar ()
+{
+ static constexpr OUStringLiteral aToolBarResName = u"private:resource/toolbar/translationbar";
+
+ Reference< beans::XPropertySet > xFrameProps
+ ( m_pShell->GetViewFrame()->GetFrame().GetFrameInterface(), uno::UNO_QUERY );
+ if ( !xFrameProps.is() )
+ return;
+
+ Reference< css::frame::XLayoutManager > xLayoutManager;
+ uno::Any a = xFrameProps->getPropertyValue( "LayoutManager" );
+ a >>= xLayoutManager;
+ if ( xLayoutManager.is() )
+ {
+ if ( !isLibraryLocalized() )
+ {
+ xLayoutManager->destroyElement( aToolBarResName );
+ }
+ else
+ {
+ xLayoutManager->createElement( aToolBarResName );
+ xLayoutManager->requestElement( aToolBarResName );
+ }
+ }
+}
+
+
+// TODO: -> export from toolkit
+
+
+static bool isLanguageDependentProperty( const OUString& aName )
+{
+ static struct Prop
+ {
+ const char* sName;
+ sal_Int32 nNameLength;
+ }
+ const vProp[] =
+ {
+ { "Text", 4 },
+ { "Label", 5 },
+ { "Title", 5 },
+ { "HelpText", 8 },
+ { "CurrencySymbol", 14 },
+ { "StringItemList", 14 },
+ { nullptr, 0 }
+ };
+
+ for (Prop const* pProp = vProp; pProp->sName; ++pProp)
+ if (aName.equalsAsciiL(pProp->sName, pProp->nNameLength))
+ return true;
+ return false;
+}
+
+
+void LocalizationMgr::implEnableDisableResourceForAllLibraryDialogs( HandleResourceMode eMode )
+{
+ Sequence< OUString > aDlgNames = m_aDocument.getObjectNames( E_DIALOGS, m_aLibName );
+ sal_Int32 nDlgCount = aDlgNames.getLength();
+ const OUString* pDlgNames = aDlgNames.getConstArray();
+
+ Reference< XStringResourceResolver > xDummyStringResolver;
+ for( sal_Int32 i = 0 ; i < nDlgCount ; i++ )
+ {
+ OUString aDlgName = pDlgNames[ i ];
+ if (VclPtr<DialogWindow> pWin = m_pShell->FindDlgWin(m_aDocument, m_aLibName, aDlgName))
+ {
+ Reference< container::XNameContainer > xDialog = pWin->GetDialog();
+ if( xDialog.is() )
+ {
+ // Handle dialog itself as control
+ Any aDialogCtrl;
+ aDialogCtrl <<= xDialog;
+ implHandleControlResourceProperties( aDialogCtrl, aDlgName,
+ std::u16string_view(), m_xStringResourceManager, xDummyStringResolver, eMode );
+
+ // Handle all controls
+ Sequence< OUString > aNames = xDialog->getElementNames();
+ const OUString* pNames = aNames.getConstArray();
+ sal_Int32 nCtrls = aNames.getLength();
+ for( sal_Int32 j = 0 ; j < nCtrls ; ++j )
+ {
+ OUString aCtrlName( pNames[j] );
+ Any aCtrl = xDialog->getByName( aCtrlName );
+ implHandleControlResourceProperties( aCtrl, aDlgName,
+ aCtrlName, m_xStringResourceManager, xDummyStringResolver, eMode );
+ }
+ }
+ }
+ }
+}
+
+
+static OUString implCreatePureResourceId
+ ( std::u16string_view aDialogName, std::u16string_view aCtrlName,
+ std::u16string_view aPropName,
+ const Reference< XStringResourceManager >& xStringResourceManager )
+{
+ sal_Int32 nUniqueId = xStringResourceManager->getUniqueNumericId();
+ OUString aPureIdStr = OUString::number( nUniqueId )
+ + aDot
+ + aDialogName
+ + aDot;
+ if( !aCtrlName.empty() )
+ {
+ aPureIdStr += aCtrlName + aDot;
+ }
+ aPureIdStr += aPropName;
+ return aPureIdStr;
+}
+
+// Works on xStringResourceManager's current language for SET_IDS/RESET_IDS,
+// anyway only one language should exist when calling this method then,
+// either the first one for mode SET_IDS or the last one for mode RESET_IDS
+sal_Int32 LocalizationMgr::implHandleControlResourceProperties
+ (const Any& rControlAny, std::u16string_view aDialogName, std::u16string_view aCtrlName,
+ const Reference< XStringResourceManager >& xStringResourceManager,
+ const Reference< XStringResourceResolver >& xSourceStringResolver, HandleResourceMode eMode )
+{
+ sal_Int32 nChangedCount = 0;
+
+ Reference< XPropertySet > xPropertySet;
+ rControlAny >>= xPropertySet;
+ if( xPropertySet.is() && xStringResourceManager.is())
+ {
+ Sequence< Locale > aLocaleSeq = xStringResourceManager->getLocales();
+ sal_Int32 nLocaleCount = aLocaleSeq.getLength();
+ if( nLocaleCount == 0 )
+ return 0;
+
+ Reference< XPropertySetInfo > xPropertySetInfo = xPropertySet->getPropertySetInfo();
+ if( xPropertySetInfo.is() )
+ {
+ // get sequence of control properties
+ Sequence< Property > aPropSeq = xPropertySetInfo->getProperties();
+ const Property* pProps = aPropSeq.getConstArray();
+ sal_Int32 nCtrlProps = aPropSeq.getLength();
+
+ // create a map of tab indices and control names, sorted by tab index
+ for( sal_Int32 j = 0 ; j < nCtrlProps ; ++j )
+ {
+ const Property& rProp = pProps[j];
+ OUString aPropName = rProp.Name;
+ TypeClass eType = rProp.Type.getTypeClass();
+ bool bLanguageDependentProperty =
+ (eType == TypeClass_STRING || eType == TypeClass_SEQUENCE)
+ && isLanguageDependentProperty( aPropName );
+ if( !bLanguageDependentProperty )
+ continue;
+
+ if( eType == TypeClass_STRING )
+ {
+ Any aPropAny = xPropertySet->getPropertyValue( aPropName );
+ OUString aPropStr;
+ aPropAny >>= aPropStr;
+
+ // Replace string by id, add id+string to StringResource
+ if( eMode == SET_IDS )
+ {
+ bool bEscAlreadyExisting = aPropStr.startsWith("&");
+ if( bEscAlreadyExisting )
+ continue;
+
+ OUString aPureIdStr = implCreatePureResourceId
+ ( aDialogName, aCtrlName, aPropName, xStringResourceManager );
+
+ // Set Id for all locales
+ const Locale* pLocales = aLocaleSeq.getConstArray();
+ for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ )
+ {
+ const Locale& rLocale = pLocales[ i ];
+ xStringResourceManager->setStringForLocale( aPureIdStr, aPropStr, rLocale );
+ }
+
+ OUString aPropIdStr = aEsc + aPureIdStr;
+ // TODO?: Change here and in toolkit
+ (void)aSemi;
+ xPropertySet->setPropertyValue( aPropName, Any(aPropIdStr) );
+ }
+ // Replace id by string from StringResource
+ else if( eMode == RESET_IDS )
+ {
+ if( aPropStr.getLength() > 1 )
+ {
+ OUString aPureIdStr = aPropStr.copy( 1 );
+ OUString aNewPropStr = aPropStr;
+ try
+ {
+ aNewPropStr = xStringResourceManager->resolveString( aPureIdStr );
+ }
+ catch(const MissingResourceException&)
+ {
+ }
+ xPropertySet->setPropertyValue( aPropName, Any(aNewPropStr) );
+ }
+ }
+ // Remove Id for all locales
+ else if( eMode == REMOVE_IDS_FROM_RESOURCE )
+ {
+ if( aPropStr.getLength() > 1 )
+ {
+ OUString aPureIdStr = aPropStr.copy( 1 );
+
+ const Locale* pLocales = aLocaleSeq.getConstArray();
+ for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ )
+ {
+ const Locale& rLocale = pLocales[ i ];
+ try
+ {
+ xStringResourceManager->removeIdForLocale( aPureIdStr, rLocale );
+ }
+ catch(const MissingResourceException&)
+ {
+ }
+ }
+ }
+ }
+ // Rename resource id
+ else if( eMode == RENAME_DIALOG_IDS || eMode == RENAME_CONTROL_IDS )
+ {
+ OUString aPureSourceIdStr = aPropStr.copy( 1 );
+
+ OUString aPureIdStr = implCreatePureResourceId
+ ( aDialogName, aCtrlName, aPropName, xStringResourceManager );
+
+ // Set new Id and remove old one for all locales
+ const Locale* pLocales = aLocaleSeq.getConstArray();
+ for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ )
+ {
+ const Locale& rLocale = pLocales[ i ];
+ try
+ {
+ OUString aResStr = xStringResourceManager->resolveStringForLocale
+ ( aPureSourceIdStr, rLocale );
+ xStringResourceManager->removeIdForLocale( aPureSourceIdStr, rLocale );
+ xStringResourceManager->setStringForLocale( aPureIdStr, aResStr, rLocale );
+ }
+ catch(const MissingResourceException&)
+ {}
+ }
+
+ OUString aPropIdStr = aEsc + aPureIdStr;
+ // TODO?: Change here and in toolkit
+ (void)aSemi;
+ xPropertySet->setPropertyValue( aPropName, Any(aPropIdStr) );
+ }
+ // Replace string by string from source StringResourceResolver
+ else if( eMode == MOVE_RESOURCES && xSourceStringResolver.is() )
+ {
+ OUString aPureSourceIdStr = aPropStr.copy( 1 );
+
+ OUString aPureIdStr = implCreatePureResourceId
+ ( aDialogName, aCtrlName, aPropName, xStringResourceManager );
+
+ const Locale& rDefaultLocale = xSourceStringResolver->getDefaultLocale();
+
+ // Set Id for all locales
+ const Locale* pLocales = aLocaleSeq.getConstArray();
+ for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ )
+ {
+ const Locale& rLocale = pLocales[ i ];
+ OUString aResStr;
+ try
+ {
+ aResStr = xSourceStringResolver->resolveStringForLocale
+ ( aPureSourceIdStr, rLocale );
+ }
+ catch(const MissingResourceException&)
+ {
+ aResStr = xSourceStringResolver->resolveStringForLocale
+ ( aPureSourceIdStr, rDefaultLocale );
+ }
+ xStringResourceManager->setStringForLocale( aPureIdStr, aResStr, rLocale );
+ }
+
+ OUString aPropIdStr = aEsc + aPureIdStr;
+ // TODO?: Change here and in toolkit
+ (void)aSemi;
+ xPropertySet->setPropertyValue( aPropName, Any(aPropIdStr) );
+ }
+ // Copy string from source to target resource
+ else if( eMode == COPY_RESOURCES && xSourceStringResolver.is() )
+ {
+ OUString aPureSourceIdStr = aPropStr.copy( 1 );
+
+ const Locale& rDefaultLocale = xSourceStringResolver->getDefaultLocale();
+
+ // Copy Id for all locales
+ const Locale* pLocales = aLocaleSeq.getConstArray();
+ for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ )
+ {
+ const Locale& rLocale = pLocales[ i ];
+ OUString aResStr;
+ try
+ {
+ aResStr = xSourceStringResolver->resolveStringForLocale
+ ( aPureSourceIdStr, rLocale );
+ }
+ catch(const MissingResourceException&)
+ {
+ aResStr = xSourceStringResolver->resolveStringForLocale
+ ( aPureSourceIdStr, rDefaultLocale );
+ }
+ xStringResourceManager->setStringForLocale( aPureSourceIdStr, aResStr, rLocale );
+ }
+ }
+ nChangedCount++;
+ }
+
+ // Listbox / Combobox
+ else if( eType == TypeClass_SEQUENCE )
+ {
+ Any aPropAny = xPropertySet->getPropertyValue( aPropName );
+ Sequence< OUString > aPropStrings;
+ aPropAny >>= aPropStrings;
+
+ const OUString* pPropStrings = aPropStrings.getConstArray();
+ sal_Int32 nPropStringCount = aPropStrings.getLength();
+ if( nPropStringCount == 0 )
+ continue;
+
+ // Replace string by id, add id+string to StringResource
+ if( eMode == SET_IDS )
+ {
+ Sequence< OUString > aIdStrings;
+ aIdStrings.realloc( nPropStringCount );
+ OUString* pIdStrings = aIdStrings.getArray();
+
+ OUString aIdStrBase = aDot
+ + aCtrlName
+ + aDot
+ + aPropName;
+
+ const Locale* pLocales = aLocaleSeq.getConstArray();
+ sal_Int32 i;
+ for ( i = 0; i < nPropStringCount; ++i )
+ {
+ OUString aPropStr = pPropStrings[i];
+ bool bEscAlreadyExisting = aPropStr.startsWith("&");
+ if( bEscAlreadyExisting )
+ {
+ pIdStrings[i] = aPropStr;
+ continue;
+ }
+
+ sal_Int32 nUniqueId = xStringResourceManager->getUniqueNumericId();
+ OUString aPureIdStr = OUString::number( nUniqueId )
+ + aIdStrBase;
+
+ // Set Id for all locales
+ for( sal_Int32 iLocale = 0 ; iLocale < nLocaleCount ; iLocale++ )
+ {
+ const Locale& rLocale = pLocales[ iLocale ];
+ xStringResourceManager->setStringForLocale( aPureIdStr, aPropStr, rLocale );
+ }
+
+ OUString aPropIdStr = aEsc + aPureIdStr;
+ pIdStrings[i] = aPropIdStr;
+ }
+ xPropertySet->setPropertyValue( aPropName, Any(aIdStrings) );
+ }
+ // Replace id by string from StringResource
+ else if( eMode == RESET_IDS )
+ {
+ Sequence< OUString > aNewPropStrings;
+ aNewPropStrings.realloc( nPropStringCount );
+ OUString* pNewPropStrings = aNewPropStrings.getArray();
+
+ sal_Int32 i;
+ for ( i = 0; i < nPropStringCount; ++i )
+ {
+ OUString aIdStr = pPropStrings[i];
+ OUString aNewPropStr = aIdStr;
+ if( aIdStr.getLength() > 1 )
+ {
+ OUString aPureIdStr = aIdStr.copy( 1 );
+ try
+ {
+ aNewPropStr = xStringResourceManager->resolveString( aPureIdStr );
+ }
+ catch(const MissingResourceException&)
+ {
+ }
+ }
+ pNewPropStrings[i] = aNewPropStr;
+ }
+ xPropertySet->setPropertyValue( aPropName, Any(aNewPropStrings) );
+ }
+ // Remove Id for all locales
+ else if( eMode == REMOVE_IDS_FROM_RESOURCE )
+ {
+ const Locale* pLocales = aLocaleSeq.getConstArray();
+ sal_Int32 i;
+ for ( i = 0; i < nPropStringCount; ++i )
+ {
+ OUString aIdStr = pPropStrings[i];
+ if( aIdStr.getLength() > 1 )
+ {
+ OUString aPureIdStr = aIdStr.copy( 1 );
+
+ for( sal_Int32 iLocale = 0 ; iLocale < nLocaleCount ; iLocale++ )
+ {
+ const Locale& rLocale = pLocales[iLocale];
+ try
+ {
+ xStringResourceManager->removeIdForLocale( aPureIdStr, rLocale );
+ }
+ catch(const MissingResourceException&)
+ {
+ }
+ }
+ }
+ }
+ }
+ // Rename resource id
+ else if( eMode == RENAME_CONTROL_IDS )
+ {
+ Sequence< OUString > aIdStrings;
+ aIdStrings.realloc( nPropStringCount );
+ OUString* pIdStrings = aIdStrings.getArray();
+
+ OUString aIdStrBase = aDot
+ + aCtrlName
+ + aDot
+ + aPropName;
+
+ const Locale* pLocales = aLocaleSeq.getConstArray();
+ sal_Int32 i;
+ for ( i = 0; i < nPropStringCount; ++i )
+ {
+ OUString aSourceIdStr = pPropStrings[i];
+ OUString aPureSourceIdStr = aSourceIdStr.copy( 1 );
+
+ sal_Int32 nUniqueId = xStringResourceManager->getUniqueNumericId();
+ OUString aPureIdStr = OUString::number( nUniqueId )
+ + aIdStrBase;
+
+ // Set Id for all locales
+ for( sal_Int32 iLocale = 0 ; iLocale < nLocaleCount ; iLocale++ )
+ {
+ const Locale& rLocale = pLocales[ iLocale ];
+
+ try
+ {
+ OUString aResStr = xStringResourceManager->resolveStringForLocale
+ ( aPureSourceIdStr, rLocale );
+ xStringResourceManager->removeIdForLocale( aPureSourceIdStr, rLocale );
+ xStringResourceManager->setStringForLocale( aPureIdStr, aResStr, rLocale );
+ }
+ catch(const MissingResourceException&)
+ {}
+ }
+
+ OUString aPropIdStr = aEsc + aPureIdStr;
+ pIdStrings[i] = aPropIdStr;
+ }
+ xPropertySet->setPropertyValue( aPropName, Any(aIdStrings) );
+ }
+ // Replace string by string from source StringResourceResolver
+ else if( eMode == MOVE_RESOURCES && xSourceStringResolver.is() )
+ {
+ Sequence< OUString > aIdStrings;
+ aIdStrings.realloc( nPropStringCount );
+ OUString* pIdStrings = aIdStrings.getArray();
+
+ OUString aIdStrBase = aDot
+ + aCtrlName
+ + aDot
+ + aPropName;
+
+ const Locale& rDefaultLocale = xSourceStringResolver->getDefaultLocale();
+
+ const Locale* pLocales = aLocaleSeq.getConstArray();
+ sal_Int32 i;
+ for ( i = 0; i < nPropStringCount; ++i )
+ {
+ OUString aSourceIdStr = pPropStrings[i];
+ OUString aPureSourceIdStr = aSourceIdStr.copy( 1 );
+
+ sal_Int32 nUniqueId = xStringResourceManager->getUniqueNumericId();
+ OUString aPureIdStr = OUString::number( nUniqueId )
+ + aIdStrBase;
+
+ // Set Id for all locales
+ for( sal_Int32 iLocale = 0 ; iLocale < nLocaleCount ; iLocale++ )
+ {
+ const Locale& rLocale = pLocales[ iLocale ];
+
+ OUString aResStr;
+ try
+ {
+ aResStr = xSourceStringResolver->resolveStringForLocale
+ ( aPureSourceIdStr, rLocale );
+ }
+ catch(const MissingResourceException&)
+ {
+ aResStr = xSourceStringResolver->resolveStringForLocale
+ ( aPureSourceIdStr, rDefaultLocale );
+ }
+ xStringResourceManager->setStringForLocale( aPureIdStr, aResStr, rLocale );
+ }
+
+ OUString aPropIdStr = aEsc + aPureIdStr;
+ pIdStrings[i] = aPropIdStr;
+ }
+ xPropertySet->setPropertyValue( aPropName, Any(aIdStrings) );
+ }
+ // Copy string from source to target resource
+ else if( eMode == COPY_RESOURCES && xSourceStringResolver.is() )
+ {
+ const Locale& rDefaultLocale = xSourceStringResolver->getDefaultLocale();
+
+ const Locale* pLocales = aLocaleSeq.getConstArray();
+ sal_Int32 i;
+ for ( i = 0; i < nPropStringCount; ++i )
+ {
+ OUString aSourceIdStr = pPropStrings[i];
+ OUString aPureSourceIdStr = aSourceIdStr.copy( 1 );
+
+ // Set Id for all locales
+ for( sal_Int32 iLocale = 0 ; iLocale < nLocaleCount ; iLocale++ )
+ {
+ const Locale& rLocale = pLocales[ iLocale ];
+
+ OUString aResStr;
+ try
+ {
+ aResStr = xSourceStringResolver->resolveStringForLocale
+ ( aPureSourceIdStr, rLocale );
+ }
+ catch(const MissingResourceException&)
+ {
+ aResStr = xSourceStringResolver->resolveStringForLocale
+ ( aPureSourceIdStr, rDefaultLocale );
+ }
+ xStringResourceManager->setStringForLocale( aPureSourceIdStr, aResStr, rLocale );
+ }
+ }
+ }
+ nChangedCount++;
+ }
+ }
+ }
+ }
+ return nChangedCount;
+}
+
+
+void LocalizationMgr::handleAddLocales( const Sequence< Locale >& aLocaleSeq )
+{
+ const Locale* pLocales = aLocaleSeq.getConstArray();
+ sal_Int32 nLocaleCount = aLocaleSeq.getLength();
+
+ if( isLibraryLocalized() )
+ {
+ for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ )
+ {
+ const Locale& rLocale = pLocales[ i ];
+ m_xStringResourceManager->newLocale( rLocale );
+ }
+ }
+ else
+ {
+ DBG_ASSERT( nLocaleCount==1, "LocalizationMgr::handleAddLocales(): Only one first locale allowed" );
+
+ const Locale& rLocale = pLocales[ 0 ];
+ m_xStringResourceManager->newLocale( rLocale );
+ enableResourceForAllLibraryDialogs();
+ }
+
+ MarkDocumentModified( m_aDocument );
+
+ // update locale toolbar
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG );
+
+ handleTranslationbar();
+}
+
+
+void LocalizationMgr::handleRemoveLocales( const Sequence< Locale >& aLocaleSeq )
+{
+ const Locale* pLocales = aLocaleSeq.getConstArray();
+ sal_Int32 nLocaleCount = aLocaleSeq.getLength();
+ bool bConsistent = true;
+ bool bModified = false;
+
+ for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ )
+ {
+ const Locale& rLocale = pLocales[ i ];
+ bool bRemove = true;
+
+ // Check if last locale
+ Sequence< Locale > aResLocaleSeq = m_xStringResourceManager->getLocales();
+ if( aResLocaleSeq.getLength() == 1 )
+ {
+ const Locale& rLastResLocale = aResLocaleSeq.getConstArray()[ 0 ];
+ if( localesAreEqual( rLocale, rLastResLocale ) )
+ {
+ disableResourceForAllLibraryDialogs();
+ }
+ else
+ {
+ // Inconsistency, keep last locale
+ bConsistent = false;
+ bRemove = false;
+ }
+ }
+
+ if( bRemove )
+ {
+ try
+ {
+ m_xStringResourceManager->removeLocale( rLocale );
+ bModified = true;
+ }
+ catch(const IllegalArgumentException&)
+ {
+ bConsistent = false;
+ }
+ }
+ }
+ if( bModified )
+ {
+ MarkDocumentModified( m_aDocument );
+
+ // update slots
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG );
+ pBindings->Invalidate( SID_BASICIDE_MANAGE_LANG );
+ }
+
+ handleTranslationbar();
+ }
+
+ DBG_ASSERT( bConsistent,
+ "LocalizationMgr::handleRemoveLocales(): sequence contains unsupported locales" );
+}
+
+void LocalizationMgr::handleSetDefaultLocale(const Locale& rLocale)
+{
+ if( !m_xStringResourceManager.is() )
+ return;
+
+ try
+ {
+ m_xStringResourceManager->setDefaultLocale(rLocale);
+ }
+ catch(const IllegalArgumentException&)
+ {
+ OSL_FAIL( "LocalizationMgr::handleSetDefaultLocale: Invalid locale" );
+ }
+
+ // update locale toolbar
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG );
+}
+
+void LocalizationMgr::handleSetCurrentLocale(const css::lang::Locale& rLocale)
+{
+ if( !m_xStringResourceManager.is() )
+ return;
+
+ try
+ {
+ m_xStringResourceManager->setCurrentLocale(rLocale, false);
+ }
+ catch(const IllegalArgumentException&)
+ {
+ OSL_FAIL( "LocalizationMgr::handleSetCurrentLocale: Invalid locale" );
+ }
+
+ // update locale toolbar
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG );
+
+ if (DialogWindow* pDlgWin = dynamic_cast<DialogWindow*>(m_pShell->GetCurWindow()))
+ if (!pDlgWin->IsSuspended())
+ pDlgWin->GetEditor().UpdatePropertyBrowserDelayed();
+}
+
+void LocalizationMgr::handleBasicStarted()
+{
+ if( m_xStringResourceManager.is() )
+ m_aLocaleBeforeBasicStart = m_xStringResourceManager->getCurrentLocale();
+}
+
+void LocalizationMgr::handleBasicStopped()
+{
+ try
+ {
+ if( m_xStringResourceManager.is() )
+ m_xStringResourceManager->setCurrentLocale( m_aLocaleBeforeBasicStart, true );
+ }
+ catch(const IllegalArgumentException&)
+ {
+ }
+}
+
+
+static DialogWindow* FindDialogWindowForEditor( DlgEditor const * pEditor )
+{
+ Shell::WindowTable const& aWindowTable = GetShell()->GetWindowTable();
+ for (auto const& window : aWindowTable)
+ {
+ BaseWindow* pWin = window.second;
+ if (!pWin->IsSuspended())
+ if (DialogWindow* pDlgWin = dynamic_cast<DialogWindow*>(pWin))
+ {
+ if (&pDlgWin->GetEditor() == pEditor)
+ return pDlgWin;
+ }
+ }
+ return nullptr;
+}
+
+
+void LocalizationMgr::setControlResourceIDsForNewEditorObject( DlgEditor const * pEditor,
+ const Any& rControlAny, std::u16string_view aCtrlName )
+{
+ // Get library for DlgEditor
+ DialogWindow* pDlgWin = FindDialogWindowForEditor( pEditor );
+ if( !pDlgWin )
+ return;
+ ScriptDocument aDocument( pDlgWin->GetDocument() );
+ DBG_ASSERT( aDocument.isValid(), "LocalizationMgr::setControlResourceIDsForNewEditorObject: invalid document!" );
+ if ( !aDocument.isValid() )
+ return;
+ const OUString& rLibName = pDlgWin->GetLibName();
+ Reference< container::XNameContainer > xDialogLib( aDocument.getLibrary( E_DIALOGS, rLibName, true ) );
+ Reference< XStringResourceManager > xStringResourceManager =
+ LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib );
+
+ // Set resource property
+ if( !xStringResourceManager.is() || !xStringResourceManager->getLocales().hasElements() )
+ return;
+
+ OUString aDialogName = pDlgWin->GetName();
+ Reference< XStringResourceResolver > xDummyStringResolver;
+ sal_Int32 nChangedCount = implHandleControlResourceProperties
+ ( rControlAny, aDialogName, aCtrlName, xStringResourceManager,
+ xDummyStringResolver, SET_IDS );
+
+ if( nChangedCount )
+ MarkDocumentModified( aDocument );
+}
+
+void LocalizationMgr::renameControlResourceIDsForEditorObject( DlgEditor const * pEditor,
+ const css::uno::Any& rControlAny, std::u16string_view aNewCtrlName )
+{
+ // Get library for DlgEditor
+ DialogWindow* pDlgWin = FindDialogWindowForEditor( pEditor );
+ if( !pDlgWin )
+ return;
+ ScriptDocument aDocument( pDlgWin->GetDocument() );
+ DBG_ASSERT( aDocument.isValid(), "LocalizationMgr::renameControlResourceIDsForEditorObject: invalid document!" );
+ if ( !aDocument.isValid() )
+ return;
+ const OUString& rLibName = pDlgWin->GetLibName();
+ Reference< container::XNameContainer > xDialogLib( aDocument.getLibrary( E_DIALOGS, rLibName, true ) );
+ Reference< XStringResourceManager > xStringResourceManager =
+ LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib );
+
+ // Set resource property
+ if( !xStringResourceManager.is() || !xStringResourceManager->getLocales().hasElements() )
+ return;
+
+ OUString aDialogName = pDlgWin->GetName();
+ Reference< XStringResourceResolver > xDummyStringResolver;
+ implHandleControlResourceProperties
+ ( rControlAny, aDialogName, aNewCtrlName, xStringResourceManager,
+ xDummyStringResolver, RENAME_CONTROL_IDS );
+}
+
+
+void LocalizationMgr::deleteControlResourceIDsForDeletedEditorObject( DlgEditor const * pEditor,
+ const Any& rControlAny, std::u16string_view aCtrlName )
+{
+ // Get library for DlgEditor
+ DialogWindow* pDlgWin = FindDialogWindowForEditor( pEditor );
+ if( !pDlgWin )
+ return;
+ ScriptDocument aDocument( pDlgWin->GetDocument() );
+ DBG_ASSERT( aDocument.isValid(), "LocalizationMgr::deleteControlResourceIDsForDeletedEditorObject: invalid document!" );
+ if ( !aDocument.isValid() )
+ return;
+ const OUString& rLibName = pDlgWin->GetLibName();
+ Reference< container::XNameContainer > xDialogLib( aDocument.getLibrary( E_DIALOGS, rLibName, true ) );
+ Reference< XStringResourceManager > xStringResourceManager =
+ LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib );
+
+ OUString aDialogName = pDlgWin->GetName();
+ Reference< XStringResourceResolver > xDummyStringResolver;
+ sal_Int32 nChangedCount = implHandleControlResourceProperties
+ ( rControlAny, aDialogName, aCtrlName, xStringResourceManager,
+ xDummyStringResolver, REMOVE_IDS_FROM_RESOURCE );
+
+ if( nChangedCount )
+ MarkDocumentModified( aDocument );
+}
+
+void LocalizationMgr::setStringResourceAtDialog( const ScriptDocument& rDocument, const OUString& aLibName,
+ std::u16string_view aDlgName, const Reference< container::XNameContainer >& xDialogModel )
+{
+ // Get library
+ Reference< container::XNameContainer > xDialogLib( rDocument.getLibrary( E_DIALOGS, aLibName, true ) );
+ Reference< XStringResourceManager > xStringResourceManager =
+ LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib );
+
+ // Set resource property
+ if( !xStringResourceManager.is() )
+ return;
+
+ // Not very elegant as dialog may or may not be localized yet
+ // TODO: Find better place, where dialog is created
+ if( xStringResourceManager->getLocales().hasElements() )
+ {
+ Any aDialogCtrl;
+ aDialogCtrl <<= xDialogModel;
+ Reference< XStringResourceResolver > xDummyStringResolver;
+ implHandleControlResourceProperties( aDialogCtrl, aDlgName,
+ std::u16string_view(), xStringResourceManager,
+ xDummyStringResolver, SET_IDS );
+ }
+
+ Reference< beans::XPropertySet > xDlgPSet( xDialogModel, UNO_QUERY );
+ xDlgPSet->setPropertyValue( "ResourceResolver", Any(xStringResourceManager) );
+}
+
+void LocalizationMgr::renameStringResourceIDs( const ScriptDocument& rDocument, const OUString& aLibName,
+ std::u16string_view aDlgName, const Reference< container::XNameContainer >& xDialogModel )
+{
+ // Get library
+ Reference< container::XNameContainer > xDialogLib( rDocument.getLibrary( E_DIALOGS, aLibName, true ) );
+ Reference< XStringResourceManager > xStringResourceManager =
+ LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib );
+ if( !xStringResourceManager.is() )
+ return;
+
+ Any aDialogCtrl;
+ aDialogCtrl <<= xDialogModel;
+ Reference< XStringResourceResolver > xDummyStringResolver;
+ implHandleControlResourceProperties( aDialogCtrl, aDlgName,
+ std::u16string_view(), xStringResourceManager,
+ xDummyStringResolver, RENAME_DIALOG_IDS );
+
+ // Handle all controls
+ Sequence< OUString > aNames = xDialogModel->getElementNames();
+ const OUString* pNames = aNames.getConstArray();
+ sal_Int32 nCtrls = aNames.getLength();
+ for( sal_Int32 i = 0 ; i < nCtrls ; ++i )
+ {
+ OUString aCtrlName( pNames[i] );
+ Any aCtrl = xDialogModel->getByName( aCtrlName );
+ implHandleControlResourceProperties( aCtrl, aDlgName,
+ aCtrlName, xStringResourceManager,
+ xDummyStringResolver, RENAME_DIALOG_IDS );
+ }
+}
+
+void LocalizationMgr::removeResourceForDialog( const ScriptDocument& rDocument, const OUString& aLibName,
+ std::u16string_view aDlgName, const Reference< container::XNameContainer >& xDialogModel )
+{
+ // Get library
+ Reference< container::XNameContainer > xDialogLib( rDocument.getLibrary( E_DIALOGS, aLibName, true ) );
+ Reference< XStringResourceManager > xStringResourceManager =
+ LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib );
+ if( !xStringResourceManager.is() )
+ return;
+
+ Any aDialogCtrl;
+ aDialogCtrl <<= xDialogModel;
+ Reference< XStringResourceResolver > xDummyStringResolver;
+ implHandleControlResourceProperties( aDialogCtrl, aDlgName,
+ std::u16string_view(), xStringResourceManager,
+ xDummyStringResolver, REMOVE_IDS_FROM_RESOURCE );
+
+ // Handle all controls
+ Sequence< OUString > aNames = xDialogModel->getElementNames();
+ const OUString* pNames = aNames.getConstArray();
+ sal_Int32 nCtrls = aNames.getLength();
+ for( sal_Int32 i = 0 ; i < nCtrls ; ++i )
+ {
+ OUString aCtrlName( pNames[i] );
+ Any aCtrl = xDialogModel->getByName( aCtrlName );
+ implHandleControlResourceProperties( aCtrl, aDlgName,
+ aCtrlName, xStringResourceManager,
+ xDummyStringResolver, REMOVE_IDS_FROM_RESOURCE );
+ }
+}
+
+void LocalizationMgr::resetResourceForDialog( const Reference< container::XNameContainer >& xDialogModel,
+ const Reference< XStringResourceManager >& xStringResourceManager )
+{
+ if( !xStringResourceManager.is() )
+ return;
+
+ // Dialog as control
+ std::u16string_view aDummyName;
+ Any aDialogCtrl;
+ aDialogCtrl <<= xDialogModel;
+ Reference< XStringResourceResolver > xDummyStringResolver;
+ implHandleControlResourceProperties( aDialogCtrl, aDummyName,
+ aDummyName, xStringResourceManager, xDummyStringResolver, RESET_IDS );
+
+ // Handle all controls
+ Sequence< OUString > aNames = xDialogModel->getElementNames();
+ const OUString* pNames = aNames.getConstArray();
+ sal_Int32 nCtrls = aNames.getLength();
+ for( sal_Int32 i = 0 ; i < nCtrls ; ++i )
+ {
+ OUString aCtrlName( pNames[i] );
+ Any aCtrl = xDialogModel->getByName( aCtrlName );
+ implHandleControlResourceProperties( aCtrl, aDummyName,
+ aCtrlName, xStringResourceManager, xDummyStringResolver, RESET_IDS );
+ }
+}
+
+void LocalizationMgr::setResourceIDsForDialog( const Reference< container::XNameContainer >& xDialogModel,
+ const Reference< XStringResourceManager >& xStringResourceManager )
+{
+ if( !xStringResourceManager.is() )
+ return;
+
+ // Dialog as control
+ std::u16string_view aDummyName;
+ Any aDialogCtrl;
+ aDialogCtrl <<= xDialogModel;
+ Reference< XStringResourceResolver > xDummyStringResolver;
+ implHandleControlResourceProperties( aDialogCtrl, aDummyName,
+ aDummyName, xStringResourceManager, xDummyStringResolver, SET_IDS );
+
+ // Handle all controls
+ Sequence< OUString > aNames = xDialogModel->getElementNames();
+ const OUString* pNames = aNames.getConstArray();
+ sal_Int32 nCtrls = aNames.getLength();
+ for( sal_Int32 i = 0 ; i < nCtrls ; ++i )
+ {
+ OUString aCtrlName( pNames[i] );
+ Any aCtrl = xDialogModel->getByName( aCtrlName );
+ implHandleControlResourceProperties( aCtrl, aDummyName,
+ aCtrlName, xStringResourceManager, xDummyStringResolver, SET_IDS );
+ }
+}
+
+void LocalizationMgr::copyResourcesForPastedEditorObject( DlgEditor const * pEditor,
+ const Any& rControlAny, std::u16string_view aCtrlName,
+ const Reference< XStringResourceResolver >& xSourceStringResolver )
+{
+ // Get library for DlgEditor
+ DialogWindow* pDlgWin = FindDialogWindowForEditor( pEditor );
+ if( !pDlgWin )
+ return;
+ ScriptDocument aDocument( pDlgWin->GetDocument() );
+ DBG_ASSERT( aDocument.isValid(), "LocalizationMgr::copyResourcesForPastedEditorObject: invalid document!" );
+ if ( !aDocument.isValid() )
+ return;
+ const OUString& rLibName = pDlgWin->GetLibName();
+ Reference< container::XNameContainer > xDialogLib( aDocument.getLibrary( E_DIALOGS, rLibName, true ) );
+ Reference< XStringResourceManager > xStringResourceManager =
+ LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib );
+
+ // Set resource property
+ if( !xStringResourceManager.is() || !xStringResourceManager->getLocales().hasElements() )
+ return;
+
+ OUString aDialogName = pDlgWin->GetName();
+ implHandleControlResourceProperties
+ ( rControlAny, aDialogName, aCtrlName, xStringResourceManager,
+ xSourceStringResolver, MOVE_RESOURCES );
+}
+
+void LocalizationMgr::copyResourceForDroppedDialog( const Reference< container::XNameContainer >& xDialogModel,
+ std::u16string_view aDialogName,
+ const Reference< XStringResourceManager >& xStringResourceManager,
+ const Reference< XStringResourceResolver >& xSourceStringResolver )
+{
+ if( !xStringResourceManager.is() )
+ return;
+
+ // Dialog as control
+ Any aDialogCtrl;
+ aDialogCtrl <<= xDialogModel;
+ implHandleControlResourceProperties( aDialogCtrl, aDialogName,
+ std::u16string_view(), xStringResourceManager, xSourceStringResolver, MOVE_RESOURCES );
+
+ // Handle all controls
+ Sequence< OUString > aNames = xDialogModel->getElementNames();
+ const OUString* pNames = aNames.getConstArray();
+ sal_Int32 nCtrls = aNames.getLength();
+ for( sal_Int32 i = 0 ; i < nCtrls ; ++i )
+ {
+ OUString aCtrlName( pNames[i] );
+ Any aCtrl = xDialogModel->getByName( aCtrlName );
+ implHandleControlResourceProperties( aCtrl, aDialogName,
+ aCtrlName, xStringResourceManager, xSourceStringResolver, MOVE_RESOURCES );
+ }
+}
+
+void LocalizationMgr::copyResourceForDialog(
+ const Reference< container::XNameContainer >& xDialogModel,
+ const Reference< XStringResourceResolver >& xSourceStringResolver,
+ const Reference< XStringResourceManager >& xTargetStringResourceManager )
+{
+ if( !xDialogModel.is() || !xSourceStringResolver.is() || !xTargetStringResourceManager.is() )
+ return;
+
+ std::u16string_view aDummyName;
+ Any aDialogCtrl;
+ aDialogCtrl <<= xDialogModel;
+ implHandleControlResourceProperties
+ ( aDialogCtrl, aDummyName, aDummyName, xTargetStringResourceManager,
+ xSourceStringResolver, COPY_RESOURCES );
+
+ // Handle all controls
+ Sequence< OUString > aNames = xDialogModel->getElementNames();
+ const OUString* pNames = aNames.getConstArray();
+ sal_Int32 nCtrls = aNames.getLength();
+ for( sal_Int32 i = 0 ; i < nCtrls ; ++i )
+ {
+ OUString aCtrlName( pNames[i] );
+ Any aCtrl = xDialogModel->getByName( aCtrlName );
+ implHandleControlResourceProperties( aCtrl, aDummyName, aDummyName,
+ xTargetStringResourceManager, xSourceStringResolver, COPY_RESOURCES );
+ }
+}
+
+Reference< XStringResourceManager > LocalizationMgr::getStringResourceFromDialogLibrary
+ ( const Reference< container::XNameContainer >& xDialogLib )
+{
+ Reference< XStringResourceManager > xStringResourceManager;
+ if( xDialogLib.is() )
+ {
+ Reference< resource::XStringResourceSupplier > xStringResourceSupplier( xDialogLib, UNO_QUERY );
+ if( xStringResourceSupplier.is() )
+ {
+ Reference< resource::XStringResourceResolver >
+ xStringResourceResolver = xStringResourceSupplier->getStringResource();
+
+ xStringResourceManager =
+ Reference< resource::XStringResourceManager >( xStringResourceResolver, UNO_QUERY );
+ }
+ }
+ return xStringResourceManager;
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/macrodlg.cxx b/basctl/source/basicide/macrodlg.cxx
new file mode 100644
index 000000000..63b487349
--- /dev/null
+++ b/basctl/source/basicide/macrodlg.cxx
@@ -0,0 +1,883 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "macrodlg.hxx"
+#include <basidesh.hxx>
+#include <strings.hrc>
+#include <iderid.hxx>
+
+#include <iderdll.hxx>
+#include "iderdll2.hxx"
+
+#include "moduldlg.hxx"
+#include <basic/basmgr.hxx>
+#include <basic/sbmeth.hxx>
+#include <basic/sbmod.hxx>
+#include <com/sun/star/script/XLibraryContainer2.hpp>
+#include <sal/log.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/minfitem.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <tools/debug.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <osl/diagnose.h>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+MacroChooser::MacroChooser(weld::Window* pParnt, const Reference< frame::XFrame >& xDocFrame)
+ : SfxDialogController(pParnt, "modules/BasicIDE/ui/basicmacrodialog.ui", "BasicMacroDialog")
+ , m_xDocumentFrame(xDocFrame)
+ // the Sfx doesn't ask the BasicManager whether modified or not
+ // => start saving in case of a change without a into the BasicIDE.
+ , bForceStoreBasic(false)
+ , nMode(All)
+ , m_xMacroNameEdit(m_xBuilder->weld_entry("macronameedit"))
+ , m_xMacroFromTxT(m_xBuilder->weld_label("macrofromft"))
+ , m_xMacrosSaveInTxt(m_xBuilder->weld_label("macrotoft"))
+ , m_xBasicBox(new SbTreeListBox(m_xBuilder->weld_tree_view("libraries"), m_xDialog.get()))
+ , m_xBasicBoxIter(m_xBasicBox->make_iterator())
+ , m_xMacrosInTxt(m_xBuilder->weld_label("existingmacrosft"))
+ , m_xMacroBox(m_xBuilder->weld_tree_view("macros"))
+ , m_xMacroBoxIter(m_xMacroBox->make_iterator())
+ , m_xRunButton(m_xBuilder->weld_button("ok"))
+ , m_xCloseButton(m_xBuilder->weld_button("close"))
+ , m_xAssignButton(m_xBuilder->weld_button("assign"))
+ , m_xEditButton(m_xBuilder->weld_button("edit"))
+ , m_xDelButton(m_xBuilder->weld_button("delete"))
+ , m_xNewButton(m_xBuilder->weld_button("new"))
+ , m_xOrganizeButton(m_xBuilder->weld_button("organize"))
+ , m_xNewLibButton(m_xBuilder->weld_button("newlibrary"))
+ , m_xNewModButton(m_xBuilder->weld_button("newmodule"))
+{
+ m_xBasicBox->set_size_request(m_xBasicBox->get_approximate_digit_width() * 30, m_xBasicBox->get_height_rows(18));
+ m_xMacroBox->set_size_request(m_xMacroBox->get_approximate_digit_width() * 30, m_xMacroBox->get_height_rows(18));
+
+ m_aMacrosInTxtBaseStr = m_xMacrosInTxt->get_label();
+
+ m_xRunButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
+ m_xCloseButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
+ m_xAssignButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
+ m_xEditButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
+ m_xDelButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
+ m_xNewButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
+ m_xOrganizeButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
+
+ // Buttons only for MacroChooser::Recording
+ m_xNewLibButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
+ m_xNewModButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
+ m_xNewLibButton->hide(); // default
+ m_xNewModButton->hide(); // default
+ m_xMacrosSaveInTxt->hide(); // default
+
+ m_xMacroNameEdit->connect_changed( LINK( this, MacroChooser, EditModifyHdl ) );
+
+ m_xBasicBox->connect_changed( LINK( this, MacroChooser, BasicSelectHdl ) );
+
+ m_xMacroBox->connect_row_activated( LINK( this, MacroChooser, MacroDoubleClickHdl ) );
+ m_xMacroBox->connect_changed( LINK( this, MacroChooser, MacroSelectHdl ) );
+ m_xMacroBox->connect_popup_menu( LINK( this, MacroChooser, ContextMenuHdl ) );
+
+ m_xBasicBox->SetMode( BrowseMode::Modules );
+
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES );
+
+ m_xBasicBox->ScanAllEntries();
+}
+
+MacroChooser::~MacroChooser()
+{
+ if (bForceStoreBasic)
+ {
+ SfxGetpApp()->SaveBasicAndDialogContainer();
+ bForceStoreBasic = false;
+ }
+}
+
+void MacroChooser::StoreMacroDescription()
+{
+ if (!m_xBasicBox->get_selected(m_xBasicBoxIter.get()))
+ return;
+ EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
+ OUString aMethodName;
+ if (m_xMacroBox->get_selected(m_xMacroBoxIter.get()))
+ aMethodName = m_xMacroBox->get_text(*m_xMacroBoxIter);
+ else
+ aMethodName = m_xMacroNameEdit->get_text();
+ if ( !aMethodName.isEmpty() )
+ {
+ aDesc.SetMethodName( aMethodName );
+ aDesc.SetType( OBJ_TYPE_METHOD );
+ }
+
+ if (ExtraData* pData = basctl::GetExtraData())
+ pData->SetLastEntryDescriptor( aDesc );
+}
+
+void MacroChooser::RestoreMacroDescription()
+{
+ EntryDescriptor aDesc;
+ if (Shell* pShell = GetShell())
+ {
+ if (BaseWindow* pCurWin = pShell->GetCurWindow())
+ aDesc = pCurWin->CreateEntryDescriptor();
+ }
+ else
+ {
+ if (ExtraData* pData = basctl::GetExtraData())
+ aDesc = pData->GetLastEntryDescriptor();
+ }
+
+ // No valid EntryDescriptor found
+ if (aDesc.GetMethodName().isEmpty())
+ {
+ m_xMacroNameEdit->select_region(0, 0);
+ return;
+ }
+
+ m_xBasicBox->SetCurrentEntry(aDesc);
+ BasicSelectHdl(m_xBasicBox->get_widget());
+
+ OUString aLastMacro( aDesc.GetMethodName() );
+ if (!aLastMacro.isEmpty())
+ {
+ // find entry in macro box
+ auto nIndex = m_xMacroBox->find_text(aLastMacro);
+ if (nIndex != -1)
+ m_xMacroBox->select(nIndex);
+ else
+ {
+ m_xMacroNameEdit->set_text(aLastMacro);
+ m_xMacroNameEdit->select_region(0, 0);
+ }
+ }
+}
+
+short MacroChooser::run()
+{
+ RestoreMacroDescription();
+
+ // #104198 Check if "wrong" document is active
+ bool bSelectedEntry = m_xBasicBox->get_cursor(m_xBasicBoxIter.get());
+ EntryDescriptor aDesc(m_xBasicBox->GetEntryDescriptor(bSelectedEntry ? m_xBasicBoxIter.get() : nullptr));
+ const ScriptDocument& rSelectedDoc(aDesc.GetDocument());
+
+ // App Basic is always ok, so only check if shell was found
+ if( rSelectedDoc.isDocument() && !rSelectedDoc.isActive() )
+ {
+ // Search for the right entry
+ bool bValidIter = m_xBasicBox->get_iter_first(*m_xBasicBoxIter);
+ while (bValidIter)
+ {
+ EntryDescriptor aCmpDesc(m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get()));
+ const ScriptDocument& rCmpDoc( aCmpDesc.GetDocument() );
+ if (rCmpDoc.isDocument() && rCmpDoc.isActive())
+ {
+ std::unique_ptr<weld::TreeIter> xEntry(m_xBasicBox->make_iterator());
+ m_xBasicBox->copy_iterator(*m_xBasicBoxIter, *xEntry);
+ std::unique_ptr<weld::TreeIter> xLastValid(m_xBasicBox->make_iterator());
+ bool bValidEntryIter = true;
+ do
+ {
+ m_xBasicBox->copy_iterator(*xEntry, *xLastValid);
+ bValidEntryIter = m_xBasicBox->iter_children(*xEntry);
+ }
+ while (bValidEntryIter);
+ m_xBasicBox->set_cursor(*xLastValid);
+ }
+ bValidIter = m_xBasicBox->iter_next_sibling(*m_xBasicBoxIter);
+ }
+ }
+
+ CheckButtons();
+ UpdateFields();
+
+ // tdf#62955 - Allow searching a name with typing the first letter
+ m_xBasicBox->get_widget().grab_focus();
+
+ if ( StarBASIC::IsRunning() )
+ m_xCloseButton->grab_focus();
+
+ return SfxDialogController::run();
+}
+
+void MacroChooser::EnableButton(weld::Button& rButton, bool bEnable)
+{
+ if ( bEnable )
+ {
+ if (nMode == ChooseOnly || nMode == Recording)
+ rButton.set_sensitive(&rButton == m_xRunButton.get());
+ else
+ rButton.set_sensitive(true);
+ }
+ else
+ rButton.set_sensitive(false);
+}
+
+SbMethod* MacroChooser::GetMacro()
+{
+ if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()))
+ return nullptr;
+ SbModule* pModule = m_xBasicBox->FindModule(m_xBasicBoxIter.get());
+ if (!pModule)
+ return nullptr;
+ if (!m_xMacroBox->get_selected(m_xMacroBoxIter.get()))
+ return nullptr;
+ OUString aMacroName(m_xMacroBox->get_text(*m_xMacroBoxIter));
+ return pModule->FindMethod(aMacroName, SbxClassType::Method);
+}
+
+void MacroChooser::DeleteMacro()
+{
+ SbMethod* pMethod = GetMacro();
+ DBG_ASSERT( pMethod, "DeleteMacro: No Macro !" );
+ if (!(pMethod && QueryDelMacro(pMethod->GetName(), m_xDialog.get())))
+ return;
+
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES );
+
+ // mark current doc as modified:
+ StarBASIC* pBasic = FindBasic(pMethod);
+ assert(pBasic && "Basic?!");
+ BasicManager* pBasMgr = FindBasicManager( pBasic );
+ DBG_ASSERT( pBasMgr, "BasMgr?" );
+ ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
+ if ( aDocument.isDocument() )
+ {
+ aDocument.setDocumentModified();
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_SAVEDOC );
+ }
+
+ SbModule* pModule = pMethod->GetModule();
+ assert(pModule && "DeleteMacro: No Module?!");
+ OUString aSource( pModule->GetSource32() );
+ sal_uInt16 nStart, nEnd;
+ pMethod->GetLineRange( nStart, nEnd );
+ pModule->GetMethods()->Remove( pMethod );
+ CutLines( aSource, nStart-1, nEnd-nStart+1 );
+ pModule->SetSource32( aSource );
+
+ // update module in library
+ OUString aLibName = pBasic->GetName();
+ OUString aModName = pModule->GetName();
+ OSL_VERIFY( aDocument.updateModule( aLibName, aModName, aSource ) );
+
+ bool bSelected = m_xMacroBox->get_selected(m_xMacroBoxIter.get());
+ DBG_ASSERT(bSelected, "DeleteMacro: Entry ?!");
+ m_xMacroBox->remove(*m_xMacroBoxIter);
+ bForceStoreBasic = true;
+}
+
+SbMethod* MacroChooser::CreateMacro()
+{
+ SbMethod* pMethod = nullptr;
+ if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter))
+ {
+ SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback");
+ return nullptr;
+ }
+ EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
+ const ScriptDocument& aDocument( aDesc.GetDocument() );
+ OSL_ENSURE( aDocument.isAlive(), "MacroChooser::CreateMacro: no document!" );
+ if ( !aDocument.isAlive() )
+ return nullptr;
+
+ OUString aLibName( aDesc.GetLibName() );
+
+ if ( aLibName.isEmpty() )
+ aLibName = "Standard" ;
+
+ aDocument.getOrCreateLibrary( E_SCRIPTS, aLibName );
+
+ OUString aOULibName( aLibName );
+ Reference< script::XLibraryContainer > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) );
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) && !xModLibContainer->isLibraryLoaded( aOULibName ) )
+ xModLibContainer->loadLibrary( aOULibName );
+ Reference< script::XLibraryContainer > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ) );
+ if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aOULibName ) && !xDlgLibContainer->isLibraryLoaded( aOULibName ) )
+ xDlgLibContainer->loadLibrary( aOULibName );
+
+ BasicManager* pBasMgr = aDocument.getBasicManager();
+ StarBASIC* pBasic = pBasMgr ? pBasMgr->GetLib( aLibName ) : nullptr;
+ if ( pBasic )
+ {
+ SbModule* pModule = nullptr;
+ OUString aModName( aDesc.GetName() );
+ if ( !aModName.isEmpty() )
+ {
+ // extract the module name from the string like "Sheet1 (Example1)"
+ if( aDesc.GetLibSubName() == IDEResId(RID_STR_DOCUMENT_OBJECTS) )
+ {
+ aModName = aModName.getToken( 0, ' ' );
+ }
+ pModule = pBasic->FindModule( aModName );
+ }
+ else if ( !pBasic->GetModules().empty() )
+ pModule = pBasic->GetModules().front().get();
+
+ // Retain the desired macro name before the macro dialog box is forced to close
+ // by opening the module name dialog window when no module exists in the current library.
+ OUString aSubName = m_xMacroNameEdit->get_text();
+
+ if ( !pModule )
+ {
+ pModule = createModImpl(m_xDialog.get(), aDocument, *m_xBasicBox, aLibName, aModName, false);
+ }
+
+ DBG_ASSERT( !pModule || !pModule->FindMethod( aSubName, SbxClassType::Method ), "Macro exists already!" );
+ pMethod = pModule ? basctl::CreateMacro( pModule, aSubName ) : nullptr;
+ }
+
+ return pMethod;
+}
+
+void MacroChooser::SaveSetCurEntry(weld::TreeView& rBox, const weld::TreeIter& rEntry)
+{
+ // the edit would be killed by the highlight otherwise:
+
+ OUString aSaveText(m_xMacroNameEdit->get_text());
+ int nStartPos, nEndPos;
+ m_xMacroNameEdit->get_selection_bounds(nStartPos, nEndPos);
+
+ rBox.set_cursor(rEntry);
+
+ m_xMacroNameEdit->set_text(aSaveText);
+ m_xMacroNameEdit->select_region(nStartPos, nEndPos);
+}
+
+void MacroChooser::CheckButtons()
+{
+ const bool bCurEntry = m_xBasicBox->get_cursor(m_xBasicBoxIter.get());
+ EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(bCurEntry ? m_xBasicBoxIter.get() : nullptr);
+ const bool bMacroEntry = m_xMacroBox->get_selected(nullptr);
+ SbMethod* pMethod = GetMacro();
+
+ // check, if corresponding libraries are readonly
+ bool bReadOnly = false;
+ sal_uInt16 nDepth = bCurEntry ? m_xBasicBox->get_iter_depth(*m_xBasicBoxIter) : 0;
+ if ( nDepth == 1 || nDepth == 2 )
+ {
+ const ScriptDocument& aDocument( aDesc.GetDocument() );
+ const OUString& aOULibName( aDesc.GetLibName() );
+ Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ Reference< script::XLibraryContainer2 > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+ if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) && xModLibContainer->isLibraryReadOnly( aOULibName ) ) ||
+ ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aOULibName ) && xDlgLibContainer->isLibraryReadOnly( aOULibName ) ) )
+ {
+ bReadOnly = true;
+ }
+ }
+
+ if (nMode != Recording)
+ {
+ // Run...
+ bool bEnable = pMethod != nullptr;
+ if (nMode != ChooseOnly && StarBASIC::IsRunning())
+ bEnable = false;
+ EnableButton(*m_xRunButton, bEnable);
+ }
+
+ // organising still possible?
+
+ // Assign...
+ EnableButton(*m_xAssignButton, pMethod != nullptr);
+
+ // Edit...
+ EnableButton(*m_xEditButton, bMacroEntry);
+
+ // Organizer...
+ EnableButton(*m_xOrganizeButton, !StarBASIC::IsRunning() && nMode == All);
+
+ // m_xDelButton/m_xNewButton ->...
+ bool bProtected = bCurEntry && m_xBasicBox->IsEntryProtected(m_xBasicBoxIter.get());
+ bool bShare = ( aDesc.GetLocation() == LIBRARY_LOCATION_SHARE );
+ bool bEnable = !StarBASIC::IsRunning() && nMode == All && !bProtected && !bReadOnly && !bShare;
+ EnableButton(*m_xDelButton, bEnable);
+ EnableButton(*m_xNewButton, bEnable);
+ if (nMode == All)
+ {
+ if (pMethod)
+ {
+ m_xDelButton->show();
+ m_xNewButton->hide();
+ }
+ else
+ {
+ m_xNewButton->show();
+ m_xDelButton->hide();
+ }
+ }
+
+ if (nMode == Recording)
+ {
+ // save button
+ m_xRunButton->set_sensitive(!bProtected && !bReadOnly && !bShare);
+ // new library button
+ m_xNewLibButton->set_sensitive(!bShare);
+ // new module button
+ m_xNewModButton->set_sensitive(!bProtected && !bReadOnly && !bShare);
+ }
+}
+
+IMPL_LINK_NOARG(MacroChooser, MacroDoubleClickHdl, weld::TreeView&, bool)
+{
+ SbMethod* pMethod = GetMacro();
+ SbModule* pModule = pMethod ? pMethod->GetModule() : nullptr;
+ StarBASIC* pBasic = pModule ? static_cast<StarBASIC*>(pModule->GetParent()) : nullptr;
+ BasicManager* pBasMgr = pBasic ? FindBasicManager(pBasic) : nullptr;
+ ScriptDocument aDocument(ScriptDocument::getDocumentForBasicManager(pBasMgr));
+ if (aDocument.isDocument() && !aDocument.allowMacros())
+ {
+ std::unique_ptr<weld::MessageDialog> xError(
+ Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Warning,
+ VclButtonsType::Ok, IDEResId(RID_STR_CANNOTRUNMACRO)));
+ xError->run();
+ return true;
+ }
+
+ StoreMacroDescription();
+ if (nMode == Recording)
+ {
+ if (pMethod && !QueryReplaceMacro(pMethod->GetName(), m_xDialog.get()))
+ return true;
+ }
+
+ m_xDialog->response(Macro_OkRun);
+ return true;
+}
+
+IMPL_LINK_NOARG(MacroChooser, MacroSelectHdl, weld::TreeView&, void)
+{
+ UpdateFields();
+ CheckButtons();
+}
+
+IMPL_LINK_NOARG(MacroChooser, BasicSelectHdl, weld::TreeView&, void)
+{
+ SbModule* pModule = nullptr;
+ if (m_xBasicBox->get_cursor(m_xBasicBoxIter.get()))
+ pModule = m_xBasicBox->FindModule(m_xBasicBoxIter.get());
+ m_xMacroBox->clear();
+ if (pModule)
+ {
+ m_xMacrosInTxt->set_label(m_aMacrosInTxtBaseStr + " " + pModule->GetName());
+
+ m_xMacroBox->freeze();
+
+ sal_uInt32 nMacroCount = pModule->GetMethods()->Count();
+ for ( sal_uInt32 iMeth = 0; iMeth < nMacroCount; iMeth++ )
+ {
+ SbMethod* pMethod = static_cast<SbMethod*>(pModule->GetMethods()->Get(iMeth));
+ assert(pMethod && "Method not found!");
+ if (pMethod->IsHidden())
+ continue;
+ m_xMacroBox->append_text(pMethod->GetName());
+ }
+
+ m_xMacroBox->thaw();
+
+ if (m_xMacroBox->get_iter_first(*m_xMacroBoxIter))
+ m_xMacroBox->set_cursor(*m_xMacroBoxIter);
+ }
+
+ UpdateFields();
+ CheckButtons();
+}
+
+IMPL_LINK_NOARG(MacroChooser, EditModifyHdl, weld::Entry&, void)
+{
+ // select the module in which the macro is put at "new",
+ // if BasicManager or Lib is selecting
+ if (m_xBasicBox->get_cursor(m_xBasicBoxIter.get()))
+ {
+ sal_uInt16 nDepth = m_xBasicBox->get_iter_depth(*m_xBasicBoxIter);
+ if (nDepth == 1 && m_xBasicBox->IsEntryProtected(m_xBasicBoxIter.get()))
+ {
+ // then put to the respective Std-Lib...
+ m_xBasicBox->iter_parent(*m_xBasicBoxIter);
+ m_xBasicBox->iter_children(*m_xBasicBoxIter);
+ }
+ if (nDepth < 2)
+ {
+ std::unique_ptr<weld::TreeIter> xNewEntry(m_xBasicBox->make_iterator());
+ m_xBasicBox->copy_iterator(*m_xBasicBoxIter, *xNewEntry);
+ bool bCurEntry = true;
+ do
+ {
+ bCurEntry = m_xBasicBox->iter_children(*m_xBasicBoxIter);
+ if (bCurEntry)
+ {
+ m_xBasicBox->copy_iterator(*m_xBasicBoxIter, *xNewEntry);
+ nDepth = m_xBasicBox->get_iter_depth(*m_xBasicBoxIter);
+ }
+ }
+ while (bCurEntry && (nDepth < 2));
+ SaveSetCurEntry(m_xBasicBox->get_widget(), *xNewEntry);
+ }
+ auto nCount = m_xMacroBox->n_children();
+ if (nCount)
+ {
+ OUString aEdtText(m_xMacroNameEdit->get_text());
+ bool bFound = false;
+ bool bValidIter = m_xMacroBox->get_iter_first(*m_xMacroBoxIter);
+ while (bValidIter)
+ {
+ if (m_xMacroBox->get_text(*m_xMacroBoxIter).equalsIgnoreAsciiCase(aEdtText))
+ {
+ SaveSetCurEntry(*m_xMacroBox, *m_xMacroBoxIter);
+ bFound = true;
+ break;
+ }
+ bValidIter = m_xMacroBox->iter_next_sibling(*m_xMacroBoxIter);
+ }
+ if (!bFound)
+ {
+ bValidIter = m_xMacroBox->get_selected(m_xMacroBoxIter.get());
+ // if the entry exists ->Select ->Description...
+ if (bValidIter)
+ m_xMacroBox->unselect(*m_xMacroBoxIter);
+ }
+ }
+ }
+
+ CheckButtons();
+}
+
+IMPL_LINK(MacroChooser, ButtonHdl, weld::Button&, rButton, void)
+{
+ // apart from New/Record the Description is done by LoseFocus
+ if (&rButton == m_xRunButton.get())
+ {
+ StoreMacroDescription();
+
+ // #116444# check security settings before macro execution
+ if (nMode == All)
+ {
+ SbMethod* pMethod = GetMacro();
+ SbModule* pModule = pMethod ? pMethod->GetModule() : nullptr;
+ StarBASIC* pBasic = pModule ? static_cast<StarBASIC*>(pModule->GetParent()) : nullptr;
+ BasicManager* pBasMgr = pBasic ? FindBasicManager(pBasic) : nullptr;
+ if ( pBasMgr )
+ {
+ ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
+ if ( aDocument.isDocument() && !aDocument.allowMacros() )
+ {
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_CANNOTRUNMACRO)));
+ xError->run();
+ return;
+ }
+ }
+ }
+ else if (nMode == Recording )
+ {
+ if ( !IsValidSbxName(m_xMacroNameEdit->get_text()) )
+ {
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
+ xError->run();
+ m_xMacroNameEdit->select_region(0, -1);
+ m_xMacroNameEdit->grab_focus();
+ return;
+ }
+
+ SbMethod* pMethod = GetMacro();
+ if (pMethod && !QueryReplaceMacro(pMethod->GetName(), m_xDialog.get()))
+ return;
+ }
+
+ m_xDialog->response(Macro_OkRun);
+ }
+ else if (&rButton == m_xCloseButton.get())
+ {
+ StoreMacroDescription();
+ m_xDialog->response(Macro_Close);
+ }
+ else if (&rButton == m_xEditButton.get() || &rButton == m_xDelButton.get() || &rButton == m_xNewButton.get())
+ {
+ if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter))
+ {
+ SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback");
+ return;
+ }
+ EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
+ const ScriptDocument& aDocument( aDesc.GetDocument() );
+ DBG_ASSERT( aDocument.isAlive(), "MacroChooser::ButtonHdl: no document, or document is dead!" );
+ if ( !aDocument.isAlive() )
+ return;
+ BasicManager* pBasMgr = aDocument.getBasicManager();
+ const OUString& aLib( aDesc.GetLibName() );
+ OUString aMod( aDesc.GetName() );
+ // extract the module name from the string like "Sheet1 (Example1)"
+ if( aDesc.GetLibSubName() == IDEResId(RID_STR_DOCUMENT_OBJECTS) )
+ {
+ aMod = aMod.getToken( 0, ' ' );
+ }
+ const OUString& aSub( aDesc.GetMethodName() );
+ SfxMacroInfoItem aInfoItem( SID_BASICIDE_ARG_MACROINFO, pBasMgr, aLib, aMod, aSub, OUString() );
+ if (&rButton == m_xEditButton.get())
+ {
+ if (m_xMacroBox->get_selected(m_xMacroBoxIter.get()))
+ aInfoItem.SetMethod(m_xMacroBox->get_text(*m_xMacroBoxIter));
+ StoreMacroDescription();
+ m_xDialog->hide(); // tdf#126828 dismiss dialog before opening new window
+
+ SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
+ SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs );
+ SfxGetpApp()->ExecuteSlot( aRequest );
+
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ {
+ pDispatcher->ExecuteList(SID_BASICIDE_EDITMACRO,
+ SfxCallMode::ASYNCHRON, { &aInfoItem });
+ }
+ m_xDialog->response(Macro_Edit);
+ }
+ else
+ {
+ if (&rButton == m_xDelButton.get())
+ {
+ DeleteMacro();
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ {
+ pDispatcher->ExecuteList( SID_BASICIDE_UPDATEMODULESOURCE,
+ SfxCallMode::SYNCHRON, { &aInfoItem });
+ }
+ CheckButtons();
+ UpdateFields();
+ //if ( m_xMacroBox->GetCurEntry() ) // OV-Bug ?
+ // m_xMacroBox->Select( m_xMacroBox->GetCurEntry() );
+ }
+ else
+ {
+ if ( !IsValidSbxName(m_xMacroNameEdit->get_text()) )
+ {
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
+ xError->run();
+ m_xMacroNameEdit->select_region(0, -1);
+ m_xMacroNameEdit->grab_focus();
+ return;
+ }
+ SbMethod* pMethod = CreateMacro();
+ if ( pMethod )
+ {
+ aInfoItem.SetMethod( pMethod->GetName() );
+ aInfoItem.SetModule( pMethod->GetModule()->GetName() );
+ aInfoItem.SetLib( pMethod->GetModule()->GetParent()->GetName() );
+ SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
+ SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs );
+ SfxGetpApp()->ExecuteSlot( aRequest );
+
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ {
+ pDispatcher->ExecuteList(SID_BASICIDE_EDITMACRO,
+ SfxCallMode::ASYNCHRON, { &aInfoItem });
+ }
+ StoreMacroDescription();
+ m_xDialog->response(Macro_New);
+ }
+ }
+ }
+ }
+ else if (&rButton == m_xAssignButton.get())
+ {
+ if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter))
+ {
+ SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback");
+ return;
+ }
+ EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
+ const ScriptDocument& aDocument( aDesc.GetDocument() );
+ DBG_ASSERT( aDocument.isAlive(), "MacroChooser::ButtonHdl: no document, or document is dead!" );
+ if ( !aDocument.isAlive() )
+ return;
+ BasicManager* pBasMgr = aDocument.getBasicManager();
+ const OUString& aLib( aDesc.GetLibName() );
+ const OUString& aMod( aDesc.GetName() );
+ OUString aSub( m_xMacroNameEdit->get_text() );
+ SbMethod* pMethod = GetMacro();
+ DBG_ASSERT( pBasMgr, "BasMgr?" );
+ DBG_ASSERT( pMethod, "Method?" );
+ OUString aComment( GetInfo( pMethod ) );
+ SfxMacroInfoItem aItem( SID_MACROINFO, pBasMgr, aLib, aMod, aSub, aComment );
+ SfxAllItemSet Args( SfxGetpApp()->GetPool() );
+
+ SfxAllItemSet aInternalSet(SfxGetpApp()->GetPool());
+ if (m_xDocumentFrame.is())
+ aInternalSet.Put(SfxUnoFrameItem(SID_FILLFRAME, m_xDocumentFrame));
+
+ SfxRequest aRequest(SID_CONFIG, SfxCallMode::SYNCHRON, Args, aInternalSet);
+ aRequest.AppendItem( aItem );
+ SfxGetpApp()->ExecuteSlot( aRequest );
+ }
+ else if (&rButton == m_xNewLibButton.get())
+ {
+ if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter))
+ {
+ SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback");
+ return;
+ }
+ EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
+ const ScriptDocument& aDocument( aDesc.GetDocument() );
+ createLibImpl(m_xDialog.get(), aDocument, nullptr, m_xBasicBox.get());
+ }
+ else if (&rButton == m_xNewModButton.get())
+ {
+ if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter))
+ {
+ SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback");
+ return;
+ }
+ EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
+ const ScriptDocument& aDocument( aDesc.GetDocument() );
+ const OUString& aLibName( aDesc.GetLibName() );
+ createModImpl(m_xDialog.get(), aDocument, *m_xBasicBox, aLibName, OUString(), true);
+ }
+ else if (&rButton == m_xOrganizeButton.get())
+ {
+ StoreMacroDescription();
+
+ m_xBasicBox->get_selected(m_xBasicBoxIter.get());
+ auto xDlg(std::make_shared<OrganizeDialog>(m_xDialog.get(), 0));
+ weld::DialogController::runAsync(xDlg, [this](sal_Int32 nRet) {
+ if (nRet == RET_OK) // not only closed
+ {
+ m_xDialog->response(Macro_Edit);
+ return;
+ }
+
+ Shell* pShell = GetShell();
+ if ( pShell && pShell->IsAppBasicModified() )
+ bForceStoreBasic = true;
+
+ m_xBasicBox->UpdateEntries();
+ });
+ }
+}
+
+IMPL_LINK(MacroChooser, ContextMenuHdl, const CommandEvent&, rCEvt, bool)
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu || !m_xMacroBox->n_children())
+ return false;
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xMacroBox.get(), "modules/BasicIDE/ui/sortmenu.ui"));
+ std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu("sortmenu"));
+ std::unique_ptr<weld::Menu> xDropMenu(xBuilder->weld_menu("sortsubmenu"));
+ xDropMenu->set_active("alphabetically", m_xMacroBox->get_sort_order());
+ xDropMenu->set_active("properorder", !m_xMacroBox->get_sort_order());
+
+ OString sCommand(xPopup->popup_at_rect(m_xMacroBox.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
+ if (sCommand == "alphabetically")
+ {
+ m_xMacroBox->make_sorted();
+ }
+ else if (sCommand == "properorder")
+ {
+ m_xMacroBox->make_unsorted();
+ BasicSelectHdl(m_xBasicBox->get_widget());
+ }
+ else if (!sCommand.isEmpty())
+ {
+ SAL_WARN("basctl.basicide", "Unknown context menu action: " << sCommand );
+ }
+
+ return true;
+}
+
+void MacroChooser::UpdateFields()
+{
+ auto nMacroEntry = m_xMacroBox->get_selected_index();
+ m_xMacroNameEdit->set_text("");
+ if (nMacroEntry != -1)
+ m_xMacroNameEdit->set_text(m_xMacroBox->get_text(nMacroEntry));
+}
+
+void MacroChooser::SetMode (Mode nM)
+{
+ nMode = nM;
+ switch (nMode)
+ {
+ case All:
+ {
+ m_xRunButton->set_label(IDEResId(RID_STR_RUN));
+ EnableButton(*m_xDelButton, true);
+ EnableButton(*m_xNewButton, true);
+ EnableButton(*m_xOrganizeButton, true);
+ break;
+ }
+
+ case ChooseOnly:
+ {
+ m_xRunButton->set_label(IDEResId(RID_STR_CHOOSE));
+ EnableButton(*m_xDelButton, false);
+ EnableButton(*m_xNewButton, false);
+ EnableButton(*m_xOrganizeButton, false);
+ break;
+ }
+
+ case Recording:
+ {
+ m_xRunButton->set_label(IDEResId(RID_STR_RECORD));
+ EnableButton(*m_xDelButton, false);
+ EnableButton(*m_xNewButton, false);
+ EnableButton(*m_xOrganizeButton, false);
+
+ m_xAssignButton->hide();
+ m_xEditButton->hide();
+ m_xDelButton->hide();
+ m_xNewButton->hide();
+ m_xOrganizeButton->hide();
+ m_xMacroFromTxT->hide();
+
+ m_xNewLibButton->show();
+ m_xNewModButton->show();
+ m_xMacrosSaveInTxt->show();
+
+ break;
+ }
+ }
+ CheckButtons();
+}
+
+OUString MacroChooser::GetInfo( SbxVariable* pVar )
+{
+ OUString aComment;
+ SbxInfoRef xInfo = pVar->GetInfo();
+ if ( xInfo.is() )
+ aComment = xInfo->GetComment();
+ return aComment;
+}
+
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/macrodlg.hxx b/basctl/source/basicide/macrodlg.hxx
new file mode 100644
index 000000000..0e50ee5de
--- /dev/null
+++ b/basctl/source/basicide/macrodlg.hxx
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <basobj.hxx>
+#include <bastype2.hxx>
+#include <sfx2/basedlgs.hxx>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <vcl/weld.hxx>
+
+namespace basctl
+{
+
+enum MacroExitCode {
+ Macro_Close = 110,
+ Macro_OkRun = 111,
+ Macro_New = 112,
+ Macro_Edit = 114,
+};
+
+class MacroChooser : public SfxDialogController
+{
+public:
+ enum Mode {
+ All = 1,
+ ChooseOnly = 2,
+ Recording = 3,
+ };
+
+private:
+ OUString m_aMacrosInTxtBaseStr;
+
+ // For forwarding to Assign dialog
+ ::css::uno::Reference< ::css::frame::XFrame > m_xDocumentFrame;
+
+ bool bForceStoreBasic;
+
+ Mode nMode;
+
+ DECL_LINK(MacroSelectHdl, weld::TreeView&, void);
+ DECL_LINK(MacroDoubleClickHdl, weld::TreeView&, bool);
+ DECL_LINK(BasicSelectHdl, weld::TreeView&, void);
+ DECL_LINK(EditModifyHdl, weld::Entry&, void);
+ DECL_LINK(ContextMenuHdl, const CommandEvent&, bool);
+ DECL_LINK(ButtonHdl, weld::Button&, void);
+
+ void CheckButtons();
+ void SaveSetCurEntry(weld::TreeView& rBox, const weld::TreeIter& rEntry);
+ void UpdateFields();
+
+ void EnableButton(weld::Button& rButton, bool bEnable);
+
+ static OUString GetInfo( SbxVariable* pVar );
+
+ void StoreMacroDescription();
+ void RestoreMacroDescription();
+
+ std::unique_ptr<weld::Entry> m_xMacroNameEdit;
+ std::unique_ptr<weld::Label> m_xMacroFromTxT;
+ std::unique_ptr<weld::Label> m_xMacrosSaveInTxt;
+ std::unique_ptr<SbTreeListBox> m_xBasicBox;
+ std::unique_ptr<weld::TreeIter> m_xBasicBoxIter;
+ std::unique_ptr<weld::Label> m_xMacrosInTxt;
+ std::unique_ptr<weld::TreeView> m_xMacroBox;
+ std::unique_ptr<weld::TreeIter> m_xMacroBoxIter;
+ std::unique_ptr<weld::Button> m_xRunButton;
+ std::unique_ptr<weld::Button> m_xCloseButton;
+ std::unique_ptr<weld::Button> m_xAssignButton;
+ std::unique_ptr<weld::Button> m_xEditButton;
+ std::unique_ptr<weld::Button> m_xDelButton;
+ std::unique_ptr<weld::Button> m_xNewButton;
+ std::unique_ptr<weld::Button> m_xOrganizeButton;
+ std::unique_ptr<weld::Button> m_xNewLibButton;
+ std::unique_ptr<weld::Button> m_xNewModButton;
+public:
+ MacroChooser(weld::Window *pParent, const ::css::uno::Reference< ::css::frame::XFrame >& xDocFrame);
+ virtual ~MacroChooser() override;
+
+ SbMethod* GetMacro();
+ void DeleteMacro();
+ SbMethod* CreateMacro();
+
+ virtual short run() override;
+
+ void SetMode (Mode);
+ Mode GetMode () const { return nMode; }
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/moduldl2.cxx b/basctl/source/basicide/moduldl2.cxx
new file mode 100644
index 000000000..57241bce7
--- /dev/null
+++ b/basctl/source/basicide/moduldl2.cxx
@@ -0,0 +1,1357 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "moduldlg.hxx"
+#include <basidesh.hxx>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <iderdll.hxx>
+#include "iderdll2.hxx"
+#include <iderid.hxx>
+#include <basobj.hxx>
+#include <svx/passwd.hxx>
+#include <ucbhelper/content.hxx>
+#include <rtl/uri.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <svl/stritem.hxx>
+#include <tools/debug.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <com/sun/star/io/Pipe.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/script/DocumentScriptLibraryContainer.hpp>
+#include <com/sun/star/script/DocumentDialogLibraryContainer.hpp>
+#include <com/sun/star/script/XLibraryContainerPassword.hpp>
+#include <com/sun/star/script/XLibraryContainerExport.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/ucb/NameClash.hpp>
+#include <com/sun/star/packages/manifest/ManifestWriter.hpp>
+#include <unotools/pathoptions.hxx>
+
+#include <com/sun/star/util/VetoException.hpp>
+#include <com/sun/star/script/ModuleSizeExceededRequest.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <cassert>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::ui::dialogs;
+
+namespace
+{
+
+class DummyInteractionHandler : public ::cppu::WeakImplHelper< task::XInteractionHandler >
+{
+ Reference< task::XInteractionHandler2 > m_xHandler;
+public:
+ explicit DummyInteractionHandler(const Reference<task::XInteractionHandler2>& xHandler)
+ : m_xHandler(xHandler)
+ {
+ }
+
+ virtual void SAL_CALL handle( const Reference< task::XInteractionRequest >& rRequest ) override
+ {
+ if ( m_xHandler.is() )
+ {
+ script::ModuleSizeExceededRequest aModSizeException;
+ if ( rRequest->getRequest() >>= aModSizeException )
+ m_xHandler->handle( rRequest );
+ }
+ }
+};
+
+} // namespace
+
+namespace
+{
+ int FindEntry(const weld::TreeView& rBox, std::u16string_view rName)
+ {
+ int nCount = rBox.n_children();
+ for (int i = 0; i < nCount; ++i)
+ {
+ if (o3tl::equalsIgnoreAsciiCase(rName, rBox.get_text(i, 0)))
+ return i;
+ }
+ return -1;
+ }
+}
+
+// NewObjectDialog
+IMPL_LINK_NOARG(NewObjectDialog, OkButtonHandler, weld::Button&, void)
+{
+ if (!m_bCheckName || IsValidSbxName(m_xEdit->get_text()))
+ m_xDialog->response(RET_OK);
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
+ xErrorBox->run();
+ m_xEdit->grab_focus();
+ }
+}
+
+NewObjectDialog::NewObjectDialog(weld::Window * pParent, ObjectMode eMode, bool bCheckName)
+ : GenericDialogController(pParent, "modules/BasicIDE/ui/newlibdialog.ui", "NewLibDialog")
+ , m_xEdit(m_xBuilder->weld_entry("entry"))
+ , m_xOKButton(m_xBuilder->weld_button("ok"))
+ , m_bCheckName(bCheckName)
+{
+ switch (eMode)
+ {
+ case ObjectMode::Library:
+ m_xDialog->set_title(IDEResId(RID_STR_NEWLIB));
+ break;
+ case ObjectMode::Module:
+ m_xDialog->set_title(IDEResId(RID_STR_NEWMOD));
+ break;
+ case ObjectMode::Dialog:
+ m_xDialog->set_title(IDEResId(RID_STR_NEWDLG));
+ break;
+ default:
+ assert(false);
+ }
+ m_xOKButton->connect_clicked(LINK(this, NewObjectDialog, OkButtonHandler));
+}
+
+// GotoLineDialog
+GotoLineDialog::GotoLineDialog(weld::Window* pParent )
+ : GenericDialogController(pParent, "modules/BasicIDE/ui/gotolinedialog.ui", "GotoLineDialog")
+ , m_xEdit(m_xBuilder->weld_entry("entry"))
+ , m_xOKButton(m_xBuilder->weld_button("ok"))
+{
+ m_xEdit->grab_focus();
+ m_xOKButton->connect_clicked(LINK(this, GotoLineDialog, OkButtonHandler));
+}
+
+GotoLineDialog::~GotoLineDialog()
+{
+}
+
+sal_Int32 GotoLineDialog::GetLineNumber() const
+{
+ return m_xEdit->get_text().toInt32();
+}
+
+IMPL_LINK_NOARG(GotoLineDialog, OkButtonHandler, weld::Button&, void)
+{
+ if (GetLineNumber())
+ m_xDialog->response(RET_OK);
+ else
+ m_xEdit->select_region(0, -1);
+}
+
+// ExportDialog
+IMPL_LINK_NOARG(ExportDialog, OkButtonHandler, weld::Button&, void)
+{
+ m_bExportAsPackage = m_xExportAsPackageButton->get_active();
+ m_xDialog->response(RET_OK);
+}
+
+ExportDialog::ExportDialog(weld::Window * pParent)
+ : GenericDialogController(pParent, "modules/BasicIDE/ui/exportdialog.ui", "ExportDialog")
+ , m_bExportAsPackage(false)
+ , m_xExportAsPackageButton(m_xBuilder->weld_radio_button("extension"))
+ , m_xOKButton(m_xBuilder->weld_button("ok"))
+{
+ m_xExportAsPackageButton->set_active(true);
+ m_xOKButton->connect_clicked(LINK(this, ExportDialog, OkButtonHandler));
+}
+
+ExportDialog::~ExportDialog()
+{
+}
+
+// LibPage
+LibPage::LibPage(weld::Container* pParent, OrganizeDialog* pDialog)
+ : OrganizePage(pParent, "modules/BasicIDE/ui/libpage.ui", "LibPage", pDialog)
+ , m_xBasicsBox(m_xBuilder->weld_combo_box("location"))
+ , m_xLibBox(m_xBuilder->weld_tree_view("library"))
+ , m_xEditButton(m_xBuilder->weld_button("edit"))
+ , m_xPasswordButton(m_xBuilder->weld_button("password"))
+ , m_xNewLibButton(m_xBuilder->weld_button("new"))
+ , m_xInsertLibButton(m_xBuilder->weld_button("import"))
+ , m_xExportButton(m_xBuilder->weld_button("export"))
+ , m_xDelButton(m_xBuilder->weld_button("delete"))
+ , m_aCurDocument(ScriptDocument::getApplicationScriptDocument())
+ , m_eCurLocation(LIBRARY_LOCATION_UNKNOWN)
+{
+ Size aSize(m_xLibBox->get_approximate_digit_width() * 40,
+ m_xLibBox->get_height_rows(10));
+ m_xLibBox->set_size_request(aSize.Width(), aSize.Height());
+
+ // tdf#93476 The libraries should be listed alphabetically
+ m_xLibBox->make_sorted();
+
+ m_xEditButton->connect_clicked( LINK( this, LibPage, ButtonHdl ) );
+ m_xNewLibButton->connect_clicked( LINK( this, LibPage, ButtonHdl ) );
+ m_xPasswordButton->connect_clicked( LINK( this, LibPage, ButtonHdl ) );
+ m_xExportButton->connect_clicked( LINK( this, LibPage, ButtonHdl ) );
+ m_xInsertLibButton->connect_clicked( LINK( this, LibPage, ButtonHdl ) );
+ m_xDelButton->connect_clicked( LINK( this, LibPage, ButtonHdl ) );
+ m_xLibBox->connect_changed( LINK( this, LibPage, TreeListHighlightHdl ) );
+
+ m_xBasicsBox->connect_changed( LINK( this, LibPage, BasicSelectHdl ) );
+
+ m_xLibBox->connect_editing(LINK(this, LibPage, EditingEntryHdl),
+ LINK(this, LibPage, EditedEntryHdl));
+
+ FillListBox();
+ m_xBasicsBox->set_active(0);
+ SetCurLib();
+
+ CheckButtons();
+}
+
+IMPL_LINK(LibPage, EditingEntryHdl, const weld::TreeIter&, rIter, bool)
+{
+ // check, if Standard library
+ OUString aLibName = m_xLibBox->get_text(rIter, 0);
+
+ if ( aLibName.equalsIgnoreAsciiCase( "Standard" ) )
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_CANNOTCHANGENAMESTDLIB)));
+ xErrorBox->run();
+ return false;
+ }
+
+ // check, if library is readonly
+ Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ Reference< script::XLibraryContainer2 > xDlgLibContainer( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+ 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<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_LIBISREADONLY)));
+ xErrorBox->run();
+ return false;
+ }
+
+ // i24094: Password verification necessary for renaming
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && !xModLibContainer->isLibraryLoaded( aLibName ) )
+ {
+ bool bOK = true;
+ // check password
+ Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
+ if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) && !xPasswd->isLibraryPasswordVerified( aLibName ) )
+ {
+ OUString aPassword;
+ bOK = QueryPassword(m_pDialog->getDialog(), xModLibContainer, aLibName, aPassword);
+ }
+ if ( !bOK )
+ return false;
+ }
+
+ // TODO: check if library is reference/link
+
+ return true;
+}
+
+IMPL_LINK(LibPage, EditedEntryHdl, const IterString&, rIterString, bool)
+{
+ const weld::TreeIter& rIter = rIterString.first;
+ OUString sNewName = rIterString.second;
+
+ bool bValid = sNewName.getLength() <= 30 && IsValidSbxName(sNewName);
+ OUString aOldName(m_xLibBox->get_text(rIter, 0));
+
+ if (bValid && aOldName != sNewName)
+ {
+ try
+ {
+ Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ if ( xModLibContainer.is() )
+ xModLibContainer->renameLibrary( aOldName, sNewName );
+
+ Reference< script::XLibraryContainer2 > xDlgLibContainer( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+ if ( xDlgLibContainer.is() )
+ xDlgLibContainer->renameLibrary( aOldName, sNewName );
+
+ MarkDocumentModified( m_aCurDocument );
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate( SID_BASICIDE_LIBSELECTOR );
+ pBindings->Update( SID_BASICIDE_LIBSELECTOR );
+ }
+ }
+ catch (const container::ElementExistException& )
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED)));
+ xErrorBox->run();
+ return false;
+ }
+ catch (const container::NoSuchElementException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ return false;
+ }
+ }
+
+ if ( !bValid )
+ {
+ OUString sWarning(sNewName.getLength() > 30 ? IDEResId(RID_STR_LIBNAMETOLONG) : IDEResId(RID_STR_BADSBXNAME));
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
+ VclMessageType::Warning, VclButtonsType::Ok, sWarning));
+ xErrorBox->run();
+
+ }
+
+ return bValid;
+}
+
+LibPage::~LibPage()
+{
+ if (m_xBasicsBox)
+ {
+ const sal_Int32 nCount = m_xBasicsBox->get_count();
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ DocumentEntry* pEntry = weld::fromId<DocumentEntry*>(m_xBasicsBox->get_id(i));
+ delete pEntry;
+ }
+ }
+}
+
+void LibPage::CheckButtons()
+{
+ std::unique_ptr<weld::TreeIter> xCur(m_xLibBox->make_iterator());
+ if (!m_xLibBox->get_cursor(xCur.get()))
+ return;
+
+ OUString aLibName = m_xLibBox->get_text(*xCur, 0);
+ Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ Reference< script::XLibraryContainer2 > xDlgLibContainer( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+
+ if ( m_eCurLocation == LIBRARY_LOCATION_SHARE )
+ {
+ m_xPasswordButton->set_sensitive(false);
+ m_xNewLibButton->set_sensitive(false);
+ m_xInsertLibButton->set_sensitive(false);
+ m_xDelButton->set_sensitive(false);
+ }
+ else if ( aLibName.equalsIgnoreAsciiCase( "Standard" ) )
+ {
+ m_xPasswordButton->set_sensitive(false);
+ m_xNewLibButton->set_sensitive(true);
+ m_xInsertLibButton->set_sensitive(true);
+ m_xExportButton->set_sensitive(false);
+ m_xDelButton->set_sensitive(false);
+ }
+ else if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) ) ||
+ ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) ) )
+ {
+ m_xPasswordButton->set_sensitive(false);
+ m_xNewLibButton->set_sensitive(true);
+ m_xInsertLibButton->set_sensitive(true);
+ if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) && !xModLibContainer->isLibraryLink( aLibName ) ) ||
+ ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) && !xDlgLibContainer->isLibraryLink( aLibName ) ) )
+ m_xDelButton->set_sensitive(false);
+ else
+ m_xDelButton->set_sensitive(true);
+ }
+ else
+ {
+ if ( xModLibContainer.is() && !xModLibContainer->hasByName( aLibName ) )
+ m_xPasswordButton->set_sensitive(false);
+ else
+ m_xPasswordButton->set_sensitive(true);
+
+ m_xNewLibButton->set_sensitive(true);
+ m_xInsertLibButton->set_sensitive(true);
+ m_xExportButton->set_sensitive(true);
+ m_xDelButton->set_sensitive(true);
+ }
+}
+
+void LibPage::ActivatePage()
+{
+ SetCurLib();
+}
+
+IMPL_LINK_NOARG(LibPage, TreeListHighlightHdl, weld::TreeView&, void)
+{
+ CheckButtons();
+}
+
+IMPL_LINK_NOARG( LibPage, BasicSelectHdl, weld::ComboBox&, void )
+{
+ SetCurLib();
+ CheckButtons();
+}
+
+IMPL_LINK( LibPage, ButtonHdl, weld::Button&, rButton, void )
+{
+ if (&rButton == m_xEditButton.get())
+ {
+ SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
+ SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs );
+ SfxGetpApp()->ExecuteSlot( aRequest );
+
+ SfxUnoAnyItem aDocItem( SID_BASICIDE_ARG_DOCUMENT_MODEL, Any( m_aCurDocument.getDocumentOrNull() ) );
+
+ std::unique_ptr<weld::TreeIter> xCurEntry(m_xLibBox->make_iterator());
+ if (!m_xLibBox->get_cursor(xCurEntry.get()))
+ return;
+ OUString aLibName(m_xLibBox->get_text(*xCurEntry, 0));
+ SfxStringItem aLibNameItem( SID_BASICIDE_ARG_LIBNAME, aLibName );
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ pDispatcher->ExecuteList( SID_BASICIDE_LIBSELECTED,
+ SfxCallMode::ASYNCHRON, { &aDocItem, &aLibNameItem });
+ EndTabDialog();
+ return;
+ }
+ else if (&rButton == m_xNewLibButton.get())
+ NewLib();
+ else if (&rButton == m_xInsertLibButton.get())
+ InsertLib();
+ else if (&rButton == m_xExportButton.get())
+ Export();
+ else if (&rButton == m_xDelButton.get())
+ DeleteCurrent();
+ else if (&rButton == m_xPasswordButton.get())
+ {
+ std::unique_ptr<weld::TreeIter> xCurEntry(m_xLibBox->make_iterator());
+ if (!m_xLibBox->get_cursor(xCurEntry.get()))
+ return;
+ OUString aLibName(m_xLibBox->get_text(*xCurEntry, 0));
+
+ // load module library (if not loaded)
+ Reference< script::XLibraryContainer > xModLibContainer = m_aCurDocument.getLibraryContainer( E_SCRIPTS );
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && !xModLibContainer->isLibraryLoaded( aLibName ) )
+ {
+ Shell* pShell = GetShell();
+ if (pShell)
+ pShell->GetViewFrame()->GetWindow().EnterWait();
+ xModLibContainer->loadLibrary( aLibName );
+ if (pShell)
+ pShell->GetViewFrame()->GetWindow().LeaveWait();
+ }
+
+ // load dialog library (if not loaded)
+ Reference< script::XLibraryContainer > xDlgLibContainer = m_aCurDocument.getLibraryContainer( E_DIALOGS );
+ if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && !xDlgLibContainer->isLibraryLoaded( aLibName ) )
+ {
+ Shell* pShell = GetShell();
+ if (pShell)
+ pShell->GetViewFrame()->GetWindow().EnterWait();
+ xDlgLibContainer->loadLibrary( aLibName );
+ if (pShell)
+ pShell->GetViewFrame()->GetWindow().LeaveWait();
+ }
+
+ // check, if library is password protected
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) )
+ {
+ Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
+ if ( xPasswd.is() )
+ {
+ bool const bProtected = xPasswd->isLibraryPasswordProtected( aLibName );
+
+ // change password dialog
+ SvxPasswordDialog aDlg(m_pDialog->getDialog(), !bProtected);
+ aDlg.SetCheckPasswordHdl(LINK(this, LibPage, CheckPasswordHdl));
+
+ if (aDlg.run() == RET_OK)
+ {
+ bool const bNewProtected = xPasswd->isLibraryPasswordProtected( aLibName );
+
+ if ( bNewProtected != bProtected )
+ {
+ int nPos = m_xLibBox->get_iter_index_in_parent(*xCurEntry);
+ m_xLibBox->remove(*xCurEntry);
+ ImpInsertLibEntry(aLibName, nPos);
+ m_xLibBox->set_cursor(nPos);
+ }
+
+ MarkDocumentModified( m_aCurDocument );
+ }
+ }
+ }
+ }
+ CheckButtons();
+}
+
+IMPL_LINK( LibPage, CheckPasswordHdl, SvxPasswordDialog *, pDlg, bool )
+{
+ bool bRet = false;
+
+ std::unique_ptr<weld::TreeIter> xCurEntry(m_xLibBox->make_iterator());
+ if (!m_xLibBox->get_cursor(xCurEntry.get()))
+ return bRet;
+
+ OUString aLibName(m_xLibBox->get_text(*xCurEntry, 0));
+ Reference< script::XLibraryContainerPassword > xPasswd( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+
+ if ( xPasswd.is() )
+ {
+ try
+ {
+ OUString aOldPassword( pDlg->GetOldPassword() );
+ OUString aNewPassword( pDlg->GetNewPassword() );
+ xPasswd->changeLibraryPassword( aLibName, aOldPassword, aNewPassword );
+ bRet = true;
+ }
+ catch (...)
+ {
+ }
+ }
+
+ return bRet;
+}
+
+void LibPage::NewLib()
+{
+ createLibImpl(m_pDialog->getDialog(), m_aCurDocument, m_xLibBox.get(), nullptr);
+}
+
+void LibPage::InsertLib()
+{
+ Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ // file open dialog
+ sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, m_pDialog->getDialog());
+ aDlg.SetContext(sfx2::FileDialogHelper::BasicInsertLib);
+ const Reference <XFilePicker3>& xFP = aDlg.GetFilePicker();
+
+ xFP->setTitle(IDEResId(RID_STR_APPENDLIBS));
+
+ // filter
+ OUString aTitle(IDEResId(RID_STR_BASIC));
+ xFP->appendFilter( aTitle, "*.sbl;*.xlc;*.xlb" // library files
+ ";*.sdw;*.sxw;*.odt" // text
+ ";*.vor;*.stw;*.ott" // text template
+ ";*.sgl;*.sxg;*.odm" // master document
+ ";*.oth" // html document template
+ ";*.sdc;*.sxc;*.ods" // spreadsheet
+ ";*.stc;*.ots" // spreadsheet template
+ ";*.sda;*.sxd;*.odg" // drawing
+ ";*.std;*.otg" // drawing template
+ ";*.sdd;*.sxi;*.odp" // presentation
+ ";*.sti;*.otp" // presentation template
+ ";*.sxm;*.odf" ); // formula
+
+ OUString aLastFilter(GetExtraData()->GetAddLibFilter());
+ if ( !aLastFilter.isEmpty() )
+ xFP->setCurrentFilter( aLastFilter );
+ else
+ xFP->setCurrentFilter( IDEResId(RID_STR_BASIC) );
+
+ if ( xFP->execute() != RET_OK )
+ return;
+
+ GetExtraData()->SetAddLibPath( xFP->getDisplayDirectory() );
+ GetExtraData()->SetAddLibFilter( xFP->getCurrentFilter() );
+
+ // library containers for import
+ Reference< script::XLibraryContainer2 > xModLibContImport;
+ Reference< script::XLibraryContainer2 > xDlgLibContImport;
+
+ // file URLs
+ Sequence< OUString > aFiles = xFP->getSelectedFiles();
+ INetURLObject aURLObj( aFiles[0] );
+ auto xModURLObj = std::make_shared<INetURLObject>(aURLObj);
+ auto xDlgURLObj = std::make_shared<INetURLObject>(aURLObj);
+
+ OUString aBase = aURLObj.getBase();
+ OUString aModBase( "script" );
+ OUString aDlgBase( "dialog" );
+
+ if ( aBase == aModBase || aBase == aDlgBase )
+ {
+ xModURLObj->setBase( aModBase );
+ xDlgURLObj->setBase( aDlgBase );
+ }
+
+ Reference< XSimpleFileAccess3 > xSFA( SimpleFileAccess::create(comphelper::getProcessComponentContext()) );
+
+ OUString aModURL( xModURLObj->GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ if ( xSFA->exists( aModURL ) )
+ {
+ xModLibContImport = script::DocumentScriptLibraryContainer::createWithURL(xContext, aModURL);
+ }
+
+ OUString aDlgURL( xDlgURLObj->GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ if ( xSFA->exists( aDlgURL ) )
+ {
+ xDlgLibContImport = script::DocumentDialogLibraryContainer::createWithURL(xContext, aDlgURL);
+ }
+
+ if ( !xModLibContImport.is() && !xDlgLibContImport.is() )
+ return;
+
+ std::shared_ptr<LibDialog> xLibDlg;
+
+ Sequence< OUString > aLibNames = GetMergedLibraryNames( xModLibContImport, xDlgLibContImport );
+ sal_Int32 nLibCount = aLibNames.getLength();
+ if (nLibCount)
+ {
+ // library import dialog
+ xLibDlg = std::make_shared<LibDialog>(m_pDialog->getDialog());
+ xLibDlg->SetStorageName(aURLObj.getName());
+ weld::TreeView& rView = xLibDlg->GetLibBox();
+ rView.make_unsorted();
+ rView.freeze();
+
+ const OUString* pLibNames = aLibNames.getConstArray();
+ for (sal_Int32 i = 0 ; i < nLibCount; ++i)
+ {
+ // libbox entries
+ OUString aLibName( pLibNames[ i ] );
+ if ( !( ( xModLibContImport.is() && xModLibContImport->hasByName( aLibName ) && xModLibContImport->isLibraryLink( aLibName ) ) ||
+ ( xDlgLibContImport.is() && xDlgLibContImport->hasByName( aLibName ) && xDlgLibContImport->isLibraryLink( aLibName ) ) ) )
+ {
+ rView.append();
+ const int nRow = rView.n_children() - 1;
+ rView.set_toggle(nRow, TRISTATE_TRUE);
+ rView.set_text(nRow, aLibName, 0);
+ }
+ }
+
+ rView.thaw();
+ rView.make_sorted();
+
+ if (rView.n_children())
+ rView.set_cursor(0);
+ }
+
+ if (!xLibDlg)
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_NOLIBINSTORAGE)));
+ xErrorBox->run();
+ return;
+ }
+
+ OUString aExtension( aURLObj.getExtension() );
+ OUString aLibExtension( "xlb" );
+ OUString aContExtension( "xlc" );
+
+ // disable reference checkbox for documents and sbls
+ if ( aExtension != aLibExtension && aExtension != aContExtension )
+ xLibDlg->EnableReference(false);
+
+ weld::DialogController::runAsync(xLibDlg, [aContExtension, xDlgURLObj, aExtension, aLibExtension, xModURLObj, xLibDlg, xDlgLibContImport, xModLibContImport, this](sal_Int32 nResult)
+ {
+ if (!nResult )
+ return;
+
+ bool bChanges = false;
+ bool bRemove = false;
+ bool bReplace = xLibDlg->IsReplace();
+ bool bReference = xLibDlg->IsReference();
+ weld::TreeView& rView = xLibDlg->GetLibBox();
+ for (int nLib = 0, nChildren = rView.n_children(); nLib < nChildren; ++nLib)
+ {
+ 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 );
+
+ // check, if the library is already existing
+ if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) ) ||
+ ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) ) )
+ {
+ if ( bReplace )
+ {
+ // check, if the library is the Standard library
+ if ( aLibName == "Standard" )
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_REPLACESTDLIB)));
+ xErrorBox->run();
+ continue;
+ }
+
+ // check, if the library is readonly and not a link
+ if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) && !xModLibContainer->isLibraryLink( aLibName ) ) ||
+ ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) && !xDlgLibContainer->isLibraryLink( aLibName ) ) )
+ {
+ OUString aErrStr( IDEResId(RID_STR_REPLACELIB) );
+ aErrStr = aErrStr.replaceAll("XX", aLibName) + "\n" + IDEResId(RID_STR_LIBISREADONLY);
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
+ VclMessageType::Warning, VclButtonsType::Ok, aErrStr));
+ xErrorBox->run();
+ continue;
+ }
+
+ // remove existing libraries
+ bRemove = true;
+ }
+ else
+ {
+ OUString aErrStr;
+ if ( bReference )
+ aErrStr = IDEResId(RID_STR_REFNOTPOSSIBLE);
+ else
+ aErrStr = IDEResId(RID_STR_IMPORTNOTPOSSIBLE);
+ aErrStr = aErrStr.replaceAll("XX", aLibName) + "\n" +IDEResId(RID_STR_SBXNAMEALLREADYUSED);
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
+ VclMessageType::Warning, VclButtonsType::Ok, aErrStr));
+ xErrorBox->run();
+ continue;
+ }
+ }
+
+ // check, if the library is password protected
+ bool bOK = false;
+ OUString aPassword;
+ if ( xModLibContImport.is() && xModLibContImport->hasByName( aLibName ) )
+ {
+ 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);
+
+ if ( !bOK )
+ {
+ OUString aErrStr( IDEResId(RID_STR_NOIMPORT) );
+ aErrStr = aErrStr.replaceAll("XX", aLibName);
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(),
+ VclMessageType::Warning, VclButtonsType::Ok, aErrStr));
+ xErrorBox->run();
+ continue;
+ }
+ }
+ }
+
+ // remove existing libraries
+ if ( bRemove )
+ {
+ // remove listbox entry
+ int nEntry_ = FindEntry(*m_xLibBox, aLibName);
+ if (nEntry_ != -1)
+ m_xLibBox->remove(nEntry_);
+
+ // remove module library
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) )
+ xModLibContainer->removeLibrary( aLibName );
+
+ // remove dialog library
+ if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) )
+ xDlgLibContainer->removeLibrary( aLibName );
+ }
+
+ // copy module library
+ if ( xModLibContImport.is() && xModLibContImport->hasByName( aLibName ) && xModLibContainer.is() && !xModLibContainer->hasByName( aLibName ) )
+ {
+ Reference< container::XNameContainer > xModLib;
+ if ( bReference )
+ {
+ // storage URL
+ INetURLObject aModStorageURLObj(*xModURLObj);
+ if ( aExtension == aContExtension )
+ {
+ sal_Int32 nCount = aModStorageURLObj.getSegmentCount();
+ aModStorageURLObj.insertName( aLibName, false, nCount-1 );
+ aModStorageURLObj.setExtension( aLibExtension );
+ aModStorageURLObj.setFinalSlash();
+ }
+ OUString aModStorageURL( aModStorageURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+
+ // create library link
+ xModLib.set( xModLibContainer->createLibraryLink( aLibName, aModStorageURL, true ), UNO_QUERY);
+ }
+ else
+ {
+ // create library
+ xModLib = xModLibContainer->createLibrary( aLibName );
+ if ( xModLib.is() )
+ {
+ // get import library
+ Reference< container::XNameContainer > xModLibImport;
+ Any aElement = xModLibContImport->getByName( aLibName );
+ aElement >>= xModLibImport;
+
+ if ( xModLibImport.is() )
+ {
+ // load library
+ if ( !xModLibContImport->isLibraryLoaded( aLibName ) )
+ xModLibContImport->loadLibrary( aLibName );
+
+ // copy all modules
+ Sequence< OUString > aModNames = xModLibImport->getElementNames();
+ sal_Int32 nModCount = aModNames.getLength();
+ const OUString* pModNames = aModNames.getConstArray();
+ for ( sal_Int32 i = 0 ; i < nModCount ; i++ )
+ {
+ OUString aModName( pModNames[ i ] );
+ Any aElement_ = xModLibImport->getByName( aModName );
+ xModLib->insertByName( aModName, aElement_ );
+ }
+
+ // set password
+ if ( bOK )
+ {
+ Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
+ if ( xPasswd.is() )
+ {
+ try
+ {
+ xPasswd->changeLibraryPassword( aLibName, OUString(), aPassword );
+ }
+ catch (...)
+ {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // copy dialog library
+ if ( xDlgLibContImport.is() && xDlgLibContImport->hasByName( aLibName ) && xDlgLibContainer.is() && !xDlgLibContainer->hasByName( aLibName ) )
+ {
+ Reference< container::XNameContainer > xDlgLib;
+ if ( bReference )
+ {
+ // storage URL
+ INetURLObject aDlgStorageURLObj( *xDlgURLObj );
+ if ( aExtension == aContExtension )
+ {
+ sal_Int32 nCount = aDlgStorageURLObj.getSegmentCount();
+ aDlgStorageURLObj.insertName( aLibName, false, nCount - 1 );
+ aDlgStorageURLObj.setExtension( aLibExtension );
+ aDlgStorageURLObj.setFinalSlash();
+ }
+ OUString aDlgStorageURL( aDlgStorageURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+
+ // create library link
+ xDlgLib.set( xDlgLibContainer->createLibraryLink( aLibName, aDlgStorageURL, true ), UNO_QUERY);
+ }
+ else
+ {
+ // create library
+ xDlgLib = xDlgLibContainer->createLibrary( aLibName );
+ if ( xDlgLib.is() )
+ {
+ // get import library
+ Reference< container::XNameContainer > xDlgLibImport;
+ Any aElement = xDlgLibContImport->getByName( aLibName );
+ aElement >>= xDlgLibImport;
+
+ if ( xDlgLibImport.is() )
+ {
+ // load library
+ if ( !xDlgLibContImport->isLibraryLoaded( aLibName ) )
+ xDlgLibContImport->loadLibrary( aLibName );
+
+ // copy all dialogs
+ Sequence< OUString > aDlgNames = xDlgLibImport->getElementNames();
+ sal_Int32 nDlgCount = aDlgNames.getLength();
+ const OUString* pDlgNames = aDlgNames.getConstArray();
+ for ( sal_Int32 i = 0 ; i < nDlgCount ; i++ )
+ {
+ OUString aDlgName( pDlgNames[ i ] );
+ Any aElement_ = xDlgLibImport->getByName( aDlgName );
+ xDlgLib->insertByName( aDlgName, aElement_ );
+ }
+ }
+ }
+ }
+ }
+
+ // insert listbox entry
+ ImpInsertLibEntry( aLibName, m_xLibBox->n_children() );
+ m_xLibBox->set_cursor( m_xLibBox->find_text(aLibName) );
+ bChanges = true;
+ }
+ }
+
+ if ( bChanges )
+ MarkDocumentModified( m_aCurDocument );
+ });
+}
+
+void LibPage::Export()
+{
+ std::unique_ptr<weld::TreeIter> xCurEntry(m_xLibBox->make_iterator());
+ if (!m_xLibBox->get_cursor(xCurEntry.get()))
+ return;
+ OUString aLibName(m_xLibBox->get_text(*xCurEntry, 0));
+
+ // Password verification
+ Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && !xModLibContainer->isLibraryLoaded( aLibName ) )
+ {
+ bool bOK = true;
+
+ // check password
+ Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
+ if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) && !xPasswd->isLibraryPasswordVerified( aLibName ) )
+ {
+ OUString aPassword;
+ bOK = QueryPassword(m_pDialog->getDialog(), xModLibContainer, aLibName, aPassword);
+ }
+ if ( !bOK )
+ return;
+ }
+
+ std::unique_ptr<ExportDialog> xNewDlg(new ExportDialog(m_pDialog->getDialog()));
+ if (xNewDlg->run() != RET_OK)
+ return;
+
+ try
+ {
+ bool bExportAsPackage = xNewDlg->isExportAsPackage();
+ //tdf#112063 ensure closing xNewDlg is not selected as
+ //parent of file dialog from ExportAs...
+ xNewDlg.reset();
+ if (bExportAsPackage)
+ ExportAsPackage( aLibName );
+ else
+ ExportAsBasic( aLibName );
+ }
+ catch(const util::VetoException& ) // user canceled operation
+ {
+ }
+}
+
+void LibPage::implExportLib( const OUString& aLibName, const OUString& aTargetURL,
+ const Reference< task::XInteractionHandler >& Handler )
+{
+ Reference< script::XLibraryContainerExport > xModLibContainerExport
+ ( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ Reference< script::XLibraryContainerExport > xDlgLibContainerExport
+ ( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+ if ( xModLibContainerExport.is() )
+ xModLibContainerExport->exportLibrary( aLibName, aTargetURL, Handler );
+
+ if (!xDlgLibContainerExport.is())
+ return;
+ Reference<container::XNameAccess> xNameAcc(xDlgLibContainerExport, UNO_QUERY);
+ if (!xNameAcc.is())
+ return;
+ if (!xNameAcc->hasByName(aLibName))
+ return;
+ xDlgLibContainerExport->exportLibrary(aLibName, aTargetURL, Handler);
+}
+
+// Implementation XCommandEnvironment
+
+namespace {
+
+class OLibCommandEnvironment : public cppu::WeakImplHelper< XCommandEnvironment >
+{
+ Reference< task::XInteractionHandler > mxInteraction;
+
+public:
+ explicit OLibCommandEnvironment(const Reference<task::XInteractionHandler>& xInteraction)
+ : mxInteraction( xInteraction )
+ {}
+
+ // Methods
+ virtual Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler() override;
+ virtual Reference< XProgressHandler > SAL_CALL getProgressHandler() override;
+};
+
+}
+
+Reference< task::XInteractionHandler > OLibCommandEnvironment::getInteractionHandler()
+{
+ return mxInteraction;
+}
+
+Reference< XProgressHandler > OLibCommandEnvironment::getProgressHandler()
+{
+ Reference< XProgressHandler > xRet;
+ return xRet;
+}
+
+void LibPage::ExportAsPackage( const OUString& aLibName )
+{
+ // file open dialog
+ sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILESAVE_SIMPLE, FileDialogFlags::NONE, m_pDialog->getDialog());
+ aDlg.SetContext(sfx2::FileDialogHelper::BasicExportPackage);
+ const Reference <XFilePicker3>& xFP = aDlg.GetFilePicker();
+
+ Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ Reference< task::XInteractionHandler2 > xHandler( task::InteractionHandler::createWithParent(xContext, nullptr) );
+ Reference< XSimpleFileAccess3 > xSFA = SimpleFileAccess::create(xContext);
+
+ xFP->setTitle(IDEResId(RID_STR_EXPORTPACKAGE));
+
+ // filter
+ OUString aTitle(IDEResId(RID_STR_PACKAGE_BUNDLE));
+ xFP->appendFilter( aTitle, "*.oxt" ); // library files
+
+ xFP->setCurrentFilter( aTitle );
+
+ if ( xFP->execute() != RET_OK )
+ return;
+
+ GetExtraData()->SetAddLibPath(xFP->getDisplayDirectory());
+
+ Sequence< OUString > aFiles = xFP->getSelectedFiles();
+ INetURLObject aURL( aFiles[0] );
+ if( aURL.getExtension().isEmpty() )
+ aURL.setExtension( u"oxt" );
+
+ OUString aPackageURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+
+ OUString aTmpPath = SvtPathOptions().GetTempPath();
+ INetURLObject aInetObj( aTmpPath );
+ aInetObj.insertName( aLibName, true, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+ OUString aSourcePath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if( xSFA->exists( aSourcePath ) )
+ xSFA->kill( aSourcePath );
+ Reference< task::XInteractionHandler > xDummyHandler( new DummyInteractionHandler( xHandler ) );
+ implExportLib( aLibName, aTmpPath, xDummyHandler );
+
+ Reference< XCommandEnvironment > xCmdEnv = new OLibCommandEnvironment(xHandler);
+
+ ::ucbhelper::Content sourceContent( aSourcePath, xCmdEnv, comphelper::getProcessComponentContext() );
+
+ OUString destFolder = "vnd.sun.star.zip://" +
+ ::rtl::Uri::encode( aPackageURL,
+ rtl_UriCharClassRegName,
+ rtl_UriEncodeIgnoreEscapes,
+ RTL_TEXTENCODING_UTF8 ) +
+ "/";
+
+ if( xSFA->exists( aPackageURL ) )
+ xSFA->kill( aPackageURL );
+
+ ::ucbhelper::Content destFolderContent( destFolder, xCmdEnv, comphelper::getProcessComponentContext() );
+ destFolderContent.transferContent(
+ sourceContent, ::ucbhelper::InsertOperation::Copy,
+ OUString(), NameClash::OVERWRITE );
+
+ INetURLObject aMetaInfInetObj( aTmpPath );
+ aMetaInfInetObj.insertName( u"META-INF",
+ true, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+ OUString aMetaInfFolder = aMetaInfInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if( xSFA->exists( aMetaInfFolder ) )
+ xSFA->kill( aMetaInfFolder );
+ xSFA->createFolder( aMetaInfFolder );
+
+ std::vector< Sequence<beans::PropertyValue> > manifest;
+
+ OUString fullPath = aLibName
+ + "/" ;
+ auto attribs(::comphelper::InitPropertySequence({
+ { "FullPath", Any(fullPath) },
+ { "MediaType", Any(OUString("application/vnd.sun.star.basic-library")) }
+ }));
+ manifest.push_back( attribs );
+
+ // write into pipe:
+ Reference<packages::manifest::XManifestWriter> xManifestWriter = packages::manifest::ManifestWriter::create( xContext );
+ Reference<io::XOutputStream> xPipe( io::Pipe::create( xContext ), UNO_QUERY_THROW );
+ xManifestWriter->writeManifestSequence(
+ xPipe, Sequence< Sequence<beans::PropertyValue> >(
+ manifest.data(), manifest.size() ) );
+
+ aMetaInfInetObj.insertName( u"manifest.xml",
+ true, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+
+ // write buffered pipe data to content:
+ ::ucbhelper::Content manifestContent( aMetaInfInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xCmdEnv, comphelper::getProcessComponentContext() );
+ manifestContent.writeStream( Reference<io::XInputStream>( xPipe, UNO_QUERY_THROW ), true );
+
+ ::ucbhelper::Content MetaInfContent( aMetaInfFolder, xCmdEnv, comphelper::getProcessComponentContext() );
+ destFolderContent.transferContent(
+ MetaInfContent, ::ucbhelper::InsertOperation::Copy,
+ OUString(), NameClash::OVERWRITE );
+
+ if( xSFA->exists( aSourcePath ) )
+ xSFA->kill( aSourcePath );
+ if( xSFA->exists( aMetaInfFolder ) )
+ xSFA->kill( aMetaInfFolder );
+}
+
+void LibPage::ExportAsBasic( const OUString& aLibName )
+{
+ // Folder picker
+ Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ Reference< XFolderPicker2 > xFolderPicker = sfx2::createFolderPicker(xContext, m_pDialog->getDialog());
+ Reference< task::XInteractionHandler2 > xHandler( task::InteractionHandler::createWithParent(xContext, nullptr) );
+
+ xFolderPicker->setTitle(IDEResId(RID_STR_EXPORTBASIC));
+
+ // set display directory and filter
+ OUString aPath =GetExtraData()->GetAddLibPath();
+ if( aPath.isEmpty() )
+ aPath = SvtPathOptions().GetWorkPath();
+
+ // INetURLObject aURL(m_sSavePath, INetProtocol::File);
+ xFolderPicker->setDisplayDirectory( aPath );
+ short nRet = xFolderPicker->execute();
+ if( nRet == RET_OK )
+ {
+ OUString aTargetURL = xFolderPicker->getDirectory();
+ GetExtraData()->SetAddLibPath(aTargetURL);
+
+ Reference< task::XInteractionHandler > xDummyHandler( new DummyInteractionHandler( xHandler ) );
+ implExportLib( aLibName, aTargetURL, xDummyHandler );
+ }
+}
+
+void LibPage::DeleteCurrent()
+{
+ std::unique_ptr<weld::TreeIter> xCurEntry(m_xLibBox->make_iterator());
+ if (!m_xLibBox->get_cursor(xCurEntry.get()))
+ return;
+ OUString aLibName(m_xLibBox->get_text(*xCurEntry, 0));
+
+ // check, if library is link
+ bool bIsLibraryLink = false;
+ Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ Reference< script::XLibraryContainer2 > xDlgLibContainer( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+ if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryLink( aLibName ) ) ||
+ ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryLink( aLibName ) ) )
+ {
+ bIsLibraryLink = true;
+ }
+
+ if (!QueryDelLib(aLibName, bIsLibraryLink, m_pDialog->getDialog()))
+ return;
+
+ // inform BasicIDE
+ SfxUnoAnyItem aDocItem( SID_BASICIDE_ARG_DOCUMENT_MODEL, Any( m_aCurDocument.getDocumentOrNull() ) );
+ SfxStringItem aLibNameItem( SID_BASICIDE_ARG_LIBNAME, aLibName );
+ if (SfxDispatcher* pDispatcher = 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 );
+
+ m_xLibBox->remove(*xCurEntry);
+ MarkDocumentModified( m_aCurDocument );
+}
+
+void LibPage::EndTabDialog()
+{
+ m_pDialog->response(RET_OK);
+}
+
+void LibPage::FillListBox()
+{
+ InsertListBoxEntry( ScriptDocument::getApplicationScriptDocument(), LIBRARY_LOCATION_USER );
+ InsertListBoxEntry( ScriptDocument::getApplicationScriptDocument(), LIBRARY_LOCATION_SHARE );
+
+ ScriptDocuments aDocuments( ScriptDocument::getAllScriptDocuments( ScriptDocument::DocumentsSorted ) );
+ for (auto const& doc : aDocuments)
+ {
+ InsertListBoxEntry( doc, LIBRARY_LOCATION_DOCUMENT );
+ }
+}
+
+void LibPage::InsertListBoxEntry( const ScriptDocument& rDocument, LibraryLocation eLocation )
+{
+ OUString aEntryText(rDocument.getTitle(eLocation));
+ OUString sId(weld::toId(new DocumentEntry(rDocument, eLocation)));
+ m_xBasicsBox->append(sId, aEntryText);
+}
+
+void LibPage::SetCurLib()
+{
+ DocumentEntry* pEntry = weld::fromId<DocumentEntry*>(m_xBasicsBox->get_active_id());
+ if (!pEntry)
+ return;
+
+ const ScriptDocument& aDocument( pEntry->GetDocument() );
+ DBG_ASSERT( aDocument.isAlive(), "LibPage::SetCurLib: no document, or document is dead!" );
+ if ( !aDocument.isAlive() )
+ return;
+ LibraryLocation eLocation = pEntry->GetLocation();
+ if ( aDocument == m_aCurDocument && eLocation == m_eCurLocation )
+ return;
+
+ m_aCurDocument = aDocument;
+ m_eCurLocation = eLocation;
+ m_xLibBox->clear();
+
+ // get a sorted list of library names
+ Sequence< OUString > aLibNames = aDocument.getLibraryNames();
+ sal_Int32 nLibCount = aLibNames.getLength();
+ const OUString* pLibNames = aLibNames.getConstArray();
+
+ int nEntry = 0;
+ for (int i = 0 ; i < nLibCount; ++i)
+ {
+ OUString aLibName(pLibNames[i]);
+ if (eLocation == aDocument.getLibraryLocation(aLibName))
+ ImpInsertLibEntry(aLibName, nEntry++);
+ }
+
+ int nEntry_ = FindEntry(*m_xLibBox, u"Standard");
+ if (nEntry_ == -1 && m_xLibBox->n_children())
+ nEntry_ = 0;
+ m_xLibBox->set_cursor(nEntry_);
+}
+
+void LibPage::ImpInsertLibEntry( const OUString& rLibName, int nPos )
+{
+ // check, if library is password protected
+ bool bProtected = false;
+ Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( rLibName ) )
+ {
+ Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
+ if ( xPasswd.is() )
+ {
+ bProtected = xPasswd->isLibraryPasswordProtected( rLibName );
+ }
+ }
+
+ m_xLibBox->insert_text(nPos, rLibName);
+
+ if (bProtected)
+ m_xLibBox->set_image(nPos, RID_BMP_LOCKED);
+
+ // check, if library is link
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( rLibName ) && xModLibContainer->isLibraryLink( rLibName ) )
+ {
+ OUString aLinkURL = xModLibContainer->getLibraryLinkURL( rLibName );
+ m_xLibBox->set_text(nPos, aLinkURL, 1);
+ }
+}
+
+// Helper function
+void createLibImpl(weld::Window* pWin, const ScriptDocument& rDocument,
+ weld::TreeView* pLibBox, SbTreeListBox* pBasicBox)
+{
+ OSL_ENSURE( rDocument.isAlive(), "createLibImpl: invalid document!" );
+ if ( !rDocument.isAlive() )
+ return;
+
+ // create library name
+ OUString aLibName;
+ bool bValid = false;
+ sal_Int32 i = 1;
+ while ( !bValid )
+ {
+ aLibName = "Library" + OUString::number( i );
+ if ( !rDocument.hasLibrary( E_SCRIPTS, aLibName ) && !rDocument.hasLibrary( E_DIALOGS, aLibName ) )
+ bValid = true;
+ i++;
+ }
+
+ NewObjectDialog aNewDlg(pWin, ObjectMode::Library);
+ aNewDlg.SetObjectName(aLibName);
+
+ if (!aNewDlg.run())
+ return;
+
+ if (!aNewDlg.GetObjectName().isEmpty())
+ aLibName = aNewDlg.GetObjectName();
+
+ if ( aLibName.getLength() > 30 )
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pWin,
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_LIBNAMETOLONG)));
+ xErrorBox->run();
+ }
+ else if ( !IsValidSbxName( aLibName ) )
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pWin,
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
+ xErrorBox->run();
+ }
+ else if ( rDocument.hasLibrary( E_SCRIPTS, aLibName ) || rDocument.hasLibrary( E_DIALOGS, aLibName ) )
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pWin,
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED2)));
+ xErrorBox->run();
+ }
+ else
+ {
+ try
+ {
+ // create module and dialog library
+ rDocument.getOrCreateLibrary( E_SCRIPTS, aLibName );
+ rDocument.getOrCreateLibrary( E_DIALOGS, aLibName );
+
+ if( pLibBox )
+ {
+ pLibBox->append_text(aLibName);
+ pLibBox->set_cursor(pLibBox->find_text(aLibName));
+ }
+
+ // create a module
+ OUString aModName = rDocument.createObjectName( E_SCRIPTS, aLibName );
+ OUString sModuleCode;
+ if ( !rDocument.createModule( aLibName, aModName, true, sModuleCode ) )
+ throw Exception("could not create module " + aModName, nullptr);
+
+ SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, rDocument, aLibName, aModName, TYPE_MODULE );
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ pDispatcher->ExecuteList(SID_BASICIDE_SBXINSERTED,
+ SfxCallMode::SYNCHRON, { &aSbxItem });
+
+ if( pBasicBox )
+ {
+ std::unique_ptr<weld::TreeIter> xIter(pBasicBox->make_iterator(nullptr));
+ bool bValidIter = pBasicBox->get_cursor(xIter.get());
+ std::unique_ptr<weld::TreeIter> xRootEntry(pBasicBox->make_iterator(xIter.get()));
+ while (bValidIter)
+ {
+ pBasicBox->copy_iterator(*xIter, *xRootEntry);
+ bValidIter = pBasicBox->iter_parent(*xIter);
+ }
+
+ BrowseMode nMode = pBasicBox->GetMode();
+ bool bDlgMode = ( nMode & BrowseMode::Dialogs ) && !( nMode & BrowseMode::Modules );
+ const auto sId = bDlgMode ? OUString(RID_BMP_DLGLIB) : OUString(RID_BMP_MODLIB);
+ pBasicBox->AddEntry(aLibName, sId, xRootEntry.get(), false, std::make_unique<Entry>(OBJ_TYPE_LIBRARY));
+ pBasicBox->AddEntry(aModName, RID_BMP_MODULE, xRootEntry.get(), false, std::make_unique<Entry>(OBJ_TYPE_MODULE));
+ pBasicBox->set_cursor(*xRootEntry);
+ pBasicBox->select(*xRootEntry);
+ }
+ }
+ catch (const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/moduldlg.cxx b/basctl/source/basicide/moduldlg.cxx
new file mode 100644
index 000000000..dc46c7db0
--- /dev/null
+++ b/basctl/source/basicide/moduldlg.cxx
@@ -0,0 +1,1033 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <strings.hrc>
+#include <iderid.hxx>
+#include <bitmaps.hlst>
+
+#include "moduldlg.hxx"
+#include <localizationmgr.hxx>
+#include <basidesh.hxx>
+#include <basobj.hxx>
+
+#include <basic/basmgr.hxx>
+#include <com/sun/star/script/XLibraryContainerPassword.hpp>
+#include <com/sun/star/script/XLibraryContainer2.hpp>
+#include <comphelper/processfactory.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <svl/stritem.hxx>
+#include <vcl/transfer.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <xmlscript/xmldlg_imexp.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::resource;
+
+IMPL_LINK(ObjectPage, EditingEntryHdl, const weld::TreeIter&, rEntry, bool)
+{
+ bool bRet = false;
+
+ sal_uInt16 nDepth = m_xBasicBox->get_iter_depth(rEntry);
+ if (nDepth >= 2)
+ {
+ EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(&rEntry);
+ const ScriptDocument& aDocument( aDesc.GetDocument() );
+ const OUString& aLibName( aDesc.GetLibName() );
+ Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ Reference< script::XLibraryContainer2 > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+ if ( !( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) ) ||
+ ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) ) ) )
+ {
+ // allow editing only for libraries, which are not readonly
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+IMPL_LINK(ObjectPage, EditedEntryHdl, const IterString&, rIterString, bool)
+{
+ const weld::TreeIter& rEntry = rIterString.first;
+ OUString sNewText = rIterString.second;
+
+ if ( !IsValidSbxName(sNewText) )
+ {
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_pDialog->getDialog(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
+ xError->run();
+ return false;
+ }
+
+ OUString aCurText(m_xBasicBox->get_text(rEntry));
+ if ( aCurText == sNewText )
+ // nothing to do
+ return true;
+
+ EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(&rEntry);
+ const ScriptDocument& aDocument( aDesc.GetDocument() );
+ DBG_ASSERT( aDocument.isValid(), "ExtTreeListBox::EditedEntry: no document!" );
+ if ( !aDocument.isValid() )
+ return false;
+ const OUString& aLibName( aDesc.GetLibName() );
+ EntryType eType = aDesc.GetType();
+
+ bool bSuccess = eType == OBJ_TYPE_MODULE ?
+ RenameModule(m_pDialog->getDialog(), aDocument, aLibName, aCurText, sNewText) :
+ RenameDialog(m_pDialog->getDialog(), aDocument, aLibName, aCurText, sNewText);
+
+ if ( !bSuccess )
+ return false;
+
+ MarkDocumentModified( aDocument );
+
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ {
+ SbxItem aSbxItem(SID_BASICIDE_ARG_SBX, aDocument, aLibName, sNewText, SbTreeListBox::ConvertType(eType));
+ pDispatcher->ExecuteList( SID_BASICIDE_SBXRENAMED,
+ SfxCallMode::SYNCHRON, { &aSbxItem });
+ }
+
+ // OV-Bug?!
+ m_xBasicBox->set_text(rEntry, sNewText);
+ m_xBasicBox->set_cursor(rEntry);
+ m_xBasicBox->unselect(rEntry);
+ m_xBasicBox->select(rEntry); // so that handler is called => update edit
+
+ return true;
+}
+
+void Shell::CopyDialogResources(
+ Reference< io::XInputStreamProvider >& io_xISP,
+ ScriptDocument const& rSourceDoc,
+ OUString const& rSourceLibName,
+ ScriptDocument const& rDestDoc,
+ OUString const& rDestLibName,
+ std::u16string_view rDlgName
+)
+{
+ if ( !io_xISP.is() )
+ return;
+
+ // Get StringResourceManager
+ Reference< container::XNameContainer > xSourceDialogLib( rSourceDoc.getLibrary( E_DIALOGS, rSourceLibName, true ) );
+ Reference< XStringResourceManager > xSourceMgr =
+ LocalizationMgr::getStringResourceFromDialogLibrary( xSourceDialogLib );
+ if( !xSourceMgr.is() )
+ return;
+ bool bSourceLocalized = xSourceMgr->getLocales().hasElements();
+
+ Reference< container::XNameContainer > xDestDialogLib( rDestDoc.getLibrary( E_DIALOGS, rDestLibName, true ) );
+ Reference< XStringResourceManager > xDestMgr =
+ LocalizationMgr::getStringResourceFromDialogLibrary( xDestDialogLib );
+ if( !xDestMgr.is() )
+ return;
+ bool bDestLocalized = xDestMgr->getLocales().hasElements();
+
+ if( !bSourceLocalized && !bDestLocalized )
+ return;
+
+ // create dialog model
+ Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
+ Reference< container::XNameContainer > xDialogModel( xContext->getServiceManager()->createInstanceWithContext
+ ( "com.sun.star.awt.UnoControlDialogModel", xContext ), UNO_QUERY );
+ Reference< io::XInputStream > xInput( io_xISP->createInputStream() );
+ ::xmlscript::importDialogModel( xInput, xDialogModel, xContext, rSourceDoc.isDocument() ? rSourceDoc.getDocument() : Reference< frame::XModel >() );
+
+ if( !xDialogModel.is() )
+ return;
+
+ if( bSourceLocalized && bDestLocalized )
+ {
+ LocalizationMgr::copyResourceForDroppedDialog( xDialogModel, rDlgName, xDestMgr, xSourceMgr );
+ }
+ else if( bSourceLocalized )
+ {
+ LocalizationMgr::resetResourceForDialog( xDialogModel, xSourceMgr );
+ }
+ else if( bDestLocalized )
+ {
+ LocalizationMgr::setResourceIDsForDialog( xDialogModel, xDestMgr );
+ }
+ io_xISP = ::xmlscript::exportDialogModel( xDialogModel, xContext, rDestDoc.isDocument() ? rDestDoc.getDocument() : Reference< frame::XModel >() );
+}
+
+// OrganizeDialog
+OrganizeDialog::OrganizeDialog(weld::Window* pParent, sal_Int16 tabId )
+ : GenericDialogController(pParent, "modules/BasicIDE/ui/organizedialog.ui", "OrganizeDialog")
+ , m_xTabCtrl(m_xBuilder->weld_notebook("tabcontrol"))
+ , m_xModulePage(new ObjectPage(m_xTabCtrl->get_page("modules"), "ModulePage", BrowseMode::Modules, this))
+ , m_xDialogPage(new ObjectPage(m_xTabCtrl->get_page("dialogs"), "DialogPage", BrowseMode::Dialogs, this))
+ , m_xLibPage(new LibPage(m_xTabCtrl->get_page("libraries"), this))
+{
+ m_xTabCtrl->connect_enter_page(LINK(this, OrganizeDialog, ActivatePageHdl));
+
+ OString sPage;
+ if (tabId == 0)
+ sPage = "modules";
+ else if (tabId == 1)
+ sPage = "dialogs";
+ else
+ sPage = "libraries";
+ m_xTabCtrl->set_current_page(sPage);
+ ActivatePageHdl(sPage);
+
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES );
+}
+
+IMPL_LINK(OrganizeDialog, ActivatePageHdl, const OString&, rPage, void)
+{
+ if (rPage == "modules")
+ m_xModulePage->ActivatePage();
+ else if (rPage == "dialogs")
+ m_xDialogPage->ActivatePage();
+ else if (rPage == "libraries")
+ m_xLibPage->ActivatePage();
+}
+
+OrganizeDialog::~OrganizeDialog()
+{
+}
+
+OrganizePage::OrganizePage(weld::Container* pParent, const OUString& rUIFile, const OString &rName, OrganizeDialog* pDialog)
+ : m_pDialog(pDialog)
+ , m_xBuilder(Application::CreateBuilder(pParent, rUIFile))
+ , m_xContainer(m_xBuilder->weld_container(rName))
+{
+}
+
+OrganizePage::~OrganizePage()
+{
+}
+
+class SbTreeListBoxDropTarget : public DropTargetHelper
+{
+private:
+ SbTreeListBox& m_rTreeView;
+
+ virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
+ {
+ // to enable the autoscroll when we're close to the edges
+ weld::TreeView& rWidget = m_rTreeView.get_widget();
+ rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
+
+ weld::TreeView* pSource = rWidget.get_drag_source();
+ if (!pSource)
+ return DND_ACTION_NONE;
+
+ // tdf#145722 only return a DND_ACTION_MOVE possibility if that
+ // is requested as an option
+ const bool bCheckForMove = rEvt.mnAction & DND_ACTION_MOVE;
+
+ sal_Int8 nMode = DND_ACTION_NONE;
+
+ std::unique_ptr<weld::TreeIter> xEntry(pSource->make_iterator());
+ if (pSource->get_selected(xEntry.get()))
+ {
+ sal_uInt16 nDepth = pSource->get_iter_depth(*xEntry);
+ if (nDepth >= 2)
+ {
+ nMode = DND_ACTION_COPY;
+ if (bCheckForMove)
+ {
+ EntryDescriptor aDesc = m_rTreeView.GetEntryDescriptor(xEntry.get());
+ const ScriptDocument& aDocument( aDesc.GetDocument() );
+ const OUString& aLibName( aDesc.GetLibName() );
+ // allow MOVE mode only for libraries, which are not readonly
+ Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ Reference< script::XLibraryContainer2 > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+ if ( !( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) ) ||
+ ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) ) ) )
+ {
+ // Only allow copy for localized libraries
+ bool bAllowMove = true;
+ if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) )
+ {
+ // Get StringResourceManager
+ Reference< container::XNameContainer > xDialogLib( aDocument.getLibrary( E_DIALOGS, aLibName, true ) );
+ Reference< XStringResourceManager > xSourceMgr =
+ LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib );
+ if( xSourceMgr.is() )
+ bAllowMove = ( xSourceMgr->getLocales().getLength() == 0 );
+ }
+ if( bAllowMove )
+ nMode |= DND_ACTION_MOVE;
+ }
+ }
+ }
+ }
+ return nMode;
+ }
+
+ virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
+ {
+ weld::TreeView& rWidget = m_rTreeView.get_widget();
+ weld::TreeView* pSource = rWidget.get_drag_source();
+ if (!pSource)
+ return DND_ACTION_NONE;
+
+ std::unique_ptr<weld::TreeIter> xEntry(rWidget.make_iterator());
+ bool bEntry = rWidget.get_dest_row_at_pos(rEvt.maPosPixel, xEntry.get(), true);
+
+ // don't drop on a BasicManager (nDepth == 0)
+ sal_uInt16 nDepth = bEntry ? m_rTreeView.get_iter_depth(*xEntry) : 0;
+ bool bValid = nDepth != 0;
+ // don't drop in the same library
+ std::unique_ptr<weld::TreeIter> xSelected(pSource->make_iterator());
+ bool bSelected = pSource->get_selected(xSelected.get());
+ if (!bSelected)
+ bValid = false;
+ else if (nDepth == 1)
+ {
+ std::unique_ptr<weld::TreeIter> xSelParent(pSource->make_iterator(xSelected.get()));
+ if (pSource->iter_parent(*xSelParent) && pSource->iter_compare(*xEntry, *xSelParent) == 0)
+ bValid = false;
+ }
+ else if (nDepth == 2)
+ {
+ std::unique_ptr<weld::TreeIter> xParent(pSource->make_iterator(xEntry.get()));
+ std::unique_ptr<weld::TreeIter> xSelParent(pSource->make_iterator(xSelected.get()));
+ if (pSource->iter_parent(*xParent) && pSource->iter_parent(*xSelParent) && pSource->iter_compare(*xParent, *xSelParent) == 0)
+ bValid = false;
+ }
+
+ // don't drop on a library, which is not loaded, readonly or password protected
+ // or which already has a module/dialog with this name
+ if ( bValid && ( nDepth > 0 ) )
+ {
+ // get source module/dialog name
+ EntryDescriptor aSourceDesc = m_rTreeView.GetEntryDescriptor(xSelected.get());
+ const OUString& aSourceName = aSourceDesc.GetName();
+ EntryType eSourceType = aSourceDesc.GetType();
+
+ // get target shell and target library name
+ EntryDescriptor aDestDesc = m_rTreeView.GetEntryDescriptor(xEntry.get());
+ ScriptDocument const& rDestDoc = aDestDesc.GetDocument();
+ const OUString& aDestLibName = aDestDesc.GetLibName();
+
+ // check if module library is not loaded, readonly or password protected
+ Reference< script::XLibraryContainer2 > xModLibContainer( rDestDoc.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aDestLibName ) )
+ {
+ if ( !xModLibContainer->isLibraryLoaded( aDestLibName ) )
+ bValid = false;
+
+ if ( xModLibContainer->isLibraryReadOnly( aDestLibName ) )
+ bValid = false;
+
+ Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
+ if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aDestLibName ) && !xPasswd->isLibraryPasswordVerified( aDestLibName ) )
+ bValid = false;
+ }
+
+ // check if dialog library is not loaded or readonly
+ Reference< script::XLibraryContainer2 > xDlgLibContainer( rDestDoc.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+ if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aDestLibName ) )
+ {
+ if ( !xDlgLibContainer->isLibraryLoaded( aDestLibName ) )
+ bValid = false;
+
+ if ( xDlgLibContainer->isLibraryReadOnly( aDestLibName ) )
+ bValid = false;
+ }
+
+ // check, if module/dialog with this name is already existing in target library
+ if ( ( eSourceType == OBJ_TYPE_MODULE && rDestDoc.hasModule( aDestLibName, aSourceName ) ) ||
+ ( eSourceType == OBJ_TYPE_DIALOG && rDestDoc.hasDialog( aDestLibName, aSourceName ) ) )
+ {
+ bValid = false;
+ }
+ }
+
+ if (bValid)
+ NotifyCopyingMoving(*xEntry, rEvt.mnAction & DND_ACTION_MOVE);
+
+ return DND_ACTION_NONE;
+ }
+
+ void NotifyCopyingMoving(const weld::TreeIter& rTarget, bool bMove)
+ {
+ sal_uInt16 nDepth = m_rTreeView.get_iter_depth(rTarget);
+ std::unique_ptr<weld::TreeIter> xNewParent(m_rTreeView.make_iterator(&rTarget));
+ int nNewChildPos = 0;
+ DBG_ASSERT( nDepth, "Depth?" );
+ if ( nDepth >= 2 )
+ {
+ // Target = module/dialog => put module/dialog under the superordinate Basic
+ m_rTreeView.iter_parent(*xNewParent);
+ nNewChildPos = m_rTreeView.get_iter_index_in_parent(rTarget) + 1;
+ }
+
+ // get target shell and target library name
+ EntryDescriptor aDestDesc = m_rTreeView.GetEntryDescriptor(xNewParent.get());
+ const ScriptDocument& rDestDoc( aDestDesc.GetDocument() );
+ const OUString& aDestLibName( aDestDesc.GetLibName() );
+
+ // get source shell, library name and module/dialog name
+ std::unique_ptr<weld::TreeIter> xSelected(m_rTreeView.make_iterator());
+ if (!m_rTreeView.get_selected(xSelected.get()))
+ xSelected.reset();
+ EntryDescriptor aSourceDesc = m_rTreeView.GetEntryDescriptor(xSelected.get());
+ const ScriptDocument& rSourceDoc( aSourceDesc.GetDocument() );
+ const OUString& aSourceLibName( aSourceDesc.GetLibName() );
+ const OUString& aSourceName( aSourceDesc.GetName() );
+ EntryType eType = aSourceDesc.GetType();
+
+ // get dispatcher
+ SfxDispatcher* pDispatcher = GetDispatcher();
+
+ if ( bMove ) // move
+ {
+ // remove source module/dialog window
+ if ( rSourceDoc != rDestDoc || aSourceLibName != aDestLibName )
+ {
+ if( pDispatcher )
+ {
+ SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, rSourceDoc, aSourceLibName, aSourceName, SbTreeListBox::ConvertType(eType) );
+ pDispatcher->ExecuteList( SID_BASICIDE_SBXDELETED,
+ SfxCallMode::SYNCHRON, { &aSbxItem });
+ }
+ }
+
+ try
+ {
+ if ( eType == OBJ_TYPE_MODULE ) // module
+ {
+ // get module
+ OUString aModule;
+ if ( rSourceDoc.getModule( aSourceLibName, aSourceName, aModule ) )
+ {
+ // remove module from source library
+ if ( rSourceDoc.removeModule( aSourceLibName, aSourceName ) )
+ {
+ MarkDocumentModified( rSourceDoc );
+
+ // insert module into target library
+ if ( rDestDoc.insertModule( aDestLibName, aSourceName, aModule ) )
+ MarkDocumentModified( rDestDoc );
+ }
+ }
+ }
+ else if ( eType == OBJ_TYPE_DIALOG ) // dialog
+ {
+ // get dialog
+ Reference< io::XInputStreamProvider > xISP;
+ if ( rSourceDoc.getDialog( aSourceLibName, aSourceName, xISP ) )
+ {
+ Shell::CopyDialogResources( xISP, rSourceDoc,
+ aSourceLibName, rDestDoc, aDestLibName, aSourceName );
+
+ // remove dialog from source library
+ if (RemoveDialog(rSourceDoc, aSourceLibName, aSourceName))
+ {
+ MarkDocumentModified(rSourceDoc);
+
+ // insert dialog into target library
+ if ( rDestDoc.insertDialog( aDestLibName, aSourceName, xISP ) )
+ MarkDocumentModified(rDestDoc);
+ }
+ }
+ }
+ }
+ catch (const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+ else // copy
+ {
+ try
+ {
+ if ( eType == OBJ_TYPE_MODULE ) // module
+ {
+ // get module
+ OUString aModule;
+ if ( rSourceDoc.getModule( aSourceLibName, aSourceName, aModule ) )
+ {
+ // insert module into target library
+ if ( rDestDoc.insertModule( aDestLibName, aSourceName, aModule ) )
+ MarkDocumentModified( rDestDoc );
+ }
+ }
+ else if ( eType == OBJ_TYPE_DIALOG ) // dialog
+ {
+ // get dialog
+ Reference< io::XInputStreamProvider > xISP;
+ if ( rSourceDoc.getDialog( aSourceLibName, aSourceName, xISP ) )
+ {
+ Shell::CopyDialogResources( xISP, rSourceDoc,
+ aSourceLibName, rDestDoc, aDestLibName, aSourceName );
+
+ // insert dialog into target library
+ if ( rDestDoc.insertDialog( aDestLibName, aSourceName, xISP ) )
+ MarkDocumentModified( rDestDoc );
+ }
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+
+ OUString sText(m_rTreeView.get_text(*xSelected));
+ OUString sId(m_rTreeView.get_id(*xSelected));
+ /// if copying then clone the userdata
+ if (Entry* pEntry = bMove ? nullptr : weld::fromId<Entry*>(sId))
+ {
+ assert(pEntry->GetType() != OBJ_TYPE_DOCUMENT);
+ std::unique_ptr<Entry> xNewUserData(std::make_unique<Entry>(*pEntry));
+ sId = weld::toId(xNewUserData.release());
+ }
+ std::unique_ptr<weld::TreeIter> xRet(m_rTreeView.make_iterator());
+ m_rTreeView.get_widget().insert(xNewParent.get(), nNewChildPos, &sText, &sId, nullptr, nullptr, false, xRet.get());
+ if (eType == OBJ_TYPE_MODULE)
+ m_rTreeView.get_widget().set_image(*xRet, RID_BMP_MODULE);
+ else if (eType == OBJ_TYPE_DIALOG)
+ m_rTreeView.get_widget().set_image(*xRet, RID_BMP_DIALOG);
+ if (!m_rTreeView.get_row_expanded(*xNewParent))
+ m_rTreeView.expand_row(*xNewParent);
+ m_rTreeView.select(*xRet);
+
+ if (bMove)
+ m_rTreeView.remove(*xSelected);
+
+ // create target module/dialog window
+ if ( rSourceDoc != rDestDoc || aSourceLibName != aDestLibName )
+ {
+ if( pDispatcher )
+ {
+ SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, rDestDoc, aDestLibName, aSourceName, SbTreeListBox::ConvertType(eType) );
+ pDispatcher->ExecuteList( SID_BASICIDE_SBXINSERTED,
+ SfxCallMode::SYNCHRON, { &aSbxItem });
+ }
+ }
+ }
+
+public:
+ SbTreeListBoxDropTarget(SbTreeListBox& rTreeView)
+ : DropTargetHelper(rTreeView.get_widget().get_drop_target())
+ , m_rTreeView(rTreeView)
+ {
+ }
+};
+
+// ObjectPage
+ObjectPage::ObjectPage(weld::Container* pParent, const OString &rName, BrowseMode nMode, OrganizeDialog* pDialog)
+ : OrganizePage(pParent, "modules/BasicIDE/ui/" + OStringToOUString(rName, RTL_TEXTENCODING_UTF8).toAsciiLowerCase() + ".ui",
+ rName, pDialog)
+ , m_xBasicBox(new SbTreeListBox(m_xBuilder->weld_tree_view("library"), pDialog->getDialog()))
+ , m_xEditButton(m_xBuilder->weld_button("edit"))
+ , m_xNewModButton(m_xBuilder->weld_button("newmodule"))
+ , m_xNewDlgButton(m_xBuilder->weld_button("newdialog"))
+ , m_xDelButton(m_xBuilder->weld_button("delete"))
+{
+ Size aSize(m_xBasicBox->get_approximate_digit_width() * 40,
+ m_xBasicBox->get_height_rows(14));
+ m_xBasicBox->set_size_request(aSize.Width(), aSize.Height());
+
+ // tdf#93476 The dialogs should be listed alphabetically
+ m_xBasicBox->make_sorted();
+
+ m_xEditButton->connect_clicked( LINK( this, ObjectPage, ButtonHdl ) );
+ m_xDelButton->connect_clicked( LINK( this, ObjectPage, ButtonHdl ) );
+ m_xBasicBox->connect_changed( LINK( this, ObjectPage, BasicBoxHighlightHdl ) );
+
+ if( nMode & BrowseMode::Modules )
+ {
+ m_xNewModButton->connect_clicked( LINK( this, ObjectPage, ButtonHdl ) );
+ m_xNewDlgButton->hide();
+ }
+ else if ( nMode & BrowseMode::Dialogs )
+ {
+ m_xNewDlgButton->connect_clicked( LINK( this, ObjectPage, ButtonHdl ) );
+ m_xNewModButton->hide();
+ }
+
+ m_xDropTarget.reset(new SbTreeListBoxDropTarget(*m_xBasicBox));
+ // tdf#145722 explicitly claim COPY and MOVE are options
+ rtl::Reference<TransferDataContainer> xHelper(new TransferDataContainer);
+ m_xBasicBox->get_widget().enable_drag_source(xHelper, DND_ACTION_COPYMOVE);
+
+ m_xBasicBox->connect_editing(LINK(this, ObjectPage, EditingEntryHdl),
+ LINK(this, ObjectPage, EditedEntryHdl));
+
+ m_xBasicBox->SetMode( nMode );
+ m_xBasicBox->ScanAllEntries();
+
+ m_xEditButton->grab_focus();
+ CheckButtons();
+}
+
+ObjectPage::~ObjectPage()
+{
+}
+
+void ObjectPage::ActivatePage()
+{
+ m_xBasicBox->UpdateEntries();
+ CheckButtons();
+}
+
+void ObjectPage::CheckButtons()
+{
+ // enable/disable edit button
+ std::unique_ptr<weld::TreeIter> xCurEntry(m_xBasicBox->make_iterator());
+ if (!m_xBasicBox->get_cursor(xCurEntry.get()))
+ xCurEntry.reset();
+ EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(xCurEntry.get());
+ const ScriptDocument& aDocument( aDesc.GetDocument() );
+ const OUString& aLibName( aDesc.GetLibName() );
+ const OUString& aLibSubName( aDesc.GetLibSubName() );
+ bool bVBAEnabled = aDocument.isInVBAMode();
+ BrowseMode nMode = m_xBasicBox->GetMode();
+
+ sal_uInt16 nDepth = xCurEntry ? m_xBasicBox->get_iter_depth(*xCurEntry) : 0;
+ if ( nDepth >= 2 )
+ {
+ if( bVBAEnabled && ( nMode & BrowseMode::Modules ) && ( nDepth == 2 ) )
+ m_xEditButton->set_sensitive(false);
+ else
+ m_xEditButton->set_sensitive(true);
+ }
+ else
+ m_xEditButton->set_sensitive(false);
+
+ // enable/disable new module/dialog buttons
+ LibraryLocation eLocation( aDesc.GetLocation() );
+ bool bReadOnly = false;
+ if ( nDepth > 0 )
+ {
+ Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ Reference< script::XLibraryContainer2 > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
+ if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) ) ||
+ ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) ) )
+ {
+ bReadOnly = true;
+ }
+ }
+ if ( bReadOnly || eLocation == LIBRARY_LOCATION_SHARE )
+ {
+ m_xNewModButton->set_sensitive(false);
+ m_xNewDlgButton->set_sensitive(false);
+ }
+ else
+ {
+ m_xNewModButton->set_sensitive(true);
+ m_xNewDlgButton->set_sensitive(true);
+ }
+
+ // enable/disable delete button
+ if ( nDepth >= 2 && !bReadOnly && eLocation != LIBRARY_LOCATION_SHARE )
+ {
+ if( bVBAEnabled && ( nMode & BrowseMode::Modules ) && ( ( nDepth == 2 ) || aLibSubName == IDEResId(RID_STR_DOCUMENT_OBJECTS) ) )
+ m_xDelButton->set_sensitive(false);
+ else
+ m_xDelButton->set_sensitive(true);
+ }
+ else
+ m_xDelButton->set_sensitive(false);
+}
+
+IMPL_LINK_NOARG(ObjectPage, BasicBoxHighlightHdl, weld::TreeView&, void)
+{
+ CheckButtons();
+}
+
+IMPL_LINK(ObjectPage, ButtonHdl, weld::Button&, rButton, void)
+{
+ if (&rButton == m_xEditButton.get())
+ {
+ SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
+ SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs );
+ SfxGetpApp()->ExecuteSlot( aRequest );
+
+ SfxDispatcher* pDispatcher = GetDispatcher();
+
+ std::unique_ptr<weld::TreeIter> xCurEntry(m_xBasicBox->make_iterator());
+ if (!m_xBasicBox->get_cursor(xCurEntry.get()))
+ return;
+ if (m_xBasicBox->get_iter_depth(*xCurEntry) >= 2)
+ {
+ EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(xCurEntry.get());
+ if ( pDispatcher )
+ {
+ OUString aModName( aDesc.GetName() );
+ // extract the module name from the string like "Sheet1 (Example1)"
+ if( aDesc.GetLibSubName() == IDEResId(RID_STR_DOCUMENT_OBJECTS) )
+ {
+ aModName = aModName.getToken( 0, ' ' );
+ }
+ SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, aDesc.GetDocument(), aDesc.GetLibName(),
+ aModName, SbTreeListBox::ConvertType( aDesc.GetType() ) );
+ pDispatcher->ExecuteList(SID_BASICIDE_SHOWSBX,
+ SfxCallMode::SYNCHRON, { &aSbxItem });
+ }
+ }
+ else // only Lib selected
+ {
+ DBG_ASSERT( m_xBasicBox->get_iter_depth(*xCurEntry) == 1, "No LibEntry?!" );
+ ScriptDocument aDocument( ScriptDocument::getApplicationScriptDocument() );
+ std::unique_ptr<weld::TreeIter> xParentEntry(m_xBasicBox->make_iterator(xCurEntry.get()));
+ if (m_xBasicBox->iter_parent(*xParentEntry))
+ {
+ DocumentEntry* pDocumentEntry = weld::fromId<DocumentEntry*>(m_xBasicBox->get_id(*xParentEntry));
+ if (pDocumentEntry)
+ aDocument = pDocumentEntry->GetDocument();
+ }
+ SfxUnoAnyItem aDocItem( SID_BASICIDE_ARG_DOCUMENT_MODEL, Any( aDocument.getDocumentOrNull() ) );
+ OUString aLibName(m_xBasicBox->get_text(*xCurEntry));
+ SfxStringItem aLibNameItem( SID_BASICIDE_ARG_LIBNAME, aLibName );
+ if ( pDispatcher )
+ {
+ pDispatcher->ExecuteList(SID_BASICIDE_LIBSELECTED,
+ SfxCallMode::ASYNCHRON, { &aDocItem, &aLibNameItem });
+ }
+ }
+ EndTabDialog();
+ }
+ else if (&rButton == m_xNewModButton.get())
+ NewModule();
+ else if (&rButton == m_xNewDlgButton.get())
+ NewDialog();
+ else if (&rButton == m_xDelButton.get())
+ DeleteCurrent();
+}
+
+bool ObjectPage::GetSelection( ScriptDocument& rDocument, OUString& rLibName )
+{
+ bool bRet = false;
+
+ std::unique_ptr<weld::TreeIter> xCurEntry(m_xBasicBox->make_iterator());
+ if (!m_xBasicBox->get_cursor(xCurEntry.get()))
+ xCurEntry.reset();
+ EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(xCurEntry.get());
+ rDocument = aDesc.GetDocument();
+ rLibName = aDesc.GetLibName();
+ if ( rLibName.isEmpty() )
+ rLibName = "Standard" ;
+
+ DBG_ASSERT( rDocument.isAlive(), "ObjectPage::GetSelection: no or dead ScriptDocument in the selection!" );
+ if ( !rDocument.isAlive() )
+ return false;
+
+ // check if the module library is loaded
+ bool bOK = true;
+ OUString aLibName( rLibName );
+ Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) );
+ if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && !xModLibContainer->isLibraryLoaded( aLibName ) )
+ {
+ // check password
+ Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
+ if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) && !xPasswd->isLibraryPasswordVerified( aLibName ) )
+ {
+ OUString aPassword;
+ bOK = QueryPassword(m_pDialog->getDialog(), xModLibContainer, rLibName, aPassword);
+ }
+
+ // load library
+ if ( bOK )
+ xModLibContainer->loadLibrary( aLibName );
+ }
+
+ // check if the dialog library is loaded
+ Reference< script::XLibraryContainer > xDlgLibContainer( rDocument.getLibraryContainer( E_DIALOGS ) );
+ if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && !xDlgLibContainer->isLibraryLoaded( aLibName ) )
+ {
+ // load library
+ if ( bOK )
+ xDlgLibContainer->loadLibrary( aLibName );
+ }
+
+ if ( bOK )
+ bRet = true;
+
+ return bRet;
+}
+
+void ObjectPage::NewModule()
+{
+ ScriptDocument aDocument( ScriptDocument::getApplicationScriptDocument() );
+ OUString aLibName;
+
+ if ( GetSelection( aDocument, aLibName ) )
+ {
+ createModImpl(m_pDialog->getDialog(), aDocument,
+ *m_xBasicBox, aLibName, OUString(), true);
+ }
+}
+
+void ObjectPage::NewDialog()
+{
+ ScriptDocument aDocument( ScriptDocument::getApplicationScriptDocument() );
+ OUString aLibName;
+
+ if ( !GetSelection( aDocument, aLibName ) )
+ return;
+
+ aDocument.getOrCreateLibrary( E_DIALOGS, aLibName );
+
+ NewObjectDialog aNewDlg(m_pDialog->getDialog(), ObjectMode::Dialog, true);
+ aNewDlg.SetObjectName(aDocument.createObjectName(E_DIALOGS, aLibName));
+
+ if (aNewDlg.run() == RET_CANCEL)
+ return;
+
+ OUString aDlgName = aNewDlg.GetObjectName();
+ if (aDlgName.isEmpty())
+ aDlgName = aDocument.createObjectName( E_DIALOGS, aLibName);
+
+ if ( aDocument.hasDialog( aLibName, aDlgName ) )
+ {
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_pDialog->getDialog(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED2)));
+ xError->run();
+ }
+ else
+ {
+ Reference< io::XInputStreamProvider > xISP;
+ if ( !aDocument.createDialog( aLibName, aDlgName, xISP ) )
+ return;
+
+ SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, aDocument, aLibName, aDlgName, TYPE_DIALOG );
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ {
+ pDispatcher->ExecuteList( SID_BASICIDE_SBXINSERTED,
+ SfxCallMode::SYNCHRON, { &aSbxItem });
+ }
+ LibraryLocation eLocation = aDocument.getLibraryLocation( aLibName );
+ std::unique_ptr<weld::TreeIter> xIter(m_xBasicBox->make_iterator());
+ bool bRootEntry = m_xBasicBox->FindRootEntry(aDocument, eLocation, *xIter);
+ if (bRootEntry)
+ {
+ if (!m_xBasicBox->get_row_expanded(*xIter))
+ m_xBasicBox->expand_row(*xIter);
+ bool bLibEntry = m_xBasicBox->FindEntry(aLibName, OBJ_TYPE_LIBRARY, *xIter);
+ DBG_ASSERT( bLibEntry, "LibEntry not found!" );
+ if (bLibEntry)
+ {
+ if (!m_xBasicBox->get_row_expanded(*xIter))
+ m_xBasicBox->expand_row(*xIter);
+ std::unique_ptr<weld::TreeIter> xSubRootEntry(m_xBasicBox->make_iterator(xIter.get()));
+ bool bDlgEntry = m_xBasicBox->FindEntry(aDlgName, OBJ_TYPE_DIALOG, *xIter);
+ if (!bDlgEntry)
+ {
+ m_xBasicBox->AddEntry(aDlgName, RID_BMP_DIALOG, xSubRootEntry.get(), false,
+ std::make_unique<Entry>(OBJ_TYPE_DIALOG), xIter.get());
+ assert(xIter && "Insert entry failed!");
+ }
+ m_xBasicBox->set_cursor(*xIter);
+ m_xBasicBox->select(*xIter);
+ }
+ }
+ }
+}
+
+void ObjectPage::DeleteCurrent()
+{
+ std::unique_ptr<weld::TreeIter> xCurEntry(m_xBasicBox->make_iterator());
+ if (!m_xBasicBox->get_cursor(xCurEntry.get()))
+ xCurEntry.reset();
+ DBG_ASSERT( xCurEntry, "No current entry!" );
+ if (!xCurEntry)
+ return;
+ EntryDescriptor aDesc( m_xBasicBox->GetEntryDescriptor( xCurEntry.get() ) );
+ const ScriptDocument& aDocument( aDesc.GetDocument() );
+ DBG_ASSERT( aDocument.isAlive(), "ObjectPage::DeleteCurrent: no document!" );
+ if ( !aDocument.isAlive() )
+ return;
+ const OUString& aLibName( aDesc.GetLibName() );
+ const OUString& aName( aDesc.GetName() );
+ EntryType eType = aDesc.GetType();
+
+ if ( !(( eType == OBJ_TYPE_MODULE && QueryDelModule(aName, m_pDialog->getDialog()) ) ||
+ ( eType == OBJ_TYPE_DIALOG && QueryDelDialog(aName, m_pDialog->getDialog()) )) )
+ return;
+
+ m_xBasicBox->remove(*xCurEntry);
+ if (m_xBasicBox->get_cursor(xCurEntry.get()))
+ m_xBasicBox->select(*xCurEntry);
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ {
+ SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, aDocument, aLibName, aName, SbTreeListBox::ConvertType( eType ) );
+ pDispatcher->ExecuteList( SID_BASICIDE_SBXDELETED,
+ SfxCallMode::SYNCHRON, { &aSbxItem });
+ }
+
+ try
+ {
+ bool bSuccess = false;
+ if ( eType == OBJ_TYPE_MODULE )
+ bSuccess = aDocument.removeModule( aLibName, aName );
+ else if ( eType == OBJ_TYPE_DIALOG )
+ bSuccess = RemoveDialog( aDocument, aLibName, aName );
+
+ if ( bSuccess )
+ MarkDocumentModified( aDocument );
+ }
+ catch (const container::NoSuchElementException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+}
+
+void ObjectPage::EndTabDialog()
+{
+ m_pDialog->response(RET_OK);
+}
+
+LibDialog::LibDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "modules/BasicIDE/ui/importlibdialog.ui", "ImportLibDialog")
+ , m_xStorageFrame(m_xBuilder->weld_frame("storageframe"))
+ , m_xLibBox(m_xBuilder->weld_tree_view("entries"))
+ , m_xReferenceBox(m_xBuilder->weld_check_button("ref"))
+ , m_xReplaceBox(m_xBuilder->weld_check_button("replace"))
+{
+ m_xLibBox->set_size_request(m_xLibBox->get_approximate_digit_width() * 28,
+ m_xLibBox->get_height_rows(8));
+ m_xLibBox->enable_toggle_buttons(weld::ColumnToggleType::Check);
+ // tdf#93476 The libraries should be listed alphabetically
+ m_xLibBox->make_sorted();
+}
+
+LibDialog::~LibDialog()
+{
+}
+
+void LibDialog::SetStorageName( std::u16string_view rName )
+{
+ OUString aName = IDEResId(RID_STR_FILENAME) + rName;
+ m_xStorageFrame->set_label(aName);
+}
+
+// Helper function
+SbModule* createModImpl(weld::Window* pWin, const ScriptDocument& rDocument,
+ SbTreeListBox& rBasicBox, const OUString& rLibName, const OUString& _aModName, bool bMain )
+{
+ OSL_ENSURE( rDocument.isAlive(), "createModImpl: invalid document!" );
+ if ( !rDocument.isAlive() )
+ return nullptr;
+
+ SbModule* pModule = nullptr;
+
+ OUString aLibName( rLibName );
+ if ( aLibName.isEmpty() )
+ aLibName = "Standard" ;
+ rDocument.getOrCreateLibrary( E_SCRIPTS, aLibName );
+ OUString aModName = _aModName;
+ if ( aModName.isEmpty() )
+ aModName = rDocument.createObjectName( E_SCRIPTS, aLibName );
+
+ NewObjectDialog aNewDlg(pWin, ObjectMode::Module, true);
+ aNewDlg.SetObjectName(aModName);
+
+ if (aNewDlg.run() != RET_CANCEL)
+ {
+ if (!aNewDlg.GetObjectName().isEmpty())
+ aModName = aNewDlg.GetObjectName();
+
+ try
+ {
+ OUString sModuleCode;
+ // the module has existed
+ if( rDocument.hasModule( aLibName, aModName ) )
+ return nullptr;
+ rDocument.createModule( aLibName, aModName, bMain, sModuleCode );
+ BasicManager* pBasMgr = rDocument.getBasicManager();
+ StarBASIC* pBasic = pBasMgr? pBasMgr->GetLib( aLibName ) : nullptr;
+ if ( pBasic )
+ pModule = pBasic->FindModule( aModName );
+ SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, rDocument, aLibName, aModName, TYPE_MODULE );
+ if (SfxDispatcher* pDispatcher = GetDispatcher())
+ {
+ pDispatcher->ExecuteList( SID_BASICIDE_SBXINSERTED,
+ SfxCallMode::SYNCHRON, { &aSbxItem });
+ }
+ LibraryLocation eLocation = rDocument.getLibraryLocation( aLibName );
+ std::unique_ptr<weld::TreeIter> xIter(rBasicBox.make_iterator());
+ bool bRootEntry = rBasicBox.FindRootEntry(rDocument, eLocation, *xIter);
+ if (bRootEntry)
+ {
+ if (!rBasicBox.get_row_expanded(*xIter))
+ rBasicBox.expand_row(*xIter);
+ bool bLibEntry = rBasicBox.FindEntry(aLibName, OBJ_TYPE_LIBRARY, *xIter);
+ DBG_ASSERT( bLibEntry, "LibEntry not found!" );
+ if (bLibEntry)
+ {
+ if (!rBasicBox.get_row_expanded(*xIter))
+ rBasicBox.expand_row(*xIter);
+ std::unique_ptr<weld::TreeIter> xSubRootEntry(rBasicBox.make_iterator(xIter.get()));
+ if (pBasic && rDocument.isInVBAMode())
+ {
+ // add the new module in the "Modules" entry
+ std::unique_ptr<weld::TreeIter> xLibSubEntry(rBasicBox.make_iterator(xIter.get()));
+ bool bLibSubEntry = rBasicBox.FindEntry(IDEResId(RID_STR_NORMAL_MODULES) , OBJ_TYPE_NORMAL_MODULES, *xLibSubEntry);
+ if (bLibSubEntry)
+ {
+ if (!rBasicBox.get_row_expanded(*xLibSubEntry))
+ rBasicBox.expand_row(*xLibSubEntry);
+ rBasicBox.copy_iterator(*xLibSubEntry, *xSubRootEntry);
+ }
+ }
+
+ std::unique_ptr<weld::TreeIter> xEntry(rBasicBox.make_iterator(xSubRootEntry.get()));
+ bool bEntry = rBasicBox.FindEntry(aModName, OBJ_TYPE_MODULE, *xEntry);
+ if (!bEntry)
+ {
+ rBasicBox.AddEntry(aModName, RID_BMP_MODULE, xSubRootEntry.get(), false,
+ std::make_unique<Entry>(OBJ_TYPE_MODULE), xEntry.get());
+ }
+ rBasicBox.set_cursor(*xEntry);
+ rBasicBox.select(*xEntry);
+ }
+ }
+ }
+ catch (const container::ElementExistException& )
+ {
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pWin,
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED2)));
+ xError->run();
+ }
+ catch (const container::NoSuchElementException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+ return pModule;
+}
+
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/moduldlg.hxx b/basctl/source/basicide/moduldlg.hxx
new file mode 100644
index 000000000..7dadebcc9
--- /dev/null
+++ b/basctl/source/basicide/moduldlg.hxx
@@ -0,0 +1,222 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <bastype2.hxx>
+#include <vcl/weld.hxx>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+
+class SvxPasswordDialog;
+
+namespace basctl
+{
+
+enum class ObjectMode
+{
+ Library = 1,
+ Module = 2,
+ Dialog = 3,
+};
+
+class NewObjectDialog : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::Entry> m_xEdit;
+ std::unique_ptr<weld::Button> m_xOKButton;
+ bool m_bCheckName;
+
+ DECL_LINK(OkButtonHandler, weld::Button&, void);
+public:
+ NewObjectDialog(weld::Window* pParent, ObjectMode, bool bCheckName = false);
+ OUString GetObjectName() const { return m_xEdit->get_text(); }
+ void SetObjectName(const OUString& rName)
+ {
+ m_xEdit->set_text(rName);
+ m_xEdit->select_region(0, -1);
+ }
+};
+
+class GotoLineDialog : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::Entry> m_xEdit;
+ std::unique_ptr<weld::Button> m_xOKButton;
+ DECL_LINK(OkButtonHandler, weld::Button&, void);
+public:
+ explicit GotoLineDialog(weld::Window* pParent);
+ virtual ~GotoLineDialog() override;
+ sal_Int32 GetLineNumber() const;
+};
+
+class ExportDialog : public weld::GenericDialogController
+{
+private:
+ bool m_bExportAsPackage;
+
+ std::unique_ptr<weld::RadioButton> m_xExportAsPackageButton;
+ std::unique_ptr<weld::Button> m_xOKButton;
+
+ DECL_LINK(OkButtonHandler, weld::Button&, void);
+
+public:
+ explicit ExportDialog(weld::Window * pParent);
+ virtual ~ExportDialog() override;
+
+ bool isExportAsPackage () const { return m_bExportAsPackage; }
+};
+
+class LibDialog : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::Frame> m_xStorageFrame;
+ std::unique_ptr<weld::TreeView> m_xLibBox;
+ std::unique_ptr<weld::CheckButton> m_xReferenceBox;
+ std::unique_ptr<weld::CheckButton> m_xReplaceBox;
+
+public:
+ explicit LibDialog(weld::Window* pParent);
+ virtual ~LibDialog() override;
+
+ void SetStorageName( std::u16string_view rName );
+
+ weld::TreeView& GetLibBox() { return *m_xLibBox; }
+ bool IsReference() const { return m_xReferenceBox->get_active(); }
+ bool IsReplace() const { return m_xReplaceBox->get_active(); }
+
+ void EnableReference (bool b) { m_xReferenceBox->set_sensitive(b); }
+};
+
+class OrganizeDialog;
+
+class OrganizePage
+{
+protected:
+ OrganizeDialog* m_pDialog;
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+
+ OrganizePage(weld::Container* pParent, const OUString& rUIFile, const OString &rName, OrganizeDialog* pDialog);
+ virtual ~OrganizePage();
+
+public:
+ virtual void ActivatePage() = 0;
+};
+
+class SbTreeListBoxDropTarget;
+
+class ObjectPage final : public OrganizePage
+{
+ std::unique_ptr<SbTreeListBox> m_xBasicBox;
+ std::unique_ptr<weld::Button> m_xEditButton;
+ std::unique_ptr<weld::Button> m_xNewModButton;
+ std::unique_ptr<weld::Button> m_xNewDlgButton;
+ std::unique_ptr<weld::Button> m_xDelButton;
+ std::unique_ptr<SbTreeListBoxDropTarget> m_xDropTarget;
+
+ DECL_LINK( BasicBoxHighlightHdl, weld::TreeView&, void );
+ DECL_LINK( ButtonHdl, weld::Button&, void );
+ DECL_LINK( EditingEntryHdl, const weld::TreeIter&, bool );
+ typedef std::pair<const weld::TreeIter&, OUString> IterString;
+ DECL_LINK( EditedEntryHdl, const IterString&, bool );
+
+ void CheckButtons();
+ bool GetSelection( ScriptDocument& rDocument, OUString& rLibName );
+ void DeleteCurrent();
+ void NewModule();
+ void NewDialog();
+ void EndTabDialog();
+
+public:
+ ObjectPage(weld::Container* pParent, const OString& rName, BrowseMode nMode, OrganizeDialog* pDialog);
+ virtual ~ObjectPage() override;
+
+ virtual void ActivatePage() override;
+};
+
+class LibPage final : public OrganizePage
+{
+ std::unique_ptr<weld::ComboBox> m_xBasicsBox;
+ std::unique_ptr<weld::TreeView> m_xLibBox;
+ std::unique_ptr<weld::Button> m_xEditButton;
+ std::unique_ptr<weld::Button> m_xPasswordButton;
+ std::unique_ptr<weld::Button> m_xNewLibButton;
+ std::unique_ptr<weld::Button> m_xInsertLibButton;
+ std::unique_ptr<weld::Button> m_xExportButton;
+ std::unique_ptr<weld::Button> m_xDelButton;
+
+ ScriptDocument m_aCurDocument;
+ LibraryLocation m_eCurLocation;
+
+ DECL_LINK( TreeListHighlightHdl, weld::TreeView&, void );
+ DECL_LINK( BasicSelectHdl, weld::ComboBox&, void );
+ DECL_LINK( ButtonHdl, weld::Button&, void );
+ DECL_LINK( CheckPasswordHdl, SvxPasswordDialog *, bool );
+ DECL_LINK( EditingEntryHdl, const weld::TreeIter&, bool );
+ typedef std::pair<const weld::TreeIter&, OUString> IterString;
+ DECL_LINK( EditedEntryHdl, const IterString&, bool );
+
+ void CheckButtons();
+ 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 );
+ void SetCurLib();
+ void ImpInsertLibEntry( const OUString& rLibName, int nPos );
+
+public:
+ explicit LibPage(weld::Container* pParent, OrganizeDialog* pDialog);
+ virtual ~LibPage() override;
+ virtual void ActivatePage() override;
+};
+
+class OrganizeDialog : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::Notebook> m_xTabCtrl;
+ std::unique_ptr<ObjectPage> m_xModulePage;
+ std::unique_ptr<ObjectPage> m_xDialogPage;
+ std::unique_ptr<LibPage> m_xLibPage;
+
+ DECL_LINK(ActivatePageHdl, const OString&, void);
+
+public:
+ OrganizeDialog(weld::Window* pParent, sal_Int16 tabId);
+ virtual ~OrganizeDialog() override;
+};
+
+// Helper functions
+SbModule* createModImpl(weld::Window* pWin, const ScriptDocument& rDocument,
+ SbTreeListBox& rBasicBox, const OUString& rLibName, const OUString& aModName, bool bMain);
+void createLibImpl(weld::Window* pWin, const ScriptDocument& rDocument,
+ weld::TreeView* pLibBox, SbTreeListBox* pBasicBox);
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/sbxitem.cxx b/basctl/source/basicide/sbxitem.cxx
new file mode 100644
index 000000000..39c86b1d0
--- /dev/null
+++ b/basctl/source/basicide/sbxitem.cxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sbxitem.hxx>
+#include <sal/log.hxx>
+#include <utility>
+
+namespace basctl
+{
+SfxPoolItem* SbxItem::CreateDefault() { SAL_WARN( "basctl.basicide", "No SbxItem factory available"); return nullptr; }
+SbxItem::SbxItem (
+ sal_uInt16 nWhichItem,
+ ScriptDocument aDocument,
+ OUString aLibName,
+ OUString aName,
+ ItemType eType
+) :
+ SfxPoolItem(nWhichItem),
+ m_aDocument(std::move(aDocument)),
+ m_aLibName(std::move(aLibName)),
+ m_aName(std::move(aName)),
+ m_eType(eType)
+{ }
+
+SbxItem::SbxItem (
+ sal_uInt16 nWhichItem,
+ ScriptDocument aDocument,
+ OUString aLibName,
+ OUString aName,
+ OUString aMethodName,
+ ItemType eType
+) :
+ SfxPoolItem(nWhichItem),
+ m_aDocument(std::move(aDocument)),
+ m_aLibName(std::move(aLibName)),
+ m_aName(std::move(aName)),
+ m_aMethodName(std::move(aMethodName)),
+ m_eType(eType)
+{ }
+
+SbxItem* SbxItem::Clone(SfxItemPool*) const
+{
+ return new SbxItem(*this);
+}
+
+bool SbxItem::operator==(const SfxPoolItem& rCmp) const
+{
+ SbxItem const* pSbxItem = static_cast<SbxItem const*>(&rCmp);
+ return
+ SfxPoolItem::operator==(rCmp) &&
+ m_aDocument == pSbxItem->m_aDocument &&
+ m_aLibName == pSbxItem->m_aLibName &&
+ m_aName == pSbxItem->m_aName &&
+ m_aMethodName == pSbxItem->m_aMethodName &&
+ m_eType == pSbxItem->m_eType;
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/scriptdocument.cxx b/basctl/source/basicide/scriptdocument.cxx
new file mode 100644
index 000000000..e23cfbe7a
--- /dev/null
+++ b/basctl/source/basicide/scriptdocument.cxx
@@ -0,0 +1,1505 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <scriptdocument.hxx>
+#include <basobj.hxx>
+#include <strings.hrc>
+#include <iderid.hxx>
+#include <dlgeddef.hxx>
+#include <doceventnotifier.hxx>
+#include "documentenumeration.hxx"
+
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/util/theMacroExpander.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/awt/XWindow2.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/XEmbeddedScripts.hpp>
+#include <com/sun/star/script/vba/XVBACompatibility.hpp>
+#include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
+#include <com/sun/star/script/ModuleInfo.hpp>
+#include <com/sun/star/script/ModuleType.hpp>
+
+#include <sfx2/app.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/docfile.hxx>
+
+#include <basic/basicmanagerrepository.hxx>
+
+#include <xmlscript/xmldlg_imexp.hxx>
+
+#include <i18nlangtag/languagetag.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <tools/debug.hxx>
+
+#include <comphelper/documentinfo.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/string.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+#include <osl/file.hxx>
+#include <rtl/uri.hxx>
+#include <set>
+
+
+namespace basctl
+{
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::script::XLibraryContainer;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::container::XNameContainer;
+ using ::com::sun::star::container::NoSuchElementException;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::task::XStatusIndicator;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::script::XLibraryContainer2;
+ using ::com::sun::star::uri::UriReferenceFactory;
+ using ::com::sun::star::uri::XUriReferenceFactory;
+ using ::com::sun::star::uri::XUriReference;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::util::XMacroExpander;
+ using ::com::sun::star::util::theMacroExpander;
+ using ::com::sun::star::io::XInputStreamProvider;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::io::XInputStream;
+ using ::com::sun::star::frame::XStorable;
+ using ::com::sun::star::util::XModifiable;
+ using ::com::sun::star::frame::XController;
+ using ::com::sun::star::frame::XFrame;
+ using ::com::sun::star::util::URL;
+ using ::com::sun::star::frame::XDispatchProvider;
+ using ::com::sun::star::frame::XDispatch;
+ using ::com::sun::star::beans::PropertyValue;
+ using ::com::sun::star::awt::XWindow2;
+ using ::com::sun::star::document::XEmbeddedScripts;
+ using ::com::sun::star::script::ModuleInfo;
+ using ::com::sun::star::script::vba::XVBACompatibility;
+ using ::com::sun::star::script::vba::XVBAModuleInfo;
+
+ namespace FrameSearchFlag = ::com::sun::star::frame::FrameSearchFlag;
+
+
+ namespace
+ {
+ class FilterDocuments : public docs::IDocumentDescriptorFilter
+ {
+ public:
+ explicit FilterDocuments(bool _bFilterInvisible)
+ : m_bFilterInvisible(_bFilterInvisible)
+ {
+ }
+
+ virtual ~FilterDocuments() {}
+
+ virtual bool includeDocument( const docs::DocumentDescriptor& _rDocument ) const override;
+
+ private:
+ static bool impl_isDocumentVisible_nothrow( const docs::DocumentDescriptor& _rDocument );
+
+ private:
+ bool m_bFilterInvisible;
+ };
+
+ bool FilterDocuments::impl_isDocumentVisible_nothrow( const docs::DocumentDescriptor& _rDocument )
+ {
+ try
+ {
+ for (auto const& controller : _rDocument.aControllers)
+ {
+ Reference< XFrame > xFrame( controller->getFrame(), UNO_SET_THROW );
+ Reference< XWindow2 > xContainer( xFrame->getContainerWindow(), UNO_QUERY_THROW );
+ if ( xContainer->isVisible() )
+ return true;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ return false;
+ }
+
+ bool FilterDocuments::includeDocument( const docs::DocumentDescriptor& _rDocument ) const
+ {
+ Reference< XEmbeddedScripts > xScripts( _rDocument.xModel, UNO_QUERY );
+ if ( !xScripts.is() )
+ return false;
+ return !m_bFilterInvisible || impl_isDocumentVisible_nothrow( _rDocument );
+ }
+
+ void lcl_getAllModels_throw( docs::Documents& _out_rModels, bool _bVisibleOnly )
+ {
+ _out_rModels.clear();
+
+ FilterDocuments aFilter( _bVisibleOnly );
+ docs::DocumentEnumeration aEnum(
+ comphelper::getProcessComponentContext(), &aFilter );
+
+ aEnum.getDocuments( _out_rModels );
+ }
+ }
+
+ class ScriptDocument::Impl : public DocumentEventListener
+ {
+ private:
+ bool m_bIsApplication;
+ bool m_bValid;
+ bool m_bDocumentClosed;
+ Reference< XModel > m_xDocument;
+ Reference< XModifiable > m_xDocModify;
+ Reference< XEmbeddedScripts > m_xScriptAccess;
+ std::unique_ptr< DocumentEventNotifier > m_pDocListener;
+
+ public:
+ Impl ();
+ explicit Impl(Reference<XModel> const& rxDocument);
+ virtual ~Impl() override;
+
+ /** determines whether the instance refers to a valid "document" with script and
+ dialog libraries
+ */
+ bool isValid() const { return m_bValid; }
+ /** determines whether the instance refers to a non-closed document
+ */
+ bool isAlive() const { return m_bValid && ( m_bIsApplication || !m_bDocumentClosed ); }
+ /// determines whether the "document" refers to the application in real
+ bool isApplication() const { return m_bValid && m_bIsApplication; }
+ /// determines whether the document refers to a real document (instead of the application)
+ bool isDocument() const { return m_bValid && !m_bIsApplication; }
+
+ /** invalidates the instance
+ */
+ void invalidate();
+
+ const Reference< XModel >&
+ getDocumentRef() const { return m_xDocument; }
+
+ /// returns a library container belonging to the document
+ Reference< XLibraryContainer >
+ getLibraryContainer( LibraryContainerType _eType ) const;
+
+ /// determines whether a given library is part of the shared installation
+ bool isLibraryShared( const OUString& _rLibName, LibraryContainerType _eType );
+
+ /** returns the current frame of the document
+
+ To be called for documents only, not for the application.
+
+ If <FALSE/> is returned, an assertion will be raised in non-product builds.
+ */
+ bool getCurrentFrame( Reference< XFrame >& _out_rxFrame ) const;
+
+ // versions with the same signature/semantics as in ScriptDocument itself
+ bool isReadOnly() const;
+ bool isInVBAMode() const;
+ BasicManager*
+ getBasicManager() const;
+ Reference< XModel >
+ getDocument() const;
+ void setDocumentModified() const;
+ bool isDocumentModified() const;
+ void saveDocument( const Reference< XStatusIndicator >& _rxStatusIndicator ) const;
+
+ OUString getTitle() const;
+ OUString getURL() const;
+
+ bool allowMacros() const;
+
+ Reference< XNameContainer >
+ getLibrary( LibraryContainerType _eType, const OUString& _rLibName, bool _bLoadLibrary ) const;
+ bool hasLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const;
+ Reference< XNameContainer >
+ getOrCreateLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const;
+
+ void loadLibraryIfExists( LibraryContainerType _eType, const OUString& _rLibrary );
+
+ bool removeModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rModuleName );
+ bool hasModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rModName ) const;
+ bool getModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rObjectName, Any& _out_rModuleOrDialog );
+ bool renameModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rOldName, const OUString& _rNewName, const Reference< XNameContainer >& _rxExistingDialogModel );
+ bool createModule( const OUString& _rLibName, const OUString& _rModName, bool _bCreateMain, OUString& _out_rNewModuleCode ) const;
+ bool insertModuleOrDialog( LibraryContainerType _eType, const OUString& _rObjectName, const OUString& _rModName, const Any& _rElement ) const;
+ bool updateModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const;
+ bool createDialog( const OUString& _rLibName, const OUString& _rDialogName, Reference< XInputStreamProvider >& _out_rDialogProvider ) const;
+
+ protected:
+ // DocumentEventListener
+ virtual void onDocumentCreated( const ScriptDocument& _rDocument ) override;
+ virtual void onDocumentOpened( const ScriptDocument& _rDocument ) override;
+ virtual void onDocumentSave( const ScriptDocument& _rDocument ) override;
+ virtual void onDocumentSaveDone( const ScriptDocument& _rDocument ) override;
+ virtual void onDocumentSaveAs( const ScriptDocument& _rDocument ) override;
+ virtual void onDocumentSaveAsDone( const ScriptDocument& _rDocument ) override;
+ virtual void onDocumentClosed( const ScriptDocument& _rDocument ) override;
+ virtual void onDocumentTitleChanged( const ScriptDocument& _rDocument ) override;
+ virtual void onDocumentModeChanged( const ScriptDocument& _rDocument ) override;
+
+ private:
+ bool impl_initDocument_nothrow( const Reference< XModel >& _rxModel );
+ };
+
+
+ ScriptDocument::Impl::Impl()
+ :m_bIsApplication( true )
+ ,m_bValid( true )
+ ,m_bDocumentClosed( false )
+ {
+ }
+
+ ScriptDocument::Impl::Impl( const Reference< XModel >& _rxDocument )
+ :m_bIsApplication( false )
+ ,m_bValid( false )
+ ,m_bDocumentClosed( false )
+ {
+ if ( _rxDocument.is() )
+ impl_initDocument_nothrow( _rxDocument );
+ }
+
+ ScriptDocument::Impl::~Impl()
+ {
+ invalidate();
+ }
+
+ void ScriptDocument::Impl::invalidate()
+ {
+ m_bIsApplication = false;
+ m_bValid = false;
+ m_bDocumentClosed = false;
+
+ m_xDocument.clear();
+ m_xDocModify.clear();
+ m_xScriptAccess.clear();
+
+ if (m_pDocListener)
+ m_pDocListener->dispose();
+ }
+
+ bool ScriptDocument::Impl::impl_initDocument_nothrow( const Reference< XModel >& _rxModel )
+ {
+ try
+ {
+ m_xDocument.set ( _rxModel, UNO_SET_THROW );
+ m_xDocModify.set ( _rxModel, UNO_QUERY_THROW );
+ m_xScriptAccess.set ( _rxModel, UNO_QUERY );
+
+ m_bValid = m_xScriptAccess.is();
+
+ if ( m_bValid )
+ m_pDocListener.reset( new DocumentEventNotifier( *this, _rxModel ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ m_bValid = false;
+ }
+
+ if ( !m_bValid )
+ {
+ invalidate();
+ }
+
+ return m_bValid;
+ }
+
+ Reference< XLibraryContainer > ScriptDocument::Impl::getLibraryContainer( LibraryContainerType _eType ) const
+ {
+ OSL_ENSURE( isValid(), "ScriptDocument::Impl::getLibraryContainer: invalid!" );
+
+ Reference< XLibraryContainer > xContainer;
+ if ( !isValid() )
+ return xContainer;
+
+ try
+ {
+ if ( isApplication() )
+ xContainer.set( _eType == E_SCRIPTS ? SfxGetpApp()->GetBasicContainer() : SfxGetpApp()->GetDialogContainer(), UNO_QUERY_THROW );
+ else
+ {
+ xContainer.set(
+ _eType == E_SCRIPTS ? m_xScriptAccess->getBasicLibraries() : m_xScriptAccess->getDialogLibraries(),
+ UNO_QUERY_THROW );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ return xContainer;
+ }
+
+ bool ScriptDocument::Impl::isReadOnly() const
+ {
+ OSL_ENSURE( isValid(), "ScriptDocument::Impl::isReadOnly: invalid state!" );
+ OSL_ENSURE( !isApplication(), "ScriptDocument::Impl::isReadOnly: not allowed to be called for the application!" );
+
+ bool bIsReadOnly = true;
+ if ( isValid() && !isApplication() )
+ {
+ try
+ {
+ // note that XStorable is required by the OfficeDocument service
+ Reference< XStorable > xDocStorable( m_xDocument, UNO_QUERY_THROW );
+ bIsReadOnly = xDocStorable->isReadonly();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+ return bIsReadOnly;
+ }
+
+ bool ScriptDocument::Impl::isInVBAMode() const
+ {
+ bool bResult = false;
+ if ( !isApplication() )
+ {
+ Reference< XVBACompatibility > xVBACompat( getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
+ if ( xVBACompat.is() )
+ bResult = xVBACompat->getVBACompatibilityMode();
+ }
+ return bResult;
+ }
+
+ BasicManager* ScriptDocument::Impl::getBasicManager() const
+ {
+ try
+ {
+ OSL_ENSURE( isValid(), "ScriptDocument::Impl::getBasicManager: invalid state!" );
+ if ( !isValid() )
+ return nullptr;
+
+ if ( isApplication() )
+ return SfxApplication::GetBasicManager();
+
+ return ::basic::BasicManagerRepository::getDocumentBasicManager( m_xDocument );
+ }
+ catch (const css::ucb::ContentCreationException&)
+ {
+ TOOLS_WARN_EXCEPTION( "basctl.basicide", "ScriptDocument::getBasicManager" );
+ }
+ return nullptr;
+ }
+
+ Reference< XModel > ScriptDocument::Impl::getDocument() const
+ {
+ OSL_ENSURE( isValid(), "ScriptDocument::Impl::getDocument: invalid state!" );
+ OSL_ENSURE( isDocument(), "ScriptDocument::Impl::getDocument: for documents only!" );
+ if ( !isValid() || !isDocument() )
+ return nullptr;
+
+ return m_xDocument;
+ }
+
+
+ Reference< XNameContainer > ScriptDocument::Impl::getLibrary( LibraryContainerType _eType, const OUString& _rLibName, bool _bLoadLibrary ) const
+ {
+ OSL_ENSURE( isValid(), "ScriptDocument::Impl::getLibrary: invalid state!" );
+
+ Reference< XNameContainer > xContainer;
+ try
+ {
+ Reference< XLibraryContainer > xLibContainer = getLibraryContainer( _eType );
+ if ( isValid() && xLibContainer.is() )
+ xContainer.set( xLibContainer->getByName( _rLibName ), UNO_QUERY_THROW );
+
+ if ( !xContainer.is() )
+ throw NoSuchElementException();
+
+ // load library
+ if ( _bLoadLibrary && !xLibContainer->isLibraryLoaded( _rLibName ) )
+ xLibContainer->loadLibrary( _rLibName );
+ }
+ catch( const NoSuchElementException& )
+ {
+ throw; // allowed to leave
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+
+ return xContainer;
+ }
+
+
+ bool ScriptDocument::Impl::hasLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const
+ {
+ bool bHas = false;
+ try
+ {
+ Reference< XLibraryContainer > xLibContainer = getLibraryContainer( _eType );
+ bHas = xLibContainer.is() && xLibContainer->hasByName( _rLibName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ return bHas;
+ }
+
+
+ Reference< XNameContainer > ScriptDocument::Impl::getOrCreateLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const
+ {
+ Reference< XNameContainer > xLibrary;
+ try
+ {
+ Reference< XLibraryContainer > xLibContainer( getLibraryContainer( _eType ), UNO_SET_THROW );
+ if ( xLibContainer->hasByName( _rLibName ) )
+ xLibrary.set( xLibContainer->getByName( _rLibName ), UNO_QUERY_THROW );
+ else
+ xLibrary.set( xLibContainer->createLibrary( _rLibName ), UNO_SET_THROW );
+
+ if ( !xLibContainer->isLibraryLoaded( _rLibName ) )
+ xLibContainer->loadLibrary( _rLibName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ return xLibrary;
+ }
+
+
+ void ScriptDocument::Impl::loadLibraryIfExists( LibraryContainerType _eType, const OUString& _rLibrary )
+ {
+ try
+ {
+ Reference< XLibraryContainer > xLibContainer( getLibraryContainer( _eType ) );
+ if ( xLibContainer.is() && xLibContainer->hasByName( _rLibrary ) && !xLibContainer->isLibraryLoaded( _rLibrary ) )
+ xLibContainer->loadLibrary( _rLibrary );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+
+
+ bool ScriptDocument::Impl::removeModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rModuleName )
+ {
+ OSL_ENSURE( isValid(), "ScriptDocument::Impl::removeModuleOrDialog: invalid!" );
+ if ( !isValid() )
+ return false;
+ try
+ {
+ Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, true ) );
+ if ( xLib.is() )
+ {
+ xLib->removeByName( _rModuleName );
+ Reference< XVBAModuleInfo > xVBAModuleInfo(xLib, UNO_QUERY);
+ if(xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo(_rModuleName))
+ xVBAModuleInfo->removeModuleInfo(_rModuleName);
+ return true;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ return false;
+ }
+
+
+ bool ScriptDocument::Impl::hasModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rModName ) const
+ {
+ OSL_ENSURE( isValid(), "ScriptDocument::Impl::hasModuleOrDialog: invalid!" );
+ if ( !isValid() )
+ return false;
+
+ try
+ {
+ Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, true ) );
+ if ( xLib.is() )
+ return xLib->hasByName( _rModName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ return false;
+ }
+
+
+ bool ScriptDocument::Impl::getModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rObjectName, Any& _out_rModuleOrDialog )
+ {
+ OSL_ENSURE( isValid(), "ScriptDocument::Impl::getModuleOrDialog: invalid!" );
+ if ( !isValid() )
+ return false;
+
+ _out_rModuleOrDialog.clear();
+ try
+ {
+ Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, true ), UNO_SET_THROW );
+ if ( xLib->hasByName( _rObjectName ) )
+ {
+ _out_rModuleOrDialog = xLib->getByName( _rObjectName );
+ return true;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ return false;
+ }
+
+
+ bool ScriptDocument::Impl::renameModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName,
+ const OUString& _rOldName, const OUString& _rNewName, const Reference< XNameContainer >& _rxExistingDialogModel )
+ {
+ OSL_ENSURE( isValid(), "ScriptDocument::Impl::renameModuleOrDialog: invalid!" );
+ if ( !isValid() )
+ return false;
+
+ try
+ {
+ Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, true ), UNO_SET_THROW );
+
+ // get element
+ Any aElement( xLib->getByName( _rOldName ) );
+
+ // remove element from container
+ xLib->removeByName( _rOldName );
+
+ // if it's a dialog, import and export, to reflect the new name
+ if ( _eType == E_DIALOGS )
+ {
+ // create dialog model
+ Reference< XComponentContext > aContext(
+ comphelper::getProcessComponentContext() );
+ Reference< XNameContainer > xDialogModel;
+ if ( _rxExistingDialogModel.is() )
+ xDialogModel = _rxExistingDialogModel;
+ else
+ xDialogModel.set(
+ ( aContext->getServiceManager()->
+ createInstanceWithContext(
+ "com.sun.star.awt.UnoControlDialogModel",
+ aContext ) ),
+ UNO_QUERY_THROW );
+
+ // import dialog model
+ Reference< XInputStreamProvider > xISP( aElement, UNO_QUERY_THROW );
+ if ( !_rxExistingDialogModel.is() )
+ {
+ Reference< XInputStream > xInput( xISP->createInputStream(), UNO_SET_THROW );
+ ::xmlscript::importDialogModel( xInput, xDialogModel, aContext, isDocument() ? getDocument() : Reference< XModel >() );
+ }
+
+ // set new name as property
+ Reference< XPropertySet > xDlgPSet( xDialogModel, UNO_QUERY_THROW );
+ xDlgPSet->setPropertyValue( DLGED_PROP_NAME, Any( _rNewName ) );
+
+ // export dialog model
+ xISP = ::xmlscript::exportDialogModel( xDialogModel, aContext, isDocument() ? getDocument() : Reference< XModel >() );
+ aElement <<= xISP;
+ }
+
+ // insert element by new name in container
+ if ( _eType == E_SCRIPTS )
+ {
+ Reference< XVBAModuleInfo > xVBAModuleInfo( xLib, UNO_QUERY );
+ if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo( _rOldName ) )
+ {
+ ModuleInfo sModuleInfo = xVBAModuleInfo->getModuleInfo( _rOldName );
+ xVBAModuleInfo->removeModuleInfo( _rOldName );
+ xVBAModuleInfo->insertModuleInfo( _rNewName, sModuleInfo );
+ }
+ }
+ xLib->insertByName( _rNewName, aElement );
+ return true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ return false;
+ }
+
+
+ bool ScriptDocument::Impl::createModule( const OUString& _rLibName, const OUString& _rModName, bool _bCreateMain, OUString& _out_rNewModuleCode ) const
+ {
+ _out_rNewModuleCode.clear();
+ try
+ {
+ Reference< XNameContainer > xLib( getLibrary( E_SCRIPTS, _rLibName, true ) );
+ if ( !xLib.is() || xLib->hasByName( _rModName ) )
+ return false;
+
+ // create new module
+ _out_rNewModuleCode = "REM ***** BASIC *****\n\n" ;
+ if ( _bCreateMain )
+ _out_rNewModuleCode += "Sub Main\n\nEnd Sub\n" ;
+
+ Reference< XVBAModuleInfo > xVBAModuleInfo(xLib, UNO_QUERY);
+ if (xVBAModuleInfo.is())
+ {
+ css::script::ModuleInfo aModuleInfo;
+ aModuleInfo.ModuleType = css::script::ModuleType::NORMAL;
+ xVBAModuleInfo->insertModuleInfo(_rModName, aModuleInfo);
+ }
+
+ // insert module into library
+ xLib->insertByName( _rModName, Any( _out_rNewModuleCode ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ return false;
+ }
+
+ return true;
+ }
+
+
+ bool ScriptDocument::Impl::insertModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rObjectName, const Any& _rElement ) const
+ {
+ try
+ {
+ Reference< XNameContainer > xLib( getOrCreateLibrary( _eType, _rLibName ), UNO_SET_THROW );
+ if ( xLib->hasByName( _rObjectName ) )
+ return false;
+
+ xLib->insertByName( _rObjectName, _rElement );
+ return true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ return false;
+ }
+
+
+ bool ScriptDocument::Impl::updateModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const
+ {
+ try
+ {
+ Reference< XNameContainer > xLib( getOrCreateLibrary( E_SCRIPTS, _rLibName ), UNO_SET_THROW );
+ if ( !xLib->hasByName( _rModName ) )
+ return false;
+ xLib->replaceByName( _rModName, Any( _rModuleCode ) );
+ return true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ return false;
+ }
+
+
+ bool ScriptDocument::Impl::createDialog( const OUString& _rLibName, const OUString& _rDialogName, Reference< XInputStreamProvider >& _out_rDialogProvider ) const
+ {
+ try
+ {
+ Reference< XNameContainer > xLib( getLibrary( E_DIALOGS, _rLibName, true ), UNO_SET_THROW );
+
+ // create dialog
+ _out_rDialogProvider.clear();
+ if ( xLib->hasByName( _rDialogName ) )
+ return false;
+
+ // create new dialog model
+ Reference< XComponentContext > aContext(
+ comphelper::getProcessComponentContext() );
+ Reference< XNameContainer > xDialogModel(
+ aContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.awt.UnoControlDialogModel", aContext ),
+ UNO_QUERY_THROW );
+
+ // set name property
+ Reference< XPropertySet > xDlgPSet( xDialogModel, UNO_QUERY_THROW );
+ xDlgPSet->setPropertyValue( DLGED_PROP_NAME, Any( _rDialogName ) );
+
+ // export dialog model
+ _out_rDialogProvider = ::xmlscript::exportDialogModel( xDialogModel, aContext, isDocument() ? getDocument() : Reference< XModel >() );
+
+ // insert dialog into library
+ xLib->insertByName( _rDialogName, Any( _out_rDialogProvider ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+
+ return _out_rDialogProvider.is();
+ }
+
+
+ void ScriptDocument::Impl::setDocumentModified() const
+ {
+ OSL_ENSURE( isValid() && isDocument(), "ScriptDocument::Impl::setDocumentModified: only to be called for real documents!" );
+ if ( isValid() && isDocument() )
+ {
+ try
+ {
+ m_xDocModify->setModified( true );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+ }
+
+
+ bool ScriptDocument::Impl::isDocumentModified() const
+ {
+ OSL_ENSURE( isValid() && isDocument(), "ScriptDocument::Impl::isDocumentModified: only to be called for real documents!" );
+ bool bIsModified = false;
+ if ( isValid() && isDocument() )
+ {
+ try
+ {
+ bIsModified = m_xDocModify->isModified();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+ return bIsModified;
+ }
+
+
+ void ScriptDocument::Impl::saveDocument( const Reference< XStatusIndicator >& _rxStatusIndicator ) const
+ {
+ Reference< XFrame > xFrame;
+ if ( !getCurrentFrame( xFrame ) )
+ return;
+
+ Sequence< PropertyValue > aArgs;
+ if ( _rxStatusIndicator.is() )
+ {
+ aArgs = ::comphelper::InitPropertySequence({
+ { "StatusIndicator", Any(_rxStatusIndicator) }
+ });
+ }
+
+ try
+ {
+ URL aURL;
+ aURL.Complete = ".uno:Save" ;
+ aURL.Main = aURL.Complete;
+ aURL.Protocol = ".uno:" ;
+ aURL.Path = "Save" ;
+
+ Reference< XDispatchProvider > xDispProv( xFrame, UNO_QUERY_THROW );
+ Reference< XDispatch > xDispatch(
+ xDispProv->queryDispatch( aURL, "_self", FrameSearchFlag::AUTO ),
+ UNO_SET_THROW );
+
+ xDispatch->dispatch( aURL, aArgs );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+
+
+ OUString ScriptDocument::Impl::getTitle() const
+ {
+ OSL_PRECOND( isValid() && isDocument(), "ScriptDocument::Impl::getTitle: for documents only!" );
+
+ OUString sTitle;
+ if ( isValid() && isDocument() )
+ {
+ sTitle = ::comphelper::DocumentInfo::getDocumentTitle( m_xDocument );
+ }
+ return sTitle;
+ }
+
+
+ OUString ScriptDocument::Impl::getURL() const
+ {
+ OSL_PRECOND( isValid() && isDocument(), "ScriptDocument::Impl::getURL: for documents only!" );
+
+ OUString sURL;
+ if ( isValid() && isDocument() )
+ {
+ try
+ {
+ sURL = m_xDocument->getURL();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+ return sURL;
+ }
+
+
+ bool ScriptDocument::Impl::allowMacros() const
+ {
+ OSL_ENSURE( isValid() && isDocument(), "ScriptDocument::Impl::allowMacros: for documents only!" );
+ bool bAllow = false;
+ if ( isValid() && isDocument() )
+ {
+ try
+ {
+ bAllow = m_xScriptAccess->getAllowMacroExecution();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ }
+ return bAllow;
+ }
+
+
+ bool ScriptDocument::Impl::getCurrentFrame( Reference< XFrame >& _out_rxFrame ) const
+ {
+ _out_rxFrame.clear();
+ OSL_PRECOND( isValid() && isDocument(), "ScriptDocument::Impl::getCurrentFrame: documents only!" );
+ if ( !isValid() || !isDocument() )
+ return false;
+
+ try
+ {
+ Reference< XModel > xDocument( m_xDocument, UNO_SET_THROW );
+ Reference< XController > xController( xDocument->getCurrentController(), UNO_SET_THROW );
+ _out_rxFrame.set( xController->getFrame(), UNO_SET_THROW );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+
+ return _out_rxFrame.is();
+ }
+
+
+ bool ScriptDocument::Impl::isLibraryShared( const OUString& _rLibName, LibraryContainerType _eType )
+ {
+ bool bIsShared = false;
+ try
+ {
+ Reference< XLibraryContainer2 > xLibContainer( getLibraryContainer( _eType ), UNO_QUERY_THROW );
+
+ if ( !xLibContainer->hasByName( _rLibName ) || !xLibContainer->isLibraryLink( _rLibName ) )
+ return false;
+ OUString aFileURL;
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ Reference< XUriReferenceFactory > xUriFac = UriReferenceFactory::create(xContext);
+
+ OUString aLinkURL( xLibContainer->getLibraryLinkURL( _rLibName ) );
+ Reference< XUriReference > xUriRef( xUriFac->parse( aLinkURL ), UNO_SET_THROW );
+
+ OUString aScheme = xUriRef->getScheme();
+ if ( aScheme.equalsIgnoreAsciiCase("file") )
+ {
+ aFileURL = aLinkURL;
+ }
+ else if ( aScheme.equalsIgnoreAsciiCase("vnd.sun.star.pkg") )
+ {
+ OUString aAuthority = xUriRef->getAuthority();
+ if ( aAuthority.matchIgnoreAsciiCase("vnd.sun.star.expand:") )
+ {
+ OUString aDecodedURL( aAuthority.copy( sizeof ( "vnd.sun.star.expand:" ) - 1 ) );
+ aDecodedURL = ::rtl::Uri::decode( aDecodedURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
+ Reference< XMacroExpander > xMacroExpander = theMacroExpander::get(xContext);
+ aFileURL = xMacroExpander->expandMacros( aDecodedURL );
+ }
+ }
+
+ if ( !aFileURL.isEmpty() )
+ {
+ ::osl::DirectoryItem aFileItem;
+ ::osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileURL );
+ OSL_VERIFY( ::osl::DirectoryItem::get( aFileURL, aFileItem ) == ::osl::FileBase::E_None );
+ OSL_VERIFY( aFileItem.getFileStatus( aFileStatus ) == ::osl::FileBase::E_None );
+ OUString aCanonicalFileURL( aFileStatus.getFileURL() );
+
+ if( aCanonicalFileURL.indexOf( "share/basic" ) >= 0 ||
+ aCanonicalFileURL.indexOf( "share/uno_packages" ) >= 0 ||
+ aCanonicalFileURL.indexOf( "share/extensions" ) >= 0 )
+ bIsShared = true;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+
+ return bIsShared;
+ }
+
+
+ void ScriptDocument::Impl::onDocumentCreated( const ScriptDocument& /*_rDocument*/ )
+ {
+ // not interested in
+ }
+
+ void ScriptDocument::Impl::onDocumentOpened( const ScriptDocument& /*_rDocument*/ )
+ {
+ // not interested in
+ }
+
+ void ScriptDocument::Impl::onDocumentSave( const ScriptDocument& /*_rDocument*/ )
+ {
+ // not interested in
+ }
+
+ void ScriptDocument::Impl::onDocumentSaveDone( const ScriptDocument& /*_rDocument*/ )
+ {
+ // not interested in
+ }
+
+ void ScriptDocument::Impl::onDocumentSaveAs( const ScriptDocument& /*_rDocument*/ )
+ {
+ // not interested in
+ }
+
+ void ScriptDocument::Impl::onDocumentSaveAsDone( const ScriptDocument& /*_rDocument*/ )
+ {
+ // not interested in
+ }
+
+ void ScriptDocument::Impl::onDocumentClosed( const ScriptDocument& _rDocument )
+ {
+ DBG_TESTSOLARMUTEX();
+ OSL_PRECOND( isValid(), "ScriptDocument::Impl::onDocumentClosed: should not be listening if I'm not valid!" );
+
+ bool bMyDocument = m_xDocument == _rDocument.getDocument();
+ OSL_PRECOND( bMyDocument, "ScriptDocument::Impl::onDocumentClosed: didn't want to know *this*!" );
+ if ( bMyDocument )
+ {
+ m_bDocumentClosed = true;
+ }
+ }
+
+
+ void ScriptDocument::Impl::onDocumentTitleChanged( const ScriptDocument& /*_rDocument*/ )
+ {
+ // not interested in
+ }
+
+ void ScriptDocument::Impl::onDocumentModeChanged( const ScriptDocument& /*_rDocument*/ )
+ {
+ // not interested in
+ }
+
+
+ ScriptDocument::ScriptDocument()
+ :m_pImpl(std::make_shared<Impl>())
+ { }
+
+
+ ScriptDocument::ScriptDocument( ScriptDocument::SpecialDocument _eType )
+ :m_pImpl( std::make_shared<Impl>( Reference< XModel >() ) )
+ {
+ OSL_ENSURE( _eType == NoDocument, "ScriptDocument::ScriptDocument: unknown SpecialDocument type!" );
+ }
+
+
+ ScriptDocument::ScriptDocument( const Reference< XModel >& _rxDocument )
+ :m_pImpl( std::make_shared<Impl>( _rxDocument ) )
+ {
+ OSL_ENSURE( _rxDocument.is(), "ScriptDocument::ScriptDocument: document must not be NULL!" );
+ // a NULL document results in an uninitialized instance, and for this
+ // purpose, there is a dedicated constructor
+ }
+
+
+ const ScriptDocument& ScriptDocument::getApplicationScriptDocument()
+ {
+ static ScriptDocument s_aApplicationScripts;
+ return s_aApplicationScripts;
+ }
+
+
+ ScriptDocument ScriptDocument::getDocumentForBasicManager( const BasicManager* _pManager )
+ {
+ if ( _pManager == SfxApplication::GetBasicManager() )
+ return getApplicationScriptDocument();
+
+ docs::Documents aDocuments;
+ lcl_getAllModels_throw( aDocuments, false );
+
+ for (auto const& doc : aDocuments)
+ {
+ const BasicManager* pDocBasicManager = ::basic::BasicManagerRepository::getDocumentBasicManager( doc.xModel );
+ if ( ( pDocBasicManager != SfxApplication::GetBasicManager() )
+ && ( pDocBasicManager == _pManager )
+ )
+ {
+ return ScriptDocument( doc.xModel );
+ }
+ }
+
+ OSL_FAIL( "ScriptDocument::getDocumentForBasicManager: did not find a document for this manager!" );
+ return ScriptDocument( NoDocument );
+ }
+
+
+ ScriptDocument ScriptDocument::getDocumentWithURLOrCaption( std::u16string_view _rUrlOrCaption )
+ {
+ ScriptDocument aDocument( getApplicationScriptDocument() );
+ if ( _rUrlOrCaption.empty() )
+ return aDocument;
+
+ docs::Documents aDocuments;
+ lcl_getAllModels_throw( aDocuments, false );
+
+ for (auto const& doc : aDocuments)
+ {
+ const ScriptDocument aCheck( doc.xModel );
+ if ( _rUrlOrCaption == aCheck.getTitle()
+ || _rUrlOrCaption == aCheck.m_pImpl->getURL()
+ )
+ {
+ aDocument = aCheck;
+ break;
+ }
+ }
+
+ return aDocument;
+ }
+
+ ScriptDocuments ScriptDocument::getAllScriptDocuments( ScriptDocument::ScriptDocumentList _eListType )
+ {
+ ScriptDocuments aScriptDocs;
+
+ // include application?
+ if ( _eListType == AllWithApplication )
+ aScriptDocs.push_back( getApplicationScriptDocument() );
+
+ // obtain documents
+ try
+ {
+ docs::Documents aDocuments;
+ lcl_getAllModels_throw( aDocuments, true /* exclude invisible */ );
+
+ for (auto const& doc : aDocuments)
+ {
+ // exclude documents without script/library containers
+ ScriptDocument aDoc( doc.xModel );
+ if ( !aDoc.isValid() )
+ continue;
+
+ aScriptDocs.push_back( aDoc );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+
+ // sort document list by doc title?
+ if ( _eListType == DocumentsSorted )
+ {
+ auto const sort = comphelper::string::NaturalStringSorter(
+ comphelper::getProcessComponentContext(),
+ Application::GetSettings().GetUILanguageTag().getLocale());
+ std::sort(aScriptDocs.begin(), aScriptDocs.end(),
+ [&sort](const ScriptDocument& rLHS, const ScriptDocument& rRHS) {
+ return sort.compare(rLHS.getTitle(), rRHS.getTitle()) < 0;
+ });
+ }
+
+ return aScriptDocs;
+ }
+
+
+ bool ScriptDocument::operator==( const ScriptDocument& _rhs ) const
+ {
+ return m_pImpl->getDocumentRef() == _rhs.m_pImpl->getDocumentRef();
+ }
+
+
+ sal_Int32 ScriptDocument::hashCode() const
+ {
+ return sal::static_int_cast<sal_Int32>(reinterpret_cast< sal_IntPtr >( m_pImpl->getDocumentRef().get() ));
+ }
+
+
+ bool ScriptDocument::isValid() const
+ {
+ return m_pImpl->isValid();
+ }
+
+
+ bool ScriptDocument::isAlive() const
+ {
+ return m_pImpl->isAlive();
+ }
+
+
+ Reference< XLibraryContainer > ScriptDocument::getLibraryContainer( LibraryContainerType _eType ) const
+ {
+ return m_pImpl->getLibraryContainer( _eType );
+ }
+
+
+ Reference< XNameContainer > ScriptDocument::getLibrary( LibraryContainerType _eType, const OUString& _rLibName, bool _bLoadLibrary ) const
+ {
+ return m_pImpl->getLibrary( _eType, _rLibName, _bLoadLibrary );
+ }
+
+
+ bool ScriptDocument::hasLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const
+ {
+ return m_pImpl->hasLibrary( _eType, _rLibName );
+ }
+
+
+ Reference< XNameContainer > ScriptDocument::getOrCreateLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const
+ {
+ return m_pImpl->getOrCreateLibrary( _eType, _rLibName );
+ }
+
+
+ void ScriptDocument::loadLibraryIfExists( LibraryContainerType _eType, const OUString& _rLibrary )
+ {
+ m_pImpl->loadLibraryIfExists( _eType, _rLibrary );
+ }
+
+
+ Sequence< OUString > ScriptDocument::getObjectNames( LibraryContainerType _eType, const OUString& _rLibName ) const
+ {
+ Sequence< OUString > aModuleNames;
+
+ try
+ {
+ if ( hasLibrary( _eType, _rLibName ) )
+ {
+ Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, false ) );
+ if ( xLib.is() )
+ aModuleNames = xLib->getElementNames();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+
+ // sort
+ auto const sort = comphelper::string::NaturalStringSorter(
+ comphelper::getProcessComponentContext(),
+ Application::GetSettings().GetUILanguageTag().getLocale());
+ auto [begin, end] = asNonConstRange(aModuleNames);
+ std::sort(begin, end,
+ [&sort](const OUString& rLHS, const OUString& rRHS) {
+ return sort.compare(rLHS, rRHS) < 0;
+ });
+ return aModuleNames;
+ }
+
+
+ OUString ScriptDocument::createObjectName( LibraryContainerType _eType, const OUString& _rLibName ) const
+ {
+ OUString aObjectName;
+
+ OUString aBaseName = _eType == E_SCRIPTS ? OUString("Module") : OUString("Dialog");
+
+ const Sequence< OUString > aUsedNames( getObjectNames( _eType, _rLibName ) );
+ std::set< OUString > aUsedNamesCheck( aUsedNames.begin(), aUsedNames.end() );
+
+ bool bValid = false;
+ sal_Int32 i = 1;
+ while ( !bValid )
+ {
+ aObjectName = aBaseName
+ + OUString::number( i );
+
+ if ( aUsedNamesCheck.find( aObjectName ) == aUsedNamesCheck.end() )
+ bValid = true;
+
+ ++i;
+ }
+
+ return aObjectName;
+ }
+
+
+ Sequence< OUString > ScriptDocument::getLibraryNames() const
+ {
+ return GetMergedLibraryNames( getLibraryContainer( E_SCRIPTS ), getLibraryContainer( E_DIALOGS ) );
+ }
+
+
+ bool ScriptDocument::isReadOnly() const
+ {
+ return m_pImpl->isReadOnly();
+ }
+
+
+ bool ScriptDocument::isApplication() const
+ {
+ return m_pImpl->isApplication();
+ }
+
+ bool ScriptDocument::isInVBAMode() const
+ {
+ return m_pImpl->isInVBAMode();
+ }
+
+
+ BasicManager* ScriptDocument::getBasicManager() const
+ {
+ return m_pImpl->getBasicManager();
+ }
+
+
+ Reference< XModel > ScriptDocument::getDocument() const
+ {
+ return m_pImpl->getDocument();
+ }
+
+
+ Reference< XModel > ScriptDocument::getDocumentOrNull() const
+ {
+ if ( isDocument() )
+ return m_pImpl->getDocument();
+ return nullptr;
+ }
+
+
+ bool ScriptDocument::removeModule( const OUString& _rLibName, const OUString& _rModuleName ) const
+ {
+ return m_pImpl->removeModuleOrDialog( E_SCRIPTS, _rLibName, _rModuleName );
+ }
+
+
+ bool ScriptDocument::hasModule( const OUString& _rLibName, const OUString& _rModuleName ) const
+ {
+ return m_pImpl->hasModuleOrDialog( E_SCRIPTS, _rLibName, _rModuleName );
+ }
+
+
+ bool ScriptDocument::getModule( const OUString& _rLibName, const OUString& _rModName, OUString& _out_rModuleSource ) const
+ {
+ Any aCode;
+ if ( !m_pImpl->getModuleOrDialog( E_SCRIPTS, _rLibName, _rModName, aCode ) )
+ return false;
+ OSL_VERIFY( aCode >>= _out_rModuleSource );
+ return true;
+ }
+
+
+ bool ScriptDocument::renameModule( const OUString& _rLibName, const OUString& _rOldName, const OUString& _rNewName ) const
+ {
+ return m_pImpl->renameModuleOrDialog( E_SCRIPTS, _rLibName, _rOldName, _rNewName, nullptr );
+ }
+
+
+ bool ScriptDocument::createModule( const OUString& _rLibName, const OUString& _rModName, bool _bCreateMain, OUString& _out_rNewModuleCode ) const
+ {
+ if ( !m_pImpl->createModule( _rLibName, _rModName, _bCreateMain, _out_rNewModuleCode ) )
+ return false;
+
+ // doc shell modified
+ MarkDocumentModified( *const_cast< ScriptDocument* >( this ) ); // here?
+ return true;
+ }
+
+
+ bool ScriptDocument::insertModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const
+ {
+ return m_pImpl->insertModuleOrDialog( E_SCRIPTS, _rLibName, _rModName, Any( _rModuleCode ) );
+ }
+
+
+ bool ScriptDocument::updateModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const
+ {
+ return m_pImpl->updateModule( _rLibName, _rModName, _rModuleCode );
+ }
+
+
+ bool ScriptDocument::removeDialog( const OUString& _rLibName, const OUString& _rDialogName ) const
+ {
+ return m_pImpl->removeModuleOrDialog( E_DIALOGS, _rLibName, _rDialogName );
+ }
+
+
+ bool ScriptDocument::hasDialog( const OUString& _rLibName, const OUString& _rDialogName ) const
+ {
+ return m_pImpl->hasModuleOrDialog( E_DIALOGS, _rLibName, _rDialogName );
+ }
+
+
+ bool ScriptDocument::getDialog( const OUString& _rLibName, const OUString& _rDialogName, Reference< XInputStreamProvider >& _out_rDialogProvider ) const
+ {
+ Any aCode;
+ if ( !m_pImpl->getModuleOrDialog( E_DIALOGS, _rLibName, _rDialogName, aCode ) )
+ return false;
+ OSL_VERIFY( aCode >>= _out_rDialogProvider );
+ return _out_rDialogProvider.is();
+ }
+
+
+ bool ScriptDocument::renameDialog( const OUString& _rLibName, const OUString& _rOldName, const OUString& _rNewName, const Reference< XNameContainer >& _rxExistingDialogModel ) const
+ {
+ return m_pImpl->renameModuleOrDialog( E_DIALOGS, _rLibName, _rOldName, _rNewName, _rxExistingDialogModel );
+ }
+
+
+ bool ScriptDocument::createDialog( const OUString& _rLibName, const OUString& _rDialogName, Reference< XInputStreamProvider >& _out_rDialogProvider ) const
+ {
+ if ( !m_pImpl->createDialog( _rLibName, _rDialogName, _out_rDialogProvider ) )
+ return false;
+
+ MarkDocumentModified( *const_cast< ScriptDocument* >( this ) ); // here?
+ return true;
+ }
+
+
+ bool ScriptDocument::insertDialog( const OUString& _rLibName, const OUString& _rDialogName, const Reference< XInputStreamProvider >& _rxDialogProvider ) const
+ {
+ return m_pImpl->insertModuleOrDialog( E_DIALOGS, _rLibName, _rDialogName, Any( _rxDialogProvider ) );
+ }
+
+
+ void ScriptDocument::setDocumentModified() const
+ {
+ m_pImpl->setDocumentModified();
+ }
+
+
+ bool ScriptDocument::isDocumentModified() const
+ {
+ return m_pImpl->isDocumentModified();
+ }
+
+
+ void ScriptDocument::saveDocument( const Reference< XStatusIndicator >& _rxStatusIndicator ) const
+ {
+ m_pImpl->saveDocument( _rxStatusIndicator );
+ }
+
+
+ LibraryLocation ScriptDocument::getLibraryLocation( const OUString& _rLibName ) const
+ {
+ LibraryLocation eLocation = LIBRARY_LOCATION_UNKNOWN;
+ if ( !_rLibName.isEmpty() )
+ {
+ if ( isDocument() )
+ {
+ eLocation = LIBRARY_LOCATION_DOCUMENT;
+ }
+ else
+ {
+ if ( ( hasLibrary( E_SCRIPTS, _rLibName ) && !m_pImpl->isLibraryShared( _rLibName, E_SCRIPTS ) )
+ || ( hasLibrary( E_DIALOGS, _rLibName ) && !m_pImpl->isLibraryShared( _rLibName, E_DIALOGS ) )
+ )
+ {
+ eLocation = LIBRARY_LOCATION_USER;
+ }
+ else
+ {
+ eLocation = LIBRARY_LOCATION_SHARE;
+ }
+ }
+ }
+
+ return eLocation;
+ }
+
+
+ OUString ScriptDocument::getTitle( LibraryLocation _eLocation, LibraryType _eType ) const
+ {
+ OUString aTitle;
+
+ switch ( _eLocation )
+ {
+ case LIBRARY_LOCATION_USER:
+ {
+ switch ( _eType )
+ {
+ case LibraryType::Module: aTitle = IDEResId(RID_STR_USERMACROS); break;
+ case LibraryType::Dialog: aTitle = IDEResId(RID_STR_USERDIALOGS); break;
+ case LibraryType::All: aTitle = IDEResId(RID_STR_USERMACROSDIALOGS); break;
+ default:
+ break;
+ }
+ }
+ break;
+ case LIBRARY_LOCATION_SHARE:
+ {
+ switch ( _eType )
+ {
+ case LibraryType::Module: aTitle = IDEResId(RID_STR_SHAREMACROS); break;
+ case LibraryType::Dialog: aTitle = IDEResId(RID_STR_SHAREDIALOGS); break;
+ case LibraryType::All: aTitle = IDEResId(RID_STR_SHAREMACROSDIALOGS); break;
+ default:
+ break;
+ }
+ }
+ break;
+ case LIBRARY_LOCATION_DOCUMENT:
+ aTitle = getTitle();
+ break;
+ default:
+ break;
+ }
+
+ return aTitle;
+ }
+
+
+ OUString ScriptDocument::getTitle() const
+ {
+ return m_pImpl->getTitle();
+ }
+
+
+ bool ScriptDocument::isActive() const
+ {
+ bool bIsActive( false );
+ try
+ {
+ Reference< XFrame > xFrame;
+ if ( m_pImpl->getCurrentFrame( xFrame ) )
+ bIsActive = xFrame->isActive();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl.basicide");
+ }
+ return bIsActive;
+ }
+
+
+ bool ScriptDocument::allowMacros() const
+ {
+ return m_pImpl->allowMacros();
+ }
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/textwindowpeer.cxx b/basctl/source/basicide/textwindowpeer.cxx
new file mode 100644
index 000000000..fc4584537
--- /dev/null
+++ b/basctl/source/basicide/textwindowpeer.cxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <vcl/svtaccessiblefactory.hxx>
+#include <vcl/accessiblefactory.hxx>
+
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <toolkit/awt/vclxwindow.hxx>
+#include <vcl/texteng.hxx>
+#include <vcl/textview.hxx>
+#include <vcl/window.hxx>
+#include "textwindowpeer.hxx"
+
+namespace {
+
+class TextWindowPeer final : public VCLXWindow {
+public:
+ explicit TextWindowPeer(TextView & view);
+
+ TextWindowPeer(const TextWindowPeer&) = delete;
+ TextWindowPeer& operator=(const TextWindowPeer&) = delete;
+
+private:
+ virtual css::uno::Reference<css::accessibility::XAccessibleContext>
+ CreateAccessibleContext() override;
+
+ TextEngine & m_rEngine;
+ TextView & m_rView;
+ vcl::AccessibleFactoryAccess m_aFactoryAccess;
+};
+
+TextWindowPeer::TextWindowPeer(TextView & view):
+ m_rEngine(*view.GetTextEngine()), m_rView(view)
+{
+ SetWindow(view.GetWindow());
+}
+
+css::uno::Reference<css::accessibility::XAccessibleContext>
+TextWindowPeer::CreateAccessibleContext() {
+ return m_aFactoryAccess.getFactory().createAccessibleTextWindowContext(
+ this, m_rEngine, m_rView);
+}
+
+}
+
+css::uno::Reference<css::awt::XWindowPeer> basctl::createTextWindowPeer(
+ TextView & view)
+{
+ return new TextWindowPeer(view);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/textwindowpeer.hxx b/basctl/source/basicide/textwindowpeer.hxx
new file mode 100644
index 000000000..077ad32cd
--- /dev/null
+++ b/basctl/source/basicide/textwindowpeer.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <com/sun/star/uno/Reference.hxx>
+
+namespace com::sun::star::awt
+{
+class XWindowPeer;
+}
+class TextView;
+
+namespace basctl
+{
+css::uno::Reference<css::awt::XWindowPeer> createTextWindowPeer(TextView& view);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/uiobject.cxx b/basctl/source/basicide/uiobject.cxx
new file mode 100644
index 000000000..80807d3a4
--- /dev/null
+++ b/basctl/source/basicide/uiobject.cxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <memory>
+#include "uiobject.hxx"
+#include <vcl/xtextedt.hxx>
+
+namespace basctl
+{
+EditorWindowUIObject::EditorWindowUIObject(const VclPtr<basctl::EditorWindow>& xEditorWindow)
+ : WindowUIObject(xEditorWindow)
+ , mxEditorWindow(xEditorWindow)
+{
+}
+
+StringMap EditorWindowUIObject::get_state()
+{
+ StringMap aMap = WindowUIObject::get_state();
+
+ ExtTextEngine* pEditEngine = mxEditorWindow->GetEditEngine();
+ sal_Int32 i, nParas;
+ OUStringBuffer aRes;
+ for (i = 0, nParas = pEditEngine->GetParagraphCount(); i < nParas; ++i)
+ {
+ aRes.append(pEditEngine->GetText(i));
+ aRes.append("\n");
+ }
+
+ aMap["Text"] = aRes.makeStringAndClear();
+
+ return aMap;
+}
+
+std::unique_ptr<UIObject> EditorWindowUIObject::create(vcl::Window* pWindow)
+{
+ basctl::EditorWindow* pEditorWindow = dynamic_cast<basctl::EditorWindow*>(pWindow);
+ assert(pEditorWindow);
+ return std::unique_ptr<UIObject>(new EditorWindowUIObject(pEditorWindow));
+}
+
+OUString EditorWindowUIObject::get_name() const { return "EditorWindowUIObject"; }
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/uiobject.hxx b/basctl/source/basicide/uiobject.hxx
new file mode 100644
index 000000000..f3a1e5ec8
--- /dev/null
+++ b/basctl/source/basicide/uiobject.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <memory>
+#include <vcl/uitest/uiobject.hxx>
+#include "baside2.hxx"
+
+namespace basctl
+{
+class EditorWindow;
+
+class EditorWindowUIObject : public WindowUIObject
+{
+ VclPtr<basctl::EditorWindow> mxEditorWindow;
+
+public:
+ EditorWindowUIObject(const VclPtr<basctl::EditorWindow>& xEditorWindow);
+
+ virtual StringMap get_state() override;
+
+ static std::unique_ptr<UIObject> create(vcl::Window* pWindow);
+
+protected:
+ virtual OUString get_name() const override;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/unomodel.cxx b/basctl/source/basicide/unomodel.cxx
new file mode 100644
index 000000000..4a9ee759f
--- /dev/null
+++ b/basctl/source/basicide/unomodel.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "basdoc.hxx"
+#include <iderdll.hxx>
+#include <com/sun/star/io/IOException.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <sfx2/objsh.hxx>
+#include <vcl/svapp.hxx>
+
+#include "unomodel.hxx"
+
+namespace basctl
+{
+
+using namespace ::cppu;
+using namespace ::std;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+SIDEModel::SIDEModel( SfxObjectShell *pObjSh )
+: SfxBaseModel(pObjSh)
+{
+}
+
+SIDEModel::~SIDEModel()
+{
+}
+
+uno::Any SAL_CALL SIDEModel::queryInterface( const uno::Type& rType )
+{
+ uno::Any aRet = ::cppu::queryInterface ( rType,
+ // OWeakObject interfaces
+ static_cast< XInterface* >( static_cast< OWeakObject* >( this ) ),
+ static_cast< XWeak* > ( this ),
+ static_cast< XServiceInfo* > ( this ) );
+ if (!aRet.hasValue())
+ aRet = SfxBaseModel::queryInterface ( rType );
+ return aRet;
+}
+
+void SAL_CALL SIDEModel::acquire() noexcept
+{
+ SolarMutexGuard aGuard;
+ OWeakObject::acquire();
+}
+
+void SAL_CALL SIDEModel::release() noexcept
+{
+ SolarMutexGuard aGuard;
+ OWeakObject::release();
+}
+
+uno::Sequence< uno::Type > SAL_CALL SIDEModel::getTypes( )
+{
+ return comphelper::concatSequences(
+ SfxBaseModel::getTypes(),
+ uno::Sequence { cppu::UnoType<XServiceInfo>::get() });
+}
+
+OUString SIDEModel::getImplementationName()
+{
+ return "com.sun.star.comp.basic.BasicIDE";
+}
+
+sal_Bool SIDEModel::supportsService(const OUString& rServiceName)
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence< OUString > SIDEModel::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.BasicIDE" };
+}
+
+// XStorable
+void SAL_CALL SIDEModel::store()
+{
+ notImplemented();
+}
+
+void SAL_CALL SIDEModel::storeAsURL( const OUString&, const uno::Sequence< beans::PropertyValue >& )
+{
+ notImplemented();
+}
+
+void SAL_CALL SIDEModel::storeToURL( const OUString&,
+ const uno::Sequence< beans::PropertyValue >& )
+{
+ notImplemented();
+}
+
+void SIDEModel::notImplemented()
+{
+ throw io::IOException("Can't store IDE model" );
+}
+
+} // namespace basctl
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_basic_BasicID_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ SolarMutexGuard aGuard;
+ basctl::EnsureIde();
+ SfxObjectShell* pShell = new basctl::DocShell();
+ auto pModel = pShell->GetModel();
+ pModel->acquire();
+ return pModel.get();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/unomodel.hxx b/basctl/source/basicide/unomodel.hxx
new file mode 100644
index 000000000..b47873005
--- /dev/null
+++ b/basctl/source/basicide/unomodel.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <sfx2/sfxbasemodel.hxx>
+
+namespace basctl
+{
+
+class SIDEModel : public SfxBaseModel,
+ public com::sun::star::lang::XServiceInfo
+{
+ /// @throws css::io::IOException
+ static void notImplemented();
+public:
+ explicit SIDEModel(SfxObjectShell *pObjSh);
+ virtual ~SIDEModel() override;
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire( ) noexcept override;
+ virtual void SAL_CALL release( ) noexcept override;
+
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ //XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+ // XStorable2
+ virtual void SAL_CALL storeSelf( const css::uno::Sequence< css::beans::PropertyValue >& ) override { notImplemented(); }
+ // XStorable
+ virtual void SAL_CALL store() override;
+ virtual void SAL_CALL storeAsURL( const OUString& sURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& seqArguments ) override;
+ virtual void SAL_CALL storeToURL( const OUString& sURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& seqArguments ) override;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */