summaryrefslogtreecommitdiffstats
path: root/basctl/source
diff options
context:
space:
mode:
Diffstat (limited to 'basctl/source')
-rw-r--r--basctl/source/accessibility/accessibledialogcontrolshape.cxx534
-rw-r--r--basctl/source/accessibility/accessibledialogwindow.cxx915
-rw-r--r--basctl/source/basicide/IDEComboBox.cxx530
-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.cxx1606
-rw-r--r--basctl/source/basicide/baside2.hxx526
-rw-r--r--basctl/source/basicide/baside2b.cxx2985
-rw-r--r--basctl/source/basicide/baside3.cxx1325
-rw-r--r--basctl/source/basicide/basidectrlr.cxx113
-rw-r--r--basctl/source/basicide/basides1.cxx1551
-rw-r--r--basctl/source/basicide/basides2.cxx239
-rw-r--r--basctl/source/basicide/basides3.cxx150
-rw-r--r--basctl/source/basicide/basidesh.cxx994
-rw-r--r--basctl/source/basicide/basobj2.cxx441
-rw-r--r--basctl/source/basicide/basobj3.cxx466
-rw-r--r--basctl/source/basicide/bastype2.cxx865
-rw-r--r--basctl/source/basicide/bastype3.cxx440
-rw-r--r--basctl/source/basicide/bastypes.cxx831
-rw-r--r--basctl/source/basicide/breakpoint.cxx158
-rw-r--r--basctl/source/basicide/breakpoint.hxx79
-rw-r--r--basctl/source/basicide/brkdlg.cxx231
-rw-r--r--basctl/source/basicide/brkdlg.hxx57
-rw-r--r--basctl/source/basicide/doceventnotifier.cxx250
-rw-r--r--basctl/source/basicide/docsignature.cxx75
-rw-r--r--basctl/source/basicide/documentenumeration.cxx157
-rw-r--r--basctl/source/basicide/documentenumeration.hxx90
-rw-r--r--basctl/source/basicide/iderdll.cxx205
-rw-r--r--basctl/source/basicide/iderdll2.hxx67
-rw-r--r--basctl/source/basicide/layout.cxx430
-rw-r--r--basctl/source/basicide/linenumberwindow.cxx135
-rw-r--r--basctl/source/basicide/linenumberwindow.hxx46
-rw-r--r--basctl/source/basicide/localizationmgr.cxx1100
-rw-r--r--basctl/source/basicide/macrodlg.cxx879
-rw-r--r--basctl/source/basicide/macrodlg.hxx108
-rw-r--r--basctl/source/basicide/moduldl2.cxx1373
-rw-r--r--basctl/source/basicide/moduldlg.cxx1052
-rw-r--r--basctl/source/basicide/moduldlg.hxx226
-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.cxx50
-rw-r--r--basctl/source/basicide/uiobject.hxx35
-rw-r--r--basctl/source/basicide/unomodel.cxx131
-rw-r--r--basctl/source/basicide/unomodel.hxx60
-rw-r--r--basctl/source/dlged/dlged.cxx1236
-rw-r--r--basctl/source/dlged/dlgedclip.cxx109
-rw-r--r--basctl/source/dlged/dlgedfac.cxx229
-rw-r--r--basctl/source/dlged/dlgedfunc.cxx548
-rw-r--r--basctl/source/dlged/dlgedlist.cxx80
-rw-r--r--basctl/source/dlged/dlgedmod.cxx36
-rw-r--r--basctl/source/dlged/dlgedobj.cxx1705
-rw-r--r--basctl/source/dlged/dlgedpage.cxx66
-rw-r--r--basctl/source/dlged/dlgedview.cxx184
-rw-r--r--basctl/source/dlged/managelang.cxx318
-rw-r--r--basctl/source/dlged/propbrw.cxx506
-rw-r--r--basctl/source/inc/IDEComboBox.hxx271
-rw-r--r--basctl/source/inc/ObjectCatalog.hxx60
-rw-r--r--basctl/source/inc/accessibledialogcontrolshape.hxx120
-rw-r--r--basctl/source/inc/accessibledialogwindow.hxx143
-rw-r--r--basctl/source/inc/baside3.hxx154
-rw-r--r--basctl/source/inc/basidectrlr.hxx68
-rw-r--r--basctl/source/inc/basidesh.hxx231
-rw-r--r--basctl/source/inc/basobj.hxx105
-rw-r--r--basctl/source/inc/bastype2.hxx278
-rw-r--r--basctl/source/inc/bastypes.hxx316
-rw-r--r--basctl/source/inc/dlged.hxx210
-rw-r--r--basctl/source/inc/dlgedclip.hxx53
-rw-r--r--basctl/source/inc/dlgeddef.hxx47
-rw-r--r--basctl/source/inc/dlgedfac.hxx43
-rw-r--r--basctl/source/inc/dlgedfunc.hxx80
-rw-r--r--basctl/source/inc/dlgedlist.hxx74
-rw-r--r--basctl/source/inc/dlgedmod.hxx45
-rw-r--r--basctl/source/inc/dlgedobj.hxx195
-rw-r--r--basctl/source/inc/dlgedpage.hxx52
-rw-r--r--basctl/source/inc/dlgedview.hxx59
-rw-r--r--basctl/source/inc/doceventnotifier.hxx82
-rw-r--r--basctl/source/inc/docsignature.hxx74
-rw-r--r--basctl/source/inc/iderid.hxx31
-rw-r--r--basctl/source/inc/layout.hxx133
-rw-r--r--basctl/source/inc/localizationmgr.hxx151
-rw-r--r--basctl/source/inc/managelang.hxx98
-rw-r--r--basctl/source/inc/propbrw.hxx85
-rw-r--r--basctl/source/inc/sbxitem.hxx65
-rw-r--r--basctl/source/inc/scriptdocument.hxx481
90 files changed, 32581 insertions, 0 deletions
diff --git a/basctl/source/accessibility/accessibledialogcontrolshape.cxx b/basctl/source/accessibility/accessibledialogcontrolshape.cxx
new file mode 100644
index 0000000000..62a260948f
--- /dev/null
+++ b/basctl/source/accessibility/accessibledialogcontrolshape.cxx
@@ -0,0 +1,534 @@
+/* -*- 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 <accessibledialogcontrolshape.hxx>
+#include <baside3.hxx>
+#include <dlgeddef.hxx>
+#include <dlgedview.hxx>
+#include <dlgedobj.hxx>
+#include <com/sun/star/awt/XVclWindowPeer.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <unotools/accessiblerelationsethelper.hxx>
+#include <toolkit/awt/vclxfont.hxx>
+#include <toolkit/helper/convert.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <comphelper/accessiblecontexthelper.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+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::accessibility;
+using namespace ::comphelper;
+
+
+
+
+AccessibleDialogControlShape::AccessibleDialogControlShape (DialogWindow* pDialogWindow, DlgEdObj* pDlgEdObj)
+ :m_pDialogWindow( pDialogWindow )
+ ,m_pDlgEdObj( pDlgEdObj )
+{
+ if ( m_pDlgEdObj )
+ m_xControlModel.set( m_pDlgEdObj->GetUnoControlModel(), UNO_QUERY );
+
+ if ( m_xControlModel.is() )
+ m_xControlModel->addPropertyChangeListener( OUString(), static_cast< beans::XPropertyChangeListener* >( this ) );
+
+ m_bFocused = IsFocused();
+ m_bSelected = IsSelected();
+ m_aBounds = GetBounds();
+}
+
+
+AccessibleDialogControlShape::~AccessibleDialogControlShape()
+{
+ if ( m_xControlModel.is() )
+ m_xControlModel->removePropertyChangeListener( OUString(), static_cast< beans::XPropertyChangeListener* >( this ) );
+}
+
+
+bool AccessibleDialogControlShape::IsFocused() const
+{
+ bool bFocused = false;
+ if ( m_pDialogWindow )
+ {
+ SdrView& rView = m_pDialogWindow->GetView();
+ if (rView.IsObjMarked(m_pDlgEdObj) && rView.GetMarkedObjectList().GetMarkCount() == 1)
+ bFocused = true;
+ }
+
+ return bFocused;
+}
+
+
+bool AccessibleDialogControlShape::IsSelected() const
+{
+ if ( m_pDialogWindow )
+ return m_pDialogWindow->GetView().IsObjMarked(m_pDlgEdObj);
+ return false;
+}
+
+
+void AccessibleDialogControlShape::SetFocused( bool bFocused )
+{
+ if ( m_bFocused != bFocused )
+ {
+ Any aOldValue, aNewValue;
+ if ( m_bFocused )
+ aOldValue <<= AccessibleStateType::FOCUSED;
+ else
+ aNewValue <<= AccessibleStateType::FOCUSED;
+ m_bFocused = bFocused;
+ NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
+ }
+}
+
+
+void AccessibleDialogControlShape::SetSelected( bool bSelected )
+{
+ if ( m_bSelected != bSelected )
+ {
+ Any aOldValue, aNewValue;
+ if ( m_bSelected )
+ aOldValue <<= AccessibleStateType::SELECTED;
+ else
+ aNewValue <<= AccessibleStateType::SELECTED;
+ m_bSelected = bSelected;
+ NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
+ }
+}
+
+
+awt::Rectangle AccessibleDialogControlShape::GetBounds() const
+{
+ awt::Rectangle aBounds( 0, 0, 0, 0 );
+ if ( m_pDlgEdObj )
+ {
+ // get the bounding box of the shape in logic units
+ tools::Rectangle aRect = m_pDlgEdObj->GetSnapRect();
+
+ if ( m_pDialogWindow )
+ {
+ // transform coordinates relative to the parent
+ MapMode aMap = m_pDialogWindow->GetMapMode();
+ Point aOrg = aMap.GetOrigin();
+ aRect.Move( aOrg.X(), aOrg.Y() );
+
+ // convert logic units to pixel
+ aRect = m_pDialogWindow->LogicToPixel( aRect, MapMode(MapUnit::Map100thMM) );
+
+ // clip the shape's bounding box with the bounding box of its parent
+ tools::Rectangle aParentRect( Point( 0, 0 ), m_pDialogWindow->GetSizePixel() );
+ aRect = aRect.GetIntersection( aParentRect );
+ aBounds = AWTRectangle( aRect );
+ }
+ }
+
+ return aBounds;
+}
+
+
+void AccessibleDialogControlShape::SetBounds( const awt::Rectangle& aBounds )
+{
+ if ( m_aBounds.X != aBounds.X || m_aBounds.Y != aBounds.Y || m_aBounds.Width != aBounds.Width || m_aBounds.Height != aBounds.Height )
+ {
+ m_aBounds = aBounds;
+ NotifyAccessibleEvent( AccessibleEventId::BOUNDRECT_CHANGED, Any(), Any() );
+ }
+}
+
+
+vcl::Window* AccessibleDialogControlShape::GetWindow() const
+{
+ vcl::Window* pWindow = nullptr;
+ if ( m_pDlgEdObj )
+ {
+ Reference< awt::XControl > xControl = m_pDlgEdObj->GetControl();
+ if ( xControl.is() )
+ pWindow = VCLUnoHelper::GetWindow( xControl->getPeer() );
+ }
+
+ return pWindow;
+}
+
+
+OUString AccessibleDialogControlShape::GetModelStringProperty( OUString const & pPropertyName )
+{
+ OUString sReturn;
+
+ try
+ {
+ if ( m_xControlModel.is() )
+ {
+ Reference< XPropertySetInfo > xInfo = m_xControlModel->getPropertySetInfo();
+ if ( xInfo.is() && xInfo->hasPropertyByName( pPropertyName ) )
+ m_xControlModel->getPropertyValue( pPropertyName ) >>= sReturn;
+ }
+ }
+ catch ( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "basctl", "AccessibleDialogControlShape::GetModelStringProperty" );
+ }
+
+ return sReturn;
+}
+
+
+void AccessibleDialogControlShape::FillAccessibleStateSet( sal_Int64& rStateSet )
+{
+ rStateSet |= AccessibleStateType::ENABLED;
+
+ rStateSet |= AccessibleStateType::VISIBLE;
+
+ rStateSet |= AccessibleStateType::SHOWING;
+
+ rStateSet |= AccessibleStateType::FOCUSABLE;
+
+ if ( IsFocused() )
+ rStateSet |= AccessibleStateType::FOCUSED;
+
+ rStateSet |= AccessibleStateType::SELECTABLE;
+
+ if ( IsSelected() )
+ rStateSet |= AccessibleStateType::SELECTED;
+
+ rStateSet |= AccessibleStateType::RESIZABLE;
+}
+
+// OCommonAccessibleComponent
+awt::Rectangle AccessibleDialogControlShape::implGetBounds()
+{
+ return GetBounds();
+}
+
+// XComponent
+void AccessibleDialogControlShape::disposing()
+{
+ OAccessibleExtendedComponentHelper::disposing();
+
+ m_pDialogWindow = nullptr;
+ m_pDlgEdObj = nullptr;
+
+ if ( m_xControlModel.is() )
+ m_xControlModel->removePropertyChangeListener( OUString(), static_cast< beans::XPropertyChangeListener* >( this ) );
+ m_xControlModel.clear();
+}
+
+
+// XEventListener
+
+
+void AccessibleDialogControlShape::disposing( const lang::EventObject& )
+{
+ if ( m_xControlModel.is() )
+ m_xControlModel->removePropertyChangeListener( OUString(), static_cast< beans::XPropertyChangeListener* >( this ) );
+ m_xControlModel.clear();
+}
+
+
+// XPropertyChangeListener
+
+
+void AccessibleDialogControlShape::propertyChange( const beans::PropertyChangeEvent& rEvent )
+{
+ if ( rEvent.PropertyName == DLGED_PROP_NAME )
+ {
+ NotifyAccessibleEvent( AccessibleEventId::NAME_CHANGED, rEvent.OldValue, rEvent.NewValue );
+ }
+ else if ( rEvent.PropertyName == DLGED_PROP_POSITIONX ||
+ rEvent.PropertyName == DLGED_PROP_POSITIONY ||
+ rEvent.PropertyName == DLGED_PROP_WIDTH ||
+ rEvent.PropertyName == DLGED_PROP_HEIGHT )
+ {
+ SetBounds( GetBounds() );
+ }
+ else if ( rEvent.PropertyName == DLGED_PROP_BACKGROUNDCOLOR ||
+ rEvent.PropertyName == DLGED_PROP_TEXTCOLOR ||
+ rEvent.PropertyName == DLGED_PROP_TEXTLINECOLOR )
+ {
+ NotifyAccessibleEvent( AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any() );
+ }
+}
+
+// XServiceInfo
+OUString AccessibleDialogControlShape::getImplementationName()
+{
+ return "com.sun.star.comp.basctl.AccessibleShape";
+}
+
+sal_Bool AccessibleDialogControlShape::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence< OUString > AccessibleDialogControlShape::getSupportedServiceNames()
+{
+ return { "com.sun.star.drawing.AccessibleShape" };
+}
+
+// XAccessible
+Reference< XAccessibleContext > AccessibleDialogControlShape::getAccessibleContext( )
+{
+ return this;
+}
+
+// XAccessibleContext
+sal_Int64 AccessibleDialogControlShape::getAccessibleChildCount()
+{
+ return 0;
+}
+
+
+Reference< XAccessible > AccessibleDialogControlShape::getAccessibleChild( sal_Int64 i )
+{
+ OExternalLockGuard aGuard( this );
+
+ if ( i < 0 || i >= getAccessibleChildCount() )
+ throw IndexOutOfBoundsException();
+
+ return Reference< XAccessible >();
+}
+
+
+Reference< XAccessible > AccessibleDialogControlShape::getAccessibleParent( )
+{
+ OExternalLockGuard aGuard( this );
+
+ Reference< XAccessible > xParent;
+ if ( m_pDialogWindow )
+ xParent = m_pDialogWindow->GetAccessible();
+
+ return xParent;
+}
+
+
+sal_Int64 AccessibleDialogControlShape::getAccessibleIndexInParent( )
+{
+ OExternalLockGuard aGuard( this );
+
+ sal_Int64 nIndexInParent = -1;
+ Reference< XAccessible > xParent( getAccessibleParent() );
+ if ( xParent.is() )
+ {
+ Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
+ if ( xParentContext.is() )
+ {
+ for ( sal_Int64 i = 0, nCount = xParentContext->getAccessibleChildCount(); i < nCount; ++i )
+ {
+ Reference< XAccessible > xChild( xParentContext->getAccessibleChild( i ) );
+ if ( xChild.is() )
+ {
+ Reference< XAccessibleContext > xChildContext = xChild->getAccessibleContext();
+ if ( xChildContext == static_cast<XAccessibleContext*>(this) )
+ {
+ nIndexInParent = i;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return nIndexInParent;
+}
+
+
+sal_Int16 AccessibleDialogControlShape::getAccessibleRole( )
+{
+ OExternalLockGuard aGuard( this );
+
+ return AccessibleRole::SHAPE;
+}
+
+
+OUString AccessibleDialogControlShape::getAccessibleDescription( )
+{
+ OExternalLockGuard aGuard( this );
+
+ return GetModelStringProperty( "HelpText" );
+}
+
+
+OUString AccessibleDialogControlShape::getAccessibleName( )
+{
+ OExternalLockGuard aGuard( this );
+
+ return GetModelStringProperty( "Name" );
+}
+
+
+Reference< XAccessibleRelationSet > AccessibleDialogControlShape::getAccessibleRelationSet( )
+{
+ OExternalLockGuard aGuard( this );
+
+ return new utl::AccessibleRelationSetHelper;
+}
+
+
+sal_Int64 AccessibleDialogControlShape::getAccessibleStateSet( )
+{
+ OExternalLockGuard aGuard( this );
+
+ sal_Int64 nStateSet = 0;
+
+ if ( !rBHelper.bDisposed && !rBHelper.bInDispose )
+ {
+ FillAccessibleStateSet( nStateSet );
+ }
+ else
+ {
+ nStateSet |= AccessibleStateType::DEFUNC;
+ }
+
+ return nStateSet;
+}
+
+
+Locale AccessibleDialogControlShape::getLocale( )
+{
+ OExternalLockGuard aGuard( this );
+
+ return Application::GetSettings().GetLanguageTag().getLocale();
+}
+
+
+// XAccessibleComponent
+
+
+Reference< XAccessible > AccessibleDialogControlShape::getAccessibleAtPoint( const awt::Point& )
+{
+ OExternalLockGuard aGuard( this );
+
+ return Reference< XAccessible >();
+}
+
+
+void AccessibleDialogControlShape::grabFocus( )
+{
+ // no focus for shapes
+}
+
+
+sal_Int32 AccessibleDialogControlShape::getForeground( )
+{
+ OExternalLockGuard aGuard( this );
+
+ Color nColor;
+ vcl::Window* pWindow = GetWindow();
+ if ( pWindow )
+ {
+ if ( pWindow->IsControlForeground() )
+ nColor = pWindow->GetControlForeground();
+ else
+ {
+ vcl::Font aFont;
+ if ( pWindow->IsControlFont() )
+ aFont = pWindow->GetControlFont();
+ else
+ aFont = pWindow->GetFont();
+ nColor = aFont.GetColor();
+ }
+ }
+
+ return sal_Int32(nColor);
+}
+
+
+sal_Int32 AccessibleDialogControlShape::getBackground( )
+{
+ OExternalLockGuard aGuard( this );
+
+ Color nColor;
+ vcl::Window* pWindow = GetWindow();
+ if ( pWindow )
+ {
+ if ( pWindow->IsControlBackground() )
+ nColor = pWindow->GetControlBackground();
+ else
+ nColor = pWindow->GetBackground().GetColor();
+ }
+
+ return sal_Int32(nColor);
+}
+
+
+// XAccessibleExtendedComponent
+
+
+Reference< awt::XFont > AccessibleDialogControlShape::getFont( )
+{
+ OExternalLockGuard aGuard( this );
+
+ Reference< awt::XFont > xFont;
+ vcl::Window* pWindow = GetWindow();
+ if ( pWindow )
+ {
+ Reference< awt::XDevice > xDev( pWindow->GetComponentInterface(), UNO_QUERY );
+ if ( xDev.is() )
+ {
+ vcl::Font aFont;
+ if ( pWindow->IsControlFont() )
+ aFont = pWindow->GetControlFont();
+ else
+ aFont = pWindow->GetFont();
+ rtl::Reference<VCLXFont> pVCLXFont = new VCLXFont;
+ pVCLXFont->Init( *xDev, aFont );
+ xFont = pVCLXFont;
+ }
+ }
+
+ return xFont;
+}
+
+
+OUString AccessibleDialogControlShape::getTitledBorderText( )
+{
+ OExternalLockGuard aGuard( this );
+
+ return OUString();
+}
+
+
+OUString AccessibleDialogControlShape::getToolTipText( )
+{
+ OExternalLockGuard aGuard( this );
+
+ OUString sText;
+ vcl::Window* pWindow = GetWindow();
+ if ( pWindow )
+ sText = pWindow->GetQuickHelpText();
+
+ return sText;
+}
+
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/accessibility/accessibledialogwindow.cxx b/basctl/source/accessibility/accessibledialogwindow.cxx
new file mode 100644
index 0000000000..d5c702616d
--- /dev/null
+++ b/basctl/source/accessibility/accessibledialogwindow.cxx
@@ -0,0 +1,915 @@
+/* -*- 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 <accessibledialogwindow.hxx>
+#include <accessibledialogcontrolshape.hxx>
+#include <baside3.hxx>
+#include <dlged.hxx>
+#include <dlgedmod.hxx>
+#include <dlgedpage.hxx>
+#include <dlgedview.hxx>
+#include <dlgedobj.hxx>
+#include <com/sun/star/awt/XVclWindowPeer.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <comphelper/accessiblecontexthelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <tools/debug.hxx>
+#include <unotools/accessiblerelationsethelper.hxx>
+#include <toolkit/awt/vclxfont.hxx>
+#include <toolkit/helper/convert.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::accessibility;
+using namespace ::comphelper;
+
+AccessibleDialogWindow::ChildDescriptor::ChildDescriptor( DlgEdObj* _pDlgEdObj )
+ :pDlgEdObj( _pDlgEdObj )
+{
+}
+
+bool AccessibleDialogWindow::ChildDescriptor::operator==( const ChildDescriptor& rDesc )
+{
+ bool bRet = false;
+ if ( pDlgEdObj == rDesc.pDlgEdObj )
+ bRet = true;
+
+ return bRet;
+}
+
+
+bool AccessibleDialogWindow::ChildDescriptor::operator<( const ChildDescriptor& rDesc ) const
+{
+ bool bRet = false;
+ if ( pDlgEdObj && rDesc.pDlgEdObj && pDlgEdObj->GetOrdNum() < rDesc.pDlgEdObj->GetOrdNum() )
+ bRet = true;
+
+ return bRet;
+}
+
+
+
+
+AccessibleDialogWindow::AccessibleDialogWindow (basctl::DialogWindow* pDialogWindow)
+ : m_pDialogWindow(pDialogWindow)
+ , m_pDlgEdModel(nullptr)
+{
+ if ( !m_pDialogWindow )
+ return;
+
+ SdrPage& rPage = m_pDialogWindow->GetPage();
+
+ for (const rtl::Reference<SdrObject>& pObj : rPage)
+ {
+ if (DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj.get()))
+ {
+ ChildDescriptor aDesc( pDlgEdObj );
+ if ( IsChildVisible( aDesc ) )
+ m_aAccessibleChildren.push_back( aDesc );
+ }
+ }
+
+ m_pDialogWindow->AddEventListener( LINK( this, AccessibleDialogWindow, WindowEventListener ) );
+
+ StartListening(m_pDialogWindow->GetEditor());
+
+ m_pDlgEdModel = &m_pDialogWindow->GetModel();
+ StartListening(*m_pDlgEdModel);
+}
+
+
+AccessibleDialogWindow::~AccessibleDialogWindow()
+{
+ if ( m_pDialogWindow )
+ m_pDialogWindow->RemoveEventListener( LINK( this, AccessibleDialogWindow, WindowEventListener ) );
+
+ if ( m_pDlgEdModel )
+ EndListening( *m_pDlgEdModel );
+}
+
+
+void AccessibleDialogWindow::UpdateFocused()
+{
+ for (const ChildDescriptor & i : m_aAccessibleChildren)
+ {
+ if ( i.mxAccessible )
+ i.mxAccessible->SetFocused( i.mxAccessible->IsFocused() );
+ }
+}
+
+
+void AccessibleDialogWindow::UpdateSelected()
+{
+ NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
+
+ for (const ChildDescriptor & i : m_aAccessibleChildren)
+ {
+ if ( i.mxAccessible )
+ i.mxAccessible->SetSelected( i.mxAccessible->IsSelected() );
+ }
+}
+
+
+void AccessibleDialogWindow::UpdateBounds()
+{
+ for (const ChildDescriptor & i : m_aAccessibleChildren)
+ {
+ if ( i.mxAccessible )
+ i.mxAccessible->SetBounds( i.mxAccessible->GetBounds() );
+ }
+}
+
+
+bool AccessibleDialogWindow::IsChildVisible( const ChildDescriptor& rDesc )
+{
+ bool bVisible = false;
+
+ if ( m_pDialogWindow )
+ {
+ // first check, if the shape is in a visible layer
+ SdrLayerAdmin& rLayerAdmin = m_pDialogWindow->GetModel().GetLayerAdmin();
+ DlgEdObj* pDlgEdObj = rDesc.pDlgEdObj;
+ if ( pDlgEdObj )
+ {
+ SdrLayerID nLayerId = pDlgEdObj->GetLayer();
+ const SdrLayer* pSdrLayer = rLayerAdmin.GetLayerPerID( nLayerId );
+ if ( pSdrLayer )
+ {
+ const OUString& aLayerName = pSdrLayer->GetName();
+ SdrView& rView = m_pDialogWindow->GetView();
+ if (rView.IsLayerVisible(aLayerName))
+ {
+ // get the bounding box of the shape in logic units
+ tools::Rectangle aRect = pDlgEdObj->GetSnapRect();
+
+ // transform coordinates relative to the parent
+ MapMode aMap = m_pDialogWindow->GetMapMode();
+ Point aOrg = aMap.GetOrigin();
+ aRect.Move( aOrg.X(), aOrg.Y() );
+
+ // convert logic units to pixel
+ aRect = m_pDialogWindow->LogicToPixel( aRect, MapMode(MapUnit::Map100thMM) );
+
+ // check, if the shape's bounding box intersects with the bounding box of its parent
+ tools::Rectangle aParentRect( Point( 0, 0 ), m_pDialogWindow->GetSizePixel() );
+ if ( aParentRect.Overlaps( aRect ) )
+ bVisible = true;
+ }
+ }
+ }
+ }
+
+ return bVisible;
+}
+
+
+void AccessibleDialogWindow::InsertChild( const ChildDescriptor& rDesc )
+{
+ // check, if object is already in child list
+ AccessibleChildren::iterator aIter = std::find( m_aAccessibleChildren.begin(), m_aAccessibleChildren.end(), rDesc );
+
+ // if not found, insert in child list
+ if ( aIter != m_aAccessibleChildren.end() )
+ return;
+
+ // insert entry in child list
+ m_aAccessibleChildren.push_back( rDesc );
+
+ // get the accessible of the inserted child
+ Reference< XAccessible > xChild( getAccessibleChild( m_aAccessibleChildren.size() - 1 ) );
+
+ // sort child list
+ SortChildren();
+
+ // send accessible child event
+ if ( xChild.is() )
+ {
+ Any aOldValue, aNewValue;
+ aNewValue <<= xChild;
+ NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
+ }
+}
+
+
+void AccessibleDialogWindow::RemoveChild( const ChildDescriptor& rDesc )
+{
+ // find object in child list
+ AccessibleChildren::iterator aIter = std::find( m_aAccessibleChildren.begin(), m_aAccessibleChildren.end(), rDesc );
+
+ // if found, remove from child list
+ if ( aIter == m_aAccessibleChildren.end() )
+ return;
+
+ // get the accessible of the removed child
+ rtl::Reference< AccessibleDialogControlShape > xChild( aIter->mxAccessible );
+
+ // remove entry from child list
+ m_aAccessibleChildren.erase( aIter );
+
+ // send accessible child event
+ if ( xChild.is() )
+ {
+ Any aOldValue, aNewValue;
+ aOldValue <<= uno::Reference<XAccessible>(xChild);
+ NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
+
+ if ( xChild )
+ xChild->dispose();
+ }
+}
+
+
+void AccessibleDialogWindow::UpdateChild( const ChildDescriptor& rDesc )
+{
+ if ( IsChildVisible( rDesc ) )
+ {
+ // if the object is not in the child list, insert child
+ InsertChild( rDesc );
+ }
+ else
+ {
+ // if the object is in the child list, remove child
+ RemoveChild( rDesc );
+ }
+}
+
+
+void AccessibleDialogWindow::UpdateChildren()
+{
+ if ( m_pDialogWindow )
+ {
+ SdrPage& rPage = m_pDialogWindow->GetPage();
+ for (const rtl::Reference<SdrObject>& pObj : rPage)
+ if (DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj.get()))
+ UpdateChild( ChildDescriptor( pDlgEdObj ) );
+ }
+}
+
+
+void AccessibleDialogWindow::SortChildren()
+{
+ // sort child list
+ std::sort( m_aAccessibleChildren.begin(), m_aAccessibleChildren.end() );
+}
+
+
+IMPL_LINK( AccessibleDialogWindow, WindowEventListener, VclWindowEvent&, rEvent, void )
+{
+ DBG_ASSERT(rEvent.GetWindow(), "AccessibleDialogWindow::WindowEventListener: no window!");
+ if (!rEvent.GetWindow()->IsAccessibilityEventsSuppressed() || rEvent.GetId() == VclEventId::ObjectDying)
+ ProcessWindowEvent(rEvent);
+}
+
+
+void AccessibleDialogWindow::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
+{
+ Any aOldValue, aNewValue;
+
+ switch ( rVclWindowEvent.GetId() )
+ {
+ case VclEventId::WindowEnabled:
+ {
+ aNewValue <<= AccessibleStateType::ENABLED;
+ NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
+ }
+ break;
+ case VclEventId::WindowDisabled:
+ {
+ aOldValue <<= AccessibleStateType::ENABLED;
+ NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
+ }
+ break;
+ case VclEventId::WindowActivate:
+ {
+ aNewValue <<= AccessibleStateType::ACTIVE;
+ NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
+ }
+ break;
+ case VclEventId::WindowDeactivate:
+ {
+ aOldValue <<= AccessibleStateType::ACTIVE;
+ NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
+ }
+ break;
+ case VclEventId::WindowGetFocus:
+ {
+ aNewValue <<= AccessibleStateType::FOCUSED;
+ NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
+ }
+ break;
+ case VclEventId::WindowLoseFocus:
+ {
+ aOldValue <<= AccessibleStateType::FOCUSED;
+ NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
+ }
+ break;
+ case VclEventId::WindowShow:
+ {
+ aNewValue <<= AccessibleStateType::SHOWING;
+ NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
+ }
+ break;
+ case VclEventId::WindowHide:
+ {
+ aOldValue <<= AccessibleStateType::SHOWING;
+ NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
+ }
+ break;
+ case VclEventId::WindowResize:
+ {
+ NotifyAccessibleEvent( AccessibleEventId::BOUNDRECT_CHANGED, aOldValue, aNewValue );
+ UpdateChildren();
+ UpdateBounds();
+ }
+ break;
+ case VclEventId::ObjectDying:
+ {
+ if ( m_pDialogWindow )
+ {
+ m_pDialogWindow->RemoveEventListener( LINK( this, AccessibleDialogWindow, WindowEventListener ) );
+ m_pDialogWindow = nullptr;
+
+ if ( m_pDlgEdModel )
+ EndListening( *m_pDlgEdModel );
+ m_pDlgEdModel = nullptr;
+
+ // dispose all children
+ for (const ChildDescriptor & i : m_aAccessibleChildren)
+ {
+ if ( i.mxAccessible )
+ i.mxAccessible->dispose();
+ }
+ m_aAccessibleChildren.clear();
+ }
+ }
+ break;
+ default:
+ {
+ }
+ break;
+ }
+}
+
+
+void AccessibleDialogWindow::FillAccessibleStateSet( sal_Int64& rStateSet )
+{
+ if ( !m_pDialogWindow )
+ return;
+
+ if ( m_pDialogWindow->IsEnabled() )
+ rStateSet |= AccessibleStateType::ENABLED;
+
+ rStateSet |= AccessibleStateType::FOCUSABLE;
+
+ if ( m_pDialogWindow->HasFocus() )
+ rStateSet |= AccessibleStateType::FOCUSED;
+
+ rStateSet |= AccessibleStateType::VISIBLE;
+
+ if ( m_pDialogWindow->IsVisible() )
+ rStateSet |= AccessibleStateType::SHOWING;
+
+ rStateSet |= AccessibleStateType::OPAQUE;
+
+ rStateSet |= AccessibleStateType::RESIZABLE;
+}
+
+
+// OCommonAccessibleComponent
+
+
+awt::Rectangle AccessibleDialogWindow::implGetBounds()
+{
+ awt::Rectangle aBounds;
+ if ( m_pDialogWindow )
+ aBounds = AWTRectangle( tools::Rectangle( m_pDialogWindow->GetPosPixel(), m_pDialogWindow->GetSizePixel() ) );
+
+ return aBounds;
+}
+
+
+// SfxListener
+
+
+void AccessibleDialogWindow::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if (SdrHint const* pSdrHint = dynamic_cast<SdrHint const*>(&rHint))
+ {
+ switch ( pSdrHint->GetKind() )
+ {
+ case SdrHintKind::ObjectInserted:
+ {
+ if (DlgEdObj const* pDlgEdObj = dynamic_cast<DlgEdObj const*>(pSdrHint->GetObject()))
+ {
+ ChildDescriptor aDesc(const_cast<DlgEdObj*>(pDlgEdObj));
+ if ( IsChildVisible( aDesc ) )
+ InsertChild( aDesc );
+ }
+ }
+ break;
+ case SdrHintKind::ObjectRemoved:
+ {
+ if (DlgEdObj const* pDlgEdObj = dynamic_cast<DlgEdObj const*>(pSdrHint->GetObject()))
+ RemoveChild( ChildDescriptor(const_cast<DlgEdObj*>(pDlgEdObj)) );
+ }
+ break;
+ default: ;
+ }
+ }
+ else if (DlgEdHint const* pDlgEdHint = dynamic_cast<DlgEdHint const*>(&rHint))
+ {
+ switch (pDlgEdHint->GetKind())
+ {
+ case DlgEdHint::WINDOWSCROLLED:
+ {
+ UpdateChildren();
+ UpdateBounds();
+ }
+ break;
+ case DlgEdHint::LAYERCHANGED:
+ {
+ if (DlgEdObj* pDlgEdObj = pDlgEdHint->GetObject())
+ UpdateChild( ChildDescriptor( pDlgEdObj ) );
+ }
+ break;
+ case DlgEdHint::OBJORDERCHANGED:
+ {
+ SortChildren();
+ }
+ break;
+ case DlgEdHint::SELECTIONCHANGED:
+ {
+ UpdateFocused();
+ UpdateSelected();
+ }
+ break;
+ default: ;
+ }
+ }
+}
+
+
+// XComponent
+
+
+void AccessibleDialogWindow::disposing()
+{
+ OAccessibleExtendedComponentHelper::disposing();
+
+ if ( !m_pDialogWindow )
+ return;
+
+ m_pDialogWindow->RemoveEventListener( LINK( this, AccessibleDialogWindow, WindowEventListener ) );
+ m_pDialogWindow = nullptr;
+
+ if ( m_pDlgEdModel )
+ EndListening( *m_pDlgEdModel );
+ m_pDlgEdModel = nullptr;
+
+ // dispose all children
+ for (const ChildDescriptor & i : m_aAccessibleChildren)
+ {
+ if ( i.mxAccessible )
+ i.mxAccessible->dispose();
+ }
+ m_aAccessibleChildren.clear();
+}
+
+// XServiceInfo
+OUString AccessibleDialogWindow::getImplementationName()
+{
+ return "com.sun.star.comp.basctl.AccessibleWindow";
+}
+
+sal_Bool AccessibleDialogWindow::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence< OUString > AccessibleDialogWindow::getSupportedServiceNames()
+{
+ return { "com.sun.star.awt.AccessibleWindow" };
+}
+
+// XAccessible
+Reference< XAccessibleContext > AccessibleDialogWindow::getAccessibleContext( )
+{
+ return this;
+}
+
+// XAccessibleContext
+sal_Int64 AccessibleDialogWindow::getAccessibleChildCount()
+{
+ OExternalLockGuard aGuard( this );
+
+ return m_aAccessibleChildren.size();
+}
+
+
+Reference< XAccessible > AccessibleDialogWindow::getAccessibleChild( sal_Int64 i )
+{
+ OExternalLockGuard aGuard( this );
+
+ if ( i < 0 || i >= getAccessibleChildCount() )
+ throw IndexOutOfBoundsException();
+
+ rtl::Reference< AccessibleDialogControlShape > xChild = m_aAccessibleChildren[i].mxAccessible;
+ if ( !xChild.is() )
+ {
+ if ( m_pDialogWindow )
+ {
+ DlgEdObj* pDlgEdObj = m_aAccessibleChildren[i].pDlgEdObj;
+ if ( pDlgEdObj )
+ {
+ xChild = new AccessibleDialogControlShape( m_pDialogWindow, pDlgEdObj );
+
+ // insert into child list
+ m_aAccessibleChildren[i].mxAccessible = xChild;
+ }
+ }
+ }
+
+ return xChild;
+}
+
+
+Reference< XAccessible > AccessibleDialogWindow::getAccessibleParent( )
+{
+ OExternalLockGuard aGuard( this );
+
+ Reference< XAccessible > xParent;
+ if ( m_pDialogWindow )
+ {
+ vcl::Window* pParent = m_pDialogWindow->GetAccessibleParentWindow();
+ if ( pParent )
+ xParent = pParent->GetAccessible();
+ }
+
+ return xParent;
+}
+
+
+sal_Int64 AccessibleDialogWindow::getAccessibleIndexInParent( )
+{
+ OExternalLockGuard aGuard( this );
+
+ sal_Int64 nIndexInParent = -1;
+ if ( m_pDialogWindow )
+ {
+ vcl::Window* pParent = m_pDialogWindow->GetAccessibleParentWindow();
+ if ( pParent )
+ {
+ for ( sal_uInt16 i = 0, nCount = pParent->GetAccessibleChildWindowCount(); i < nCount; ++i )
+ {
+ vcl::Window* pChild = pParent->GetAccessibleChildWindow( i );
+ if ( pChild == static_cast< vcl::Window* >( m_pDialogWindow ) )
+ {
+ nIndexInParent = i;
+ break;
+ }
+ }
+ }
+ }
+
+ return nIndexInParent;
+}
+
+
+sal_Int16 AccessibleDialogWindow::getAccessibleRole( )
+{
+ OExternalLockGuard aGuard( this );
+
+ return AccessibleRole::PANEL;
+}
+
+
+OUString AccessibleDialogWindow::getAccessibleDescription( )
+{
+ OExternalLockGuard aGuard( this );
+
+ OUString sDescription;
+ if ( m_pDialogWindow )
+ sDescription = m_pDialogWindow->GetAccessibleDescription();
+
+ return sDescription;
+}
+
+
+OUString AccessibleDialogWindow::getAccessibleName( )
+{
+ OExternalLockGuard aGuard( this );
+
+ OUString sName;
+ if ( m_pDialogWindow )
+ sName = m_pDialogWindow->GetAccessibleName();
+
+ return sName;
+}
+
+
+Reference< XAccessibleRelationSet > AccessibleDialogWindow::getAccessibleRelationSet( )
+{
+ OExternalLockGuard aGuard( this );
+
+ return new utl::AccessibleRelationSetHelper;
+}
+
+
+sal_Int64 AccessibleDialogWindow::getAccessibleStateSet( )
+{
+ OExternalLockGuard aGuard( this );
+
+ sal_Int64 nStateSet = 0;
+
+ if ( !rBHelper.bDisposed && !rBHelper.bInDispose )
+ {
+ FillAccessibleStateSet( nStateSet );
+ }
+ else
+ {
+ nStateSet |= AccessibleStateType::DEFUNC;
+ }
+
+ return nStateSet;
+}
+
+
+Locale AccessibleDialogWindow::getLocale( )
+{
+ OExternalLockGuard aGuard( this );
+
+ return Application::GetSettings().GetLanguageTag().getLocale();
+}
+
+
+// XAccessibleComponent
+
+
+Reference< XAccessible > AccessibleDialogWindow::getAccessibleAtPoint( const awt::Point& rPoint )
+{
+ OExternalLockGuard aGuard( this );
+
+ Reference< XAccessible > xChild;
+ for ( size_t i = 0; i < m_aAccessibleChildren.size(); ++i )
+ {
+ Reference< XAccessible > xAcc = getAccessibleChild( i );
+ if ( xAcc.is() )
+ {
+ Reference< XAccessibleComponent > xComp( xAcc->getAccessibleContext(), UNO_QUERY );
+ if ( xComp.is() )
+ {
+ tools::Rectangle aRect = VCLRectangle( xComp->getBounds() );
+ Point aPos = VCLPoint( rPoint );
+ if ( aRect.Contains( aPos ) )
+ {
+ xChild = xAcc;
+ break;
+ }
+ }
+ }
+ }
+
+ return xChild;
+}
+
+
+void AccessibleDialogWindow::grabFocus( )
+{
+ OExternalLockGuard aGuard( this );
+
+ if ( m_pDialogWindow )
+ m_pDialogWindow->GrabFocus();
+}
+
+
+sal_Int32 AccessibleDialogWindow::getForeground( )
+{
+ OExternalLockGuard aGuard( this );
+
+ Color nColor;
+ if ( m_pDialogWindow )
+ {
+ if ( m_pDialogWindow->IsControlForeground() )
+ nColor = m_pDialogWindow->GetControlForeground();
+ else
+ {
+ vcl::Font aFont;
+ if ( m_pDialogWindow->IsControlFont() )
+ aFont = m_pDialogWindow->GetControlFont();
+ else
+ aFont = m_pDialogWindow->GetFont();
+ nColor = aFont.GetColor();
+ }
+ }
+
+ return sal_Int32(nColor);
+}
+
+
+sal_Int32 AccessibleDialogWindow::getBackground( )
+{
+ OExternalLockGuard aGuard( this );
+
+ Color nColor;
+ if ( m_pDialogWindow )
+ {
+ if ( m_pDialogWindow->IsControlBackground() )
+ nColor = m_pDialogWindow->GetControlBackground();
+ else
+ nColor = m_pDialogWindow->GetBackground().GetColor();
+ }
+
+ return sal_Int32(nColor);
+}
+
+
+// XAccessibleExtendedComponent
+
+
+Reference< awt::XFont > AccessibleDialogWindow::getFont( )
+{
+ OExternalLockGuard aGuard( this );
+
+ Reference< awt::XFont > xFont;
+ if ( m_pDialogWindow )
+ {
+ Reference< awt::XDevice > xDev( m_pDialogWindow->GetComponentInterface(), UNO_QUERY );
+ if ( xDev.is() )
+ {
+ vcl::Font aFont;
+ if ( m_pDialogWindow->IsControlFont() )
+ aFont = m_pDialogWindow->GetControlFont();
+ else
+ aFont = m_pDialogWindow->GetFont();
+ rtl::Reference<VCLXFont> pVCLXFont = new VCLXFont;
+ pVCLXFont->Init( *xDev, aFont );
+ xFont = pVCLXFont;
+ }
+ }
+
+ return xFont;
+}
+
+
+OUString AccessibleDialogWindow::getTitledBorderText( )
+{
+ OExternalLockGuard aGuard( this );
+
+ return OUString();
+}
+
+
+OUString AccessibleDialogWindow::getToolTipText( )
+{
+ OExternalLockGuard aGuard( this );
+
+ OUString sText;
+ if ( m_pDialogWindow )
+ sText = m_pDialogWindow->GetQuickHelpText();
+
+ return sText;
+}
+
+
+// XAccessibleSelection
+
+
+void AccessibleDialogWindow::selectAccessibleChild( sal_Int64 nChildIndex )
+{
+ OExternalLockGuard aGuard( this );
+
+ if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() )
+ throw IndexOutOfBoundsException();
+
+ if ( m_pDialogWindow )
+ {
+ if (DlgEdObj* pDlgEdObj = m_aAccessibleChildren[nChildIndex].pDlgEdObj)
+ {
+ SdrView& rView = m_pDialogWindow->GetView();
+ if (SdrPageView* pPgView = rView.GetSdrPageView())
+ rView.MarkObj(pDlgEdObj, pPgView);
+ }
+ }
+}
+
+
+sal_Bool AccessibleDialogWindow::isAccessibleChildSelected( sal_Int64 nChildIndex )
+{
+ OExternalLockGuard aGuard( this );
+
+ if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() )
+ throw IndexOutOfBoundsException();
+
+ if (m_pDialogWindow)
+ if (DlgEdObj* pDlgEdObj = m_aAccessibleChildren[nChildIndex].pDlgEdObj)
+ return m_pDialogWindow->GetView().IsObjMarked(pDlgEdObj);
+ return false;
+}
+
+
+void AccessibleDialogWindow::clearAccessibleSelection()
+{
+ OExternalLockGuard aGuard( this );
+
+ if ( m_pDialogWindow )
+ m_pDialogWindow->GetView().UnmarkAll();
+}
+
+
+void AccessibleDialogWindow::selectAllAccessibleChildren( )
+{
+ OExternalLockGuard aGuard( this );
+
+ if ( m_pDialogWindow )
+ m_pDialogWindow->GetView().MarkAll();
+}
+
+
+sal_Int64 AccessibleDialogWindow::getSelectedAccessibleChildCount( )
+{
+ OExternalLockGuard aGuard( this );
+
+ sal_Int64 nRet = 0;
+
+ for ( sal_Int64 i = 0, nCount = getAccessibleChildCount(); i < nCount; ++i )
+ {
+ if ( isAccessibleChildSelected( i ) )
+ ++nRet;
+ }
+
+ return nRet;
+}
+
+
+Reference< XAccessible > AccessibleDialogWindow::getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex )
+{
+ OExternalLockGuard aGuard( this );
+
+ if ( nSelectedChildIndex < 0 || nSelectedChildIndex >= getSelectedAccessibleChildCount() )
+ throw IndexOutOfBoundsException();
+
+ Reference< XAccessible > xChild;
+
+ for ( sal_Int64 i = 0, j = 0, nCount = getAccessibleChildCount(); i < nCount; ++i )
+ {
+ if ( isAccessibleChildSelected( i ) && ( j++ == nSelectedChildIndex ) )
+ {
+ xChild = getAccessibleChild( i );
+ break;
+ }
+ }
+
+ return xChild;
+}
+
+
+void AccessibleDialogWindow::deselectAccessibleChild( sal_Int64 nChildIndex )
+{
+ OExternalLockGuard aGuard( this );
+
+ if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() )
+ throw IndexOutOfBoundsException();
+
+ if ( m_pDialogWindow )
+ {
+ if (DlgEdObj* pDlgEdObj = m_aAccessibleChildren[nChildIndex].pDlgEdObj)
+ {
+ SdrView& rView = m_pDialogWindow->GetView();
+ SdrPageView* pPgView = rView.GetSdrPageView();
+ if (pPgView)
+ rView.MarkObj( pDlgEdObj, pPgView, true );
+ }
+ }
+}
+
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/basicide/IDEComboBox.cxx b/basctl/source/basicide/IDEComboBox.cxx
new file mode 100644
index 0000000000..d25e143d62
--- /dev/null
+++ b/basctl/source/basicide/IDEComboBox.cxx
@@ -0,0 +1,530 @@
+/* -*- 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>
+#include <svl/itemset.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 0000000000..13069ed466
--- /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 0000000000..ffd22b9063
--- /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, bool )
+{}
+
+} // 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 0000000000..bb847a0a9b
--- /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, bool bOutputForScreen ) 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 0000000000..7a0175183d
--- /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 0000000000..648f234cbd
--- /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 = dynamic_cast<VCLXDevice*>(xRenderDevice.get());
+ 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 0000000000..638749c649
--- /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 0000000000..b01e5c238a
--- /dev/null
+++ b/basctl/source/basicide/baside2.cxx
@@ -0,0 +1,1606 @@
+/* -*- 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 OUString FilterMask_All = u"*.*"_ustr;
+#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 );
+ 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()
+{
+ 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();
+ ErrCodeMsg nError = aMedium.GetErrorIgnoreWarning();
+ 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,
+ FileDialogFlags::NONE, this->GetFrameWeld());
+ aDlg.SetContext(sfx2::FileDialogHelper::BasicExportSource);
+ const Reference<XFilePicker3>& xFP = aDlg.GetFilePicker();
+
+ xFP.queryThrow<XFilePickerControlAccess>()->setValue(ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0, Any(true));
+
+ 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();
+ ErrCodeMsg nError = aMedium.GetErrorIgnoreWarning();
+ 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;
+
+ if (IsReadOnly())
+ aTitle += " (" + IDEResId(RID_STR_READONLY) + ")";
+
+ 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( Scrollable* 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 = 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);
+}
+
+OUString 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::ShowWatchWindow(bool bVisible)
+{
+ aWatchWindow->Show(bVisible);
+ ArrangeWindows();
+}
+
+void ModulWindowLayout::ShowStackWindow(bool bVisible)
+{
+ aStackWindow->Show(bVisible);
+ ArrangeWindows();
+}
+
+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::BASICEDITOR).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 (const auto& vId: vIds)
+ {
+ Color const aColor = aConfig.GetColorValue(vId.eEntry).nColor;
+ Color& rMyColor = aColors[vId.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 0000000000..116dab2bb9
--- /dev/null
+++ b/basctl/source/basicide/baside2.hxx
@@ -0,0 +1,526 @@
+/* -*- 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 <svtools/scrolladaptor.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();
+ sal_uInt16 nCurrentZoomLevel;
+
+ bool bHighlighting;
+ bool bDoSyntaxHighlight;
+ bool bDelayHighlight;
+
+ virtual css::uno::Reference< css::awt::XVclWindowPeer > 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 ();
+
+ void SetEditorZoomLevel(sal_uInt16 nNewZoomLevel);
+ sal_uInt16 GetCurrentZoom() { return nCurrentZoomLevel; }
+
+ 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<ScrollAdaptor> aEWVScrollBar;
+ VclPtr<ScrollAdaptor> aEWHScrollBar;
+
+ virtual void DataChanged(DataChangedEvent const & rDCEvt) override;
+
+ virtual void Resize() override;
+ DECL_LINK(ScrollHdl, weld::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; }
+ ScrollAdaptor& GetEWVScrollBar() { return *aEWVScrollBar; }
+ ScrollAdaptor& GetEWHScrollBar() { return *aEWHScrollBar; }
+
+ 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(Scrollable* 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(); }
+ ScrollAdaptor& GetEditVScrollBar() { return m_aXEditorWindow->GetEWVScrollBar(); }
+ ScrollAdaptor& GetEditHScrollBar() { return m_aXEditorWindow->GetEWHScrollBar(); }
+ 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 OUString 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 ();
+ void ShowWatchWindow(bool bVisible);
+ void ShowStackWindow(bool bVisible);
+ bool IsWatchWindowVisible() { return aWatchWindow->IsVisible(); }
+ bool IsStackWindowVisible() { return aStackWindow->IsVisible(); }
+ 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 0000000000..0cb1316117
--- /dev/null
+++ b/basctl/source/basicide/baside2b.cxx
@@ -0,0 +1,2985 @@
+/* -*- 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 <comphelper/diagnose_ex.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 <cppuhelper/implbase.hxx>
+#include <vector>
+#include <com/sun/star/reflection/theCoreReflection.hpp>
+#include <unotools/charclass.hxx>
+#include "textwindowpeer.hxx"
+#include "uiobject.hxx"
+#include <basegfx/utils/zoomtools.hxx>
+#include <svl/itemset.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_uInt32 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");
+ const Wallpaper aBackground(rModulWindow.GetLayout().GetSyntaxBackgroundColor());
+ SetBackground(aBackground);
+ GetWindow(GetWindowType::Border)->SetBackground(aBackground);
+ 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;
+ }
+
+ // The zoom level applied to the editor window is the zoom slider value in the shell
+ nCurrentZoomLevel = GetShell()->GetCurrentZoomSliderValue();
+
+ 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 ) )
+ {
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+
+ // Check if it is a Ctrl+Wheel zoom command
+ if (pData && pData->IsMod1())
+ {
+ const sal_uInt16 nOldZoom = GetCurrentZoom();
+ sal_uInt16 nNewZoom;
+ if( pData->GetDelta() < 0 )
+ nNewZoom = std::max<sal_uInt16>(basctl::Shell::GetMinZoom(),
+ basegfx::zoomtools::zoomOut(nOldZoom));
+ else
+ nNewZoom = std::min<sal_uInt16>(basctl::Shell::GetMaxZoom(),
+ basegfx::zoomtools::zoomIn(nOldZoom));
+ GetShell()->SetGlobalEditorZoomLevel(nNewZoom);
+ }
+ else
+ HandleScrollCommand(rCEvt, &rModulWindow.GetEditHScrollBar(), &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())
+ {
+ pCodeCompleteWnd->HandleKeyInput(rKEvt);
+ if( rKEvt.GetKeyCode().GetCode() == KEY_UP
+ || rKEvt.GetKeyCode().GetCode() == KEY_DOWN
+ || rKEvt.GetKeyCode().GetCode() == KEY_TAB
+ || rKEvt.GetKeyCode().GetCode() == KEY_POINT)
+ 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 ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_ALPHA ||
+ rKEvt.GetKeyCode().GetGroup() == KEYGROUP_NUM )
+ {
+ // If the module is read-only, warn that it can't be edited
+ if ( rModulWindow.IsReadOnly() )
+ rModulWindow.ShowReadOnlyInfoBar();
+ }
+ 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();
+
+ std::u16string_view sStr = aLine.subView( r.nBegin, r.nEnd - r.nBegin );
+ TextPaM aStart( nLine, r.nBegin );
+ TextPaM aEnd( nLine, r.nBegin + sStr.size() );
+ 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 )
+ {
+ rModulWindow.GetEditVScrollBar().SetThumbPos( pEditView->GetStartDocPos().Y() );
+ rModulWindow.GetEditHScrollBar().SetThumbPos( pEditView->GetStartDocPos().X() );
+ 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 )
+ {
+
+ const tools::Long nWidth = pEditEngine->CalcTextWidth();
+ if ( nWidth != nCurTextWidth )
+ {
+ nCurTextWidth = nWidth;
+ rModulWindow.GetEditHScrollBar().SetRange( Range( 0, nCurTextWidth-1) );
+ rModulWindow.GetEditHScrollBar().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;
+
+ rModulWindow.GetEditVScrollBar().SetRange( Range( 0, pEditEngine->GetTextHeight()-1 ) );
+ rModulWindow.GetEditHScrollBar().SetRange( Range( 0, nCurTextWidth-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();
+
+ rModulWindow.GetEditHScrollBar().SetVisibleSize(aOutSz.Width());
+ rModulWindow.GetEditHScrollBar().SetPageSize(aOutSz.Width() * 8 / 10);
+ rModulWindow.GetEditHScrollBar().SetLineSize(GetTextWidth( "x" ));
+ rModulWindow.GetEditHScrollBar().SetThumbPos(pEditView->GetStartDocPos().X());
+ rModulWindow.GetEditHScrollBar().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()
+{
+ // Get default font name and height defined in the Options dialog
+ 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();
+ }
+ sal_uInt16 nDefaultFontHeight = officecfg::Office::Common::Font::SourceViewFont::FontHeight::get();
+
+ // Calculate font size considering zoom level
+ sal_uInt16 nNewFontHeight = nDefaultFontHeight * (static_cast<float>(nCurrentZoomLevel) / 100);
+ Size aFontSize(0, nNewFontHeight);
+
+ 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);
+ rModulWindow.Invalidate();
+
+ if (pEditEngine)
+ {
+ bool const bModified = pEditEngine->IsModified();
+ pEditEngine->SetFont(aFont);
+ pEditEngine->SetModified(bModified);
+ }
+
+ // Update controls
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate( SID_BASICIDE_CURRENT_ZOOM );
+ pBindings->Invalidate( SID_ATTR_ZOOMSLIDER );
+ }
+}
+
+void EditorWindow::SetEditorZoomLevel(sal_uInt16 nNewZoomLevel)
+{
+ if (nCurrentZoomLevel == nNewZoomLevel)
+ return;
+
+ if (nNewZoomLevel < MIN_ZOOM_LEVEL || nNewZoomLevel > MAX_ZOOM_LEVEL)
+ return;
+
+ nCurrentZoomLevel = nNewZoomLevel;
+ ImplSetFont();
+}
+
+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 ? RID_BMP_ERRORMARKER : 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 );
+
+ tools::Long 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_uInt16>(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);
+ OUString 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");
+ OUString 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<ScrollAdaptor>::Create(this, false)),
+ aEWHScrollBar(VclPtr<ScrollAdaptor>::Create(this, true))
+{
+ aEdtWindow->Show();
+ aBrkWindow->Show();
+
+ aEWVScrollBar->SetLineSize(nScrollLine);
+ aEWVScrollBar->SetPageSize(nScrollPage);
+ aEWVScrollBar->SetScrollHdl( LINK( this, ComplexEditorWindow, ScrollHdl ) );
+ aEWVScrollBar->Show();
+
+ aEWHScrollBar->SetLineSize(nScrollLine);
+ aEWHScrollBar->SetPageSize(nScrollPage);
+ aEWHScrollBar->SetScrollHdl( LINK( this, ComplexEditorWindow, ScrollHdl ) );
+ aEWHScrollBar->Show();
+}
+
+ComplexEditorWindow::~ComplexEditorWindow()
+{
+ disposeOnce();
+}
+
+void ComplexEditorWindow::dispose()
+{
+ aBrkWindow.disposeAndClear();
+ aLineNumberWindow.disposeAndClear();
+ aEdtWindow.disposeAndClear();
+ aEWVScrollBar.disposeAndClear();
+ aEWHScrollBar.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();
+ tools::Long nSBHeight = aEWHScrollBar->GetSizePixel().Height();
+
+ Size aBrkSz(nBrkWidth, aSz.Height() - nSBHeight);
+
+ if (aLineNumberWindow->IsVisible())
+ {
+ Size aLnSz(aLineNumberWindow->GetWidth(), aSz.Height() - nSBHeight);
+ Size aEWSz(aSz.Width() - nBrkWidth - aLineNumberWindow->GetWidth() - nSBWidth, aSz.Height() - nSBHeight);
+ aBrkWindow->SetPosSizePixel(Point(DWBORDER, DWBORDER), aBrkSz);
+ aLineNumberWindow->SetPosSizePixel(Point(DWBORDER + nBrkWidth, DWBORDER), aLnSz);
+ aEdtWindow->SetPosSizePixel(Point(DWBORDER + nBrkWidth + aLnSz.Width(), DWBORDER), aEWSz);
+ }
+ else
+ {
+ Size aEWSz(aSz.Width() - nBrkWidth - nSBWidth, aSz.Height() - nSBHeight);
+ aBrkWindow->SetPosSizePixel( Point( DWBORDER, DWBORDER ), aBrkSz );
+ aEdtWindow->SetPosSizePixel(Point(DWBORDER + nBrkWidth, DWBORDER), aEWSz);
+ }
+
+ aEWVScrollBar->SetPosSizePixel(Point(aOutSz.Width() - DWBORDER - nSBWidth, DWBORDER),
+ Size(nSBWidth, aSz.Height() - nSBHeight));
+ aEWHScrollBar->SetPosSizePixel(Point(DWBORDER, aOutSz.Height() - DWBORDER - nSBHeight),
+ Size(aSz.Width() - nSBWidth, nSBHeight));
+}
+
+IMPL_LINK_NOARG(ComplexEditorWindow, ScrollHdl, weld::Scrollbar&, void)
+{
+ if (aEdtWindow->GetEditView())
+ {
+ tools::Long nXDiff = aEdtWindow->GetEditView()->GetStartDocPos().X() - aEWHScrollBar->GetThumbPos();
+ tools::Long nYDiff = aEdtWindow->GetEditView()->GetStartDocPos().Y() - aEWVScrollBar->GetThumbPos();
+ aEdtWindow->GetEditView()->Scroll(nXDiff, nYDiff);
+ aBrkWindow->DoScroll( nYDiff );
+ aLineNumberWindow->DoScroll( nYDiff );
+ aEdtWindow->GetEditView()->ShowCursor(false);
+ aEWVScrollBar->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::XVclWindowPeer >
+EditorWindow::GetComponentInterface(bool bCreate)
+{
+ uno::Reference< awt::XVclWindowPeer > 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 0000000000..4a6b1dfbfb
--- /dev/null
+++ b/basctl/source/basicide/baside3.cxx
@@ -0,0 +1,1325 @@
+/* -*- 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 <comphelper/diagnose_ex.hxx>
+#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
+constexpr OUString FilterMask_All = u"*.*"_ustr;
+#else
+constexpr OUString FilterMask_All = u"*"_ustr;
+#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()
+{
+ m_pEditor->SetScrollBars( GetHScrollBar(), GetVScrollBar() );
+}
+
+void DialogWindow::DoScroll( Scrollable* )
+{
+ 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()
+{
+ sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION,
+ FileDialogFlags::NONE, this->GetFrameWeld());
+ aDlg.SetContext(sfx2::FileDialogHelper::BasicExportDialog);
+ Reference<XFilePicker3> xFP = aDlg.GetFilePicker();
+
+ xFP.queryThrow<XFilePickerControlAccess>()->setValue(ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0, Any(true));
+ 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;
+
+ OUString aSelectedFileURL = xFP->getSelectedFiles()[0];
+
+ Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
+ Reference< XSimpleFileAccess3 > xSFI( SimpleFileAccess::create(xContext) );
+
+ Reference< XOutputStream > xOutput;
+ try
+ {
+ if( xSFI->exists(aSelectedFileURL) )
+ xSFI->kill(aSelectedFileURL);
+ xOutput = xSFI->openFileWrite(aSelectedFileURL);
+ }
+ catch(const Exception& )
+ {}
+
+ if (!xOutput)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_COULDNTWRITE)));
+ xBox->run();
+ return;
+ }
+
+ // export dialog model to xml
+ auto xInput(xmlscript::exportDialogModel(GetDialog(), xContext, GetDocument().getDocumentOrNull())->createInputStream());
+
+ for (Sequence<sal_Int8> bytes; xInput->readBytes(bytes, xInput->available());)
+ xOutput->writeBytes(bytes);
+
+ // With resource?
+ Reference< resource::XStringResourceResolver > xStringResourceResolver;
+ if (auto xDialogModelPropSet = GetDialog().query<beans::XPropertySet>())
+ {
+ try
+ {
+ Any aResourceResolver = xDialogModelPropSet->getPropertyValue( "ResourceResolver" );
+ aResourceResolver >>= xStringResourceResolver;
+ }
+ catch(const beans::UnknownPropertyException& )
+ {}
+ }
+
+ Sequence<lang::Locale> aLocaleSeq;
+ if (xStringResourceResolver)
+ aLocaleSeq = xStringResourceResolver->getLocales();
+ if (aLocaleSeq.hasElements())
+ {
+ INetURLObject aURLObj(aSelectedFileURL);
+ 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 + "_" ;
+ for( const OUString& rCompleteName : aContentSeq )
+ {
+ OUString aPureName;
+ OUString aExtension;
+ sal_Int32 iDot = rCompleteName.lastIndexOf( '.' );
+ if( iDot != -1 )
+ {
+ sal_Int32 iSlash = rCompleteName.lastIndexOf( '/' );
+ sal_Int32 iCopyFrom = (iSlash != -1) ? iSlash + 1 : 0;
+ aPureName = rCompleteName.copy( iCopyFrom, iDot-iCopyFrom );
+ aExtension = rCompleteName.copy( iDot + 1 );
+ }
+
+ if( aExtension == "properties" || aExtension == "default" )
+ {
+ if( aPureName.startsWith( aDialogName_ ) )
+ {
+ try
+ {
+ xSFI->kill( rCompleteName );
+ }
+ catch(const uno::Exception& )
+ {}
+ }
+ }
+ }
+ }
+
+ Reference< XStringResourceWithLocation > xStringResourceWithLocation =
+ StringResourceWithLocation::create( xContext, aURL, false/*bReadOnly*/,
+ xStringResourceResolver->getDefaultLocale(), aDialogName, aComment, xDummyHandler );
+
+ // Add locales
+ for( const lang::Locale& rLocale : aLocaleSeq )
+ {
+ xStringResourceWithLocation->newLocale( rLocale );
+ }
+
+ LocalizationMgr::copyResourceForDialog( GetDialog(),
+ xStringResourceResolver, xStringResourceWithLocation );
+
+ xStringResourceWithLocation->store();
+ }
+}
+
+static std::vector< lang::Locale > implGetLanguagesOnlyContainedInFirstSeq
+ ( const Sequence< lang::Locale >& aFirstSeq, const Sequence< lang::Locale >& aSecondSeq )
+{
+ std::vector< lang::Locale > avRet;
+
+ std::copy_if(aFirstSeq.begin(), aFirstSeq.end(),
+ std::back_inserter(avRet),
+ [&aSecondSeq](const lang::Locale& rFirstLocale) {
+ return std::none_of(
+ aSecondSeq.begin(), aSecondSeq.end(),
+ [&rFirstLocale](const lang::Locale& rSecondLocale) {
+ return localesAreEqual(rFirstLocale, rSecondLocale);
+ });
+ });
+ 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();
+
+ 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();
+
+ if (std::any_of(aOnlyInImportLanguages.begin(), aOnlyInImportLanguages.end(),
+ [&aImportDefaultLocale](const lang::Locale& aTmpLocale) {
+ return localesAreEqual(aImportDefaultLocale, aTmpLocale);
+ }))
+ {
+ aFirstLocale = aImportDefaultLocale;
+ }
+ }
+
+ pCurMgr->handleAddLocales( {aFirstLocale} );
+
+ if( nOnlyInImportLanguageCount > 1 )
+ {
+ Sequence< lang::Locale > aRemainingLocaleSeq( nOnlyInImportLanguageCount - 1 );
+ auto pRemainingLocaleSeq = aRemainingLocaleSeq.getArray();
+ int iSeq = 0;
+ for( const lang::Locale& rLocale : aOnlyInImportLanguages )
+ {
+ if( !localesAreEqual( aFirstLocale, rLocale ) )
+ pRemainingLocaleSeq[iSeq++] = rLocale;
+ }
+ 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.GetFaceColor());
+}
+
+css::uno::Reference< css::accessibility::XAccessible > DialogWindow::CreateAccessible()
+{
+ return new AccessibleDialogWindow(this);
+}
+
+OUString 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 0000000000..849bff30cb
--- /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 0000000000..9ef9f75e3f
--- /dev/null
+++ b/basctl/source/basicide/basides1.cxx
@@ -0,0 +1,1551 @@
+/* -*- 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>
+#include <svx/zoomsliderctrl.hxx>
+#include <svx/zoomslideritem.hxx>
+#include <basegfx/utils/zoomtools.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;
+
+static void lcl_InvalidateZoomSlots(SfxBindings* pBindings)
+{
+ if (!pBindings)
+ return;
+
+ static sal_uInt16 const aInval[] = {
+ SID_ZOOM_OUT, SID_ZOOM_IN, SID_ATTR_ZOOMSLIDER, 0
+ };
+ pBindings->Invalidate(aInval);
+}
+
+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& rViewFrame = GetViewFrame();
+ SfxChildWindow* pChildWin = rViewFrame.GetChildWindow(SID_SEARCH_DLG);
+ 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(), nullptr, rTabId.GetValue());
+ }
+ else
+ Organize(rReq.GetFrameWeld(), nullptr, 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& rViewFrame = GetViewFrame();
+ rViewFrame.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_WATCH:
+ {
+ // Toggling the watch window can only be done from a ModulWindow
+ if (!dynamic_cast<ModulWindowLayout*>(pLayout.get()))
+ return;
+
+ pModulLayout->ShowWatchWindow(!pModulLayout->IsWatchWindowVisible());
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate(SID_BASICIDE_WATCH);
+ }
+ break;
+
+ case SID_BASICIDE_STACK:
+ {
+ // Toggling the stack window can only be done from a ModulWindow
+ if (!dynamic_cast<ModulWindowLayout*>(pLayout.get()))
+ return;
+
+ pModulLayout->ShowStackWindow(!pModulLayout->IsStackWindowVisible());
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate(SID_BASICIDE_STACK);
+ }
+ 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;
+
+ case SID_ATTR_ZOOMSLIDER:
+ {
+ const SfxItemSet *pArgs = rReq.GetArgs();
+ const SfxPoolItem* pItem;
+
+ if (pArgs && pArgs->GetItemState(SID_ATTR_ZOOMSLIDER, true, &pItem ) == SfxItemState::SET)
+ SetGlobalEditorZoomLevel(static_cast<const SvxZoomSliderItem*>(pItem)->GetValue());
+
+ lcl_InvalidateZoomSlots(GetBindingsPtr());
+ }
+ break;
+
+ case SID_ZOOM_IN:
+ case SID_ZOOM_OUT:
+ {
+ const sal_uInt16 nOldZoom = GetCurrentZoomSliderValue();
+ sal_uInt16 nNewZoom;
+ if (nSlot == SID_ZOOM_IN)
+ nNewZoom = std::min<sal_uInt16>(GetMaxZoom(), basegfx::zoomtools::zoomIn(nOldZoom));
+ else
+ nNewZoom = std::max<sal_uInt16>(GetMinZoom(), basegfx::zoomtools::zoomOut(nOldZoom));
+ SetGlobalEditorZoomLevel(nNewZoom);
+ lcl_InvalidateZoomSlots(GetBindingsPtr());
+ }
+ 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_WATCH:
+ {
+ if (pLayout)
+ {
+ rSet.Put(SfxBoolItem(nWh, pModulLayout->IsWatchWindowVisible()));
+ // Disable command if the visible window is not a ModulWindow
+ if (!dynamic_cast<ModulWindowLayout*>(pLayout.get()))
+ rSet.DisableItem(nWh);
+ }
+ else
+ rSet.Put(SfxVisibilityItem(nWh, false));
+ }
+ break;
+
+ case SID_BASICIDE_STACK:
+ {
+ if (pLayout)
+ {
+ rSet.Put(SfxBoolItem(nWh, pModulLayout->IsStackWindowVisible()));
+ // Disable command if the visible window is not a ModulWindow
+ if (!dynamic_cast<ModulWindowLayout*>(pLayout.get()))
+ rSet.DisableItem(nWh);
+ }
+ 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();
+ if (pCurWin->IsReadOnly())
+ aTitle += " (" + IDEResId(RID_STR_READONLY) + ")";
+ SfxStringItem aItem( SID_BASICIDE_STAT_TITLE, aTitle );
+ rSet.Put( aItem );
+ }
+ }
+ break;
+ case SID_BASICIDE_CURRENT_ZOOM:
+ {
+ // The current zoom value is only visible in a module window
+ ModulWindow* pModuleWindow = dynamic_cast<ModulWindow*>(pCurWin.get());
+ if (pModuleWindow)
+ {
+ OUString sZoom;
+ sZoom = OUString::number(m_nCurrentZoomSliderValue) + "%";
+ SfxStringItem aItem( SID_BASICIDE_CURRENT_ZOOM, sZoom );
+ 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;
+
+ case SID_ZOOM_IN:
+ case SID_ZOOM_OUT:
+ {
+ const sal_uInt16 nCurrentZoom = GetCurrentZoomSliderValue();
+ if ((nWh == SID_ZOOM_IN && nCurrentZoom >= GetMaxZoom()) ||
+ (nWh == SID_ZOOM_OUT && nCurrentZoom <= GetMinZoom()))
+ rSet.DisableItem(nWh);
+ }
+ break;
+
+ case SID_ATTR_ZOOMSLIDER:
+ {
+ // The zoom slider is only visible in a module window
+ ModulWindow* pModuleWindow = dynamic_cast<ModulWindow*>(pCurWin.get());
+ if (pModuleWindow)
+ {
+ SvxZoomSliderItem aZoomSliderItem(GetCurrentZoomSliderValue(), GetMinZoom(), GetMaxZoom());
+ aZoomSliderItem.AddSnappingPoint(100);
+ rSet.Put( aZoomSliderItem );
+ }
+ }
+ 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();
+
+ if ( m_pCurLocalizationMgr )
+ m_pCurLocalizationMgr->handleTranslationbar();
+
+ ManageToolbars();
+
+ // fade out (in) property browser in module (dialog) windows
+ UIFeatureChanged();
+}
+
+void Shell::ManageToolbars()
+{
+ static constexpr OUString aMacroBarResName = u"private:resource/toolbar/macrobar"_ustr;
+ static constexpr OUString aDialogBarResName = u"private:resource/toolbar/dialogbar"_ustr;
+ static constexpr OUString aInsertControlsBarResName
+ = u"private:resource/toolbar/insertcontrolsbar"_ustr;
+ static constexpr OUString aFormControlsBarResName
+ = u"private:resource/toolbar/formcontrolsbar"_ustr;
+
+ 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 );
+ auto nScrollBarSz(Application::GetSettings().GetStyleSettings().GetScrollBarSize());
+ aSz.AdjustHeight(-aTabBarSize.Height());
+
+ Size aOutSz( aSz );
+ aSz.AdjustWidth(-nScrollBarSz);
+ aSz.AdjustHeight(-nScrollBarSz);
+ aVScrollBar->SetPosSizePixel( Point( rPos.X()+aSz.Width(), rPos.Y() ), Size( nScrollBarSz, aSz.Height() ) );
+ aHScrollBar->SetPosSizePixel( Point( rPos.X(), rPos.Y()+aSz.Height() ), Size( aOutSz.Width(), nScrollBarSz ) );
+ pTabBar->SetPosSizePixel( Point( rPos.X(), rPos.Y() + nScrollBarSz + aSz.Height()), aTabBarSize );
+
+ // The size to be applied depends on whether it is a DialogWindow or a ModulWindow
+ if (pLayout)
+ {
+ if (dynamic_cast<DialogWindow*>(pCurWin.get()))
+ {
+ pCurWin->ShowShellScrollBars();
+ pLayout->SetPosSizePixel(rPos, aSz);
+ }
+ else
+ {
+ pCurWin->ShowShellScrollBars(false);
+ pLayout->SetPosSizePixel(rPos, 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 0000000000..5bd69b76f3
--- /dev/null
+++ b/basctl/source/basicide/basides2.cxx
@@ -0,0 +1,239 @@
+/* -*- 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& rViewFrame = GetViewFrame();
+ SfxObjectShell* pShell = rViewFrame.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 0000000000..44bc54ba62
--- /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 <comphelper/diagnose_ex.hxx>
+#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 0000000000..d23da94d26
--- /dev/null
+++ b/basctl/source/basicide/basidesh.cxx
@@ -0,0 +1,994 @@
+/* -*- 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 <comphelper/diagnose_ex.hxx>
+#include <basic/basmgr.hxx>
+#include <svx/zoomsliderctrl.hxx>
+#include <svx/zoomslideritem.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>
+#include <unotools/viewoptions.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
+{
+constexpr OUString BASIC_IDE_EDITOR_WINDOW = u"BasicIDEEditorWindow"_ustr;
+constexpr OUString BASIC_IDE_CURRENT_ZOOM = u"CurrentZoom"_ustr;
+
+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& rFrame_, SfxViewShell* /* pOldShell */ ) :
+ SfxViewShell( rFrame_, SfxViewShellFlags::NO_NEWWINDOW ),
+ m_aCurDocument( ScriptDocument::getApplicationScriptDocument() ),
+ aHScrollBar( VclPtr<ScrollAdaptor>::Create(&GetViewFrame().GetWindow(), true) ),
+ aVScrollBar( VclPtr<ScrollAdaptor>::Create(&GetViewFrame().GetWindow(), false) ),
+ 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 );
+ SvxZoomSliderControl::RegisterControl( SID_ATTR_ZOOMSLIDER );
+
+ 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();
+ InitZoomLevel();
+
+ 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();
+ 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();
+
+ // Remember current zoom level
+ SvtViewOptions(EViewType::Window, BASIC_IDE_EDITOR_WINDOW).SetUserItem(
+ BASIC_IDE_CURRENT_ZOOM, Any(m_nCurrentZoomSliderValue));
+}
+
+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::InitZoomLevel()
+{
+ m_nCurrentZoomSliderValue = DEFAULT_ZOOM_LEVEL;
+ SvtViewOptions aWinOpt(EViewType::Window, BASIC_IDE_EDITOR_WINDOW);
+ if (aWinOpt.Exists())
+ {
+ try
+ {
+ aWinOpt.GetUserItem(BASIC_IDE_CURRENT_ZOOM) >>= m_nCurrentZoomSliderValue;
+ }
+ catch(const css::container::NoSuchElementException&)
+ { TOOLS_WARN_EXCEPTION("basctl.basicide", "Zoom level not defined"); }
+ }
+}
+
+// Applies the new zoom level to all open editor windows
+void Shell::SetGlobalEditorZoomLevel(sal_uInt16 nNewZoomLevel)
+{
+ for (auto const& window : aWindowTable)
+ {
+ ModulWindow* pModuleWindow = dynamic_cast<ModulWindow*>(window.second.get());
+ if (pModuleWindow)
+ {
+ EditorWindow& pEditorWindow = pModuleWindow->GetEditorWindow();
+ pEditorWindow.SetEditorZoomLevel(nNewZoomLevel);
+ }
+ }
+
+ // Update the zoom slider value based on the new global zoom level
+ m_nCurrentZoomSliderValue = nNewZoomLevel;
+
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ {
+ pBindings->Invalidate( SID_BASICIDE_CURRENT_ZOOM );
+ pBindings->Invalidate( SID_ATTR_ZOOMSLIDER );
+ }
+}
+
+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 );
+}
+
+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;
+ // stores the total number of modules and dialogs visible
+ sal_uInt16 nTotalTabs = 0;
+
+ 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();
+ nTotalTabs += nModCount;
+
+ 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();
+ nTotalTabs += nDlgCount;
+
+ 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 ( nTotalTabs == 0 )
+ {
+ // If no tabs are opened, create a generic module and make it visible
+ pNextActiveWindow = CreateBasWin( m_aCurDocument, m_aCurLibName, OUString() );
+ }
+ else 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::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 0000000000..708b1ce035
--- /dev/null
+++ b/basctl/source/basicide/basobj2.cxx
@@ -0,0 +1,441 @@
+/* -*- 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 <comphelper/diagnose_ex.hxx>
+#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, void* pDocFrame_AsXFrame, sal_Int16 nTabId)
+ {
+ SAL_INFO("basctl.basicide","in basicide_macro_organizer");
+ Reference< frame::XFrame > aDocFrame( static_cast< frame::XFrame* >( pDocFrame_AsXFrame ) );
+ basctl::Organize(static_cast<weld::Window*>(pParent), aDocFrame, nTabId);
+ }
+}
+
+void Organize(weld::Window* pParent, const css::uno::Reference<css::frame::XFrame>& xDocFrame, sal_Int16 tabId)
+{
+ EnsureIde();
+
+ auto xDlg(std::make_shared<OrganizeDialog>(pParent, xDocFrame, tabId));
+ weld::DialogController::runAsync(xDlg, [](int) {});
+}
+
+bool IsValidSbxName( std::u16string_view rName )
+{
+ for ( size_t nChar = 0; nChar < rName.size(); 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 0000000000..4672cdd52c
--- /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 );
+ }
+
+ aOUSource += "Sub " + aMacroName + "\n\nEnd Sub";
+
+ // 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())
+ {
+ SfxViewFrame& rViewFrame = pShell->GetViewFrame();
+ if (SfxDispatcher* pDispatcher = rViewFrame.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 0000000000..18ca75e01b
--- /dev/null
+++ b/basctl/source/basicide/bastype2.cxx
@@ -0,0 +1,865 @@
+/* -*- 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 <comphelper/diagnose_ex.hxx>
+#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 <svl/itemset.hxx>
+
+#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 ? RID_BMP_DLGLIB : RID_BMP_DLGLIBNOTLOADED;
+ else
+ sId = bLoaded ? RID_BMP_MODLIB : 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 0000000000..d26ae83252
--- /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 ? RID_BMP_DLGLIB : 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 0000000000..e436bc9f7e
--- /dev/null
+++ b/basctl/source/basicide/bastypes.cxx
@@ -0,0 +1,831 @@
+/* -*- 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/infobar.hxx>
+#include <sfx2/passwd.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/srchdefs.hxx>
+#include <svl/itemset.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
+{
+
+// ID used for the read-only infobar
+constexpr OUString BASIC_IDE_READONLY_INFOBAR = u"readonly"_ustr;
+
+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->isDisposed())
+ pShellVScrollBar->SetScrollHdl( Link<weld::Scrollbar&,void>() );
+ if (pShellHScrollBar && !pShellHScrollBar->isDisposed())
+ pShellHScrollBar->SetScrollHdl( Link<weld::Scrollbar&,void>() );
+ pShellVScrollBar.clear();
+ pShellHScrollBar.clear();
+ vcl::Window::dispose();
+}
+
+void BaseWindow::Init()
+{
+ if ( pShellVScrollBar )
+ pShellVScrollBar->SetScrollHdl( LINK( this, BaseWindow, VertScrollHdl ) );
+ if ( pShellHScrollBar )
+ pShellHScrollBar->SetScrollHdl( LINK( this, BaseWindow, HorzScrollHdl ) );
+
+ // Show the read-only infobar if the module/dialog is read-only
+ GetShell()->GetViewFrame().RemoveInfoBar(BASIC_IDE_READONLY_INFOBAR);
+ if (IsReadOnly())
+ ShowReadOnlyInfoBar();
+
+ DoInit(); // virtual...
+}
+
+void BaseWindow::DoInit()
+{
+}
+
+void BaseWindow::GrabScrollBars(ScrollAdaptor* pHScroll, ScrollAdaptor* pVScroll)
+{
+ pShellHScrollBar = pHScroll;
+ pShellVScrollBar = pVScroll;
+}
+
+IMPL_LINK_NOARG(BaseWindow, VertScrollHdl, weld::Scrollbar&, void)
+{
+ DoScroll(pShellVScrollBar);
+}
+
+IMPL_LINK_NOARG(BaseWindow, HorzScrollHdl, weld::Scrollbar&, void)
+{
+ DoScroll(pShellHScrollBar);
+}
+
+void BaseWindow::ExecuteCommand (SfxRequest&)
+{
+}
+
+void BaseWindow::ExecuteGlobal (SfxRequest&)
+{
+}
+
+bool BaseWindow::EventNotify( NotifyEvent& rNEvt )
+{
+ bool bDone = false;
+
+ if ( rNEvt.GetType() == NotifyEventType::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::ShowShellScrollBars(bool bVisible)
+{
+ if (bVisible)
+ {
+ if (pShellHScrollBar)
+ {
+ pShellHScrollBar->Enable();
+ pShellHScrollBar->Show();
+ }
+ if (pShellVScrollBar)
+ {
+ pShellVScrollBar->Enable();
+ pShellVScrollBar->Show();
+ }
+ }
+ else
+ {
+ if (pShellHScrollBar)
+ {
+ pShellHScrollBar->Disable();
+ pShellHScrollBar->Hide();
+ }
+ if (pShellVScrollBar)
+ {
+ pShellVScrollBar->Disable();
+ pShellVScrollBar->Hide();
+ }
+ }
+}
+
+void BaseWindow::DoScroll( Scrollable* )
+{
+}
+
+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;
+}
+
+// Show the read-only warning messages for module and dialog windows
+void BaseWindow::ShowReadOnlyInfoBar()
+{
+ OUString aMsg;
+ if (dynamic_cast<ModulWindow*>(this))
+ aMsg = IDEResId(RID_STR_MODULE_READONLY);
+ else
+ aMsg = IDEResId(RID_STR_DIALOG_READONLY);
+
+ GetShell()->GetViewFrame().AppendInfoBar(BASIC_IDE_READONLY_INFOBAR, OUString(),
+ aMsg, InfobarType::INFO, true);
+}
+
+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 OUString& 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++;
+
+ rStr = OUString::Concat(rStr.subView( 0, nStartPos )) + rStr.subView( nEndPos );
+
+ // 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 )
+ {
+ rStr = OUString::Concat(rStr.subView( 0, nStartPos )) + rStr.subView( n );
+ }
+ }
+}
+
+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 0000000000..0d0347ace2
--- /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 0000000000..324564aaa7
--- /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 0000000000..f39255371b
--- /dev/null
+++ b/basctl/source/basicide/brkdlg.cxx
@@ -0,0 +1,231 @@
+/* -*- 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>
+#include <svl/itemset.hxx>
+
+namespace basctl
+{
+namespace
+{
+bool lcl_ParseText(OUString const& rText, size_t& rLineNr)
+{
+ // aText should look like "# n" where n > 0
+ // 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);
+ 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 0000000000..89406d2c0c
--- /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 0000000000..254c719bb5
--- /dev/null
+++ b/basctl/source/basicide/doceventnotifier.cxx
@@ -0,0 +1,250 @@
+/* -*- 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 <comphelper/compbase.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/processfactory.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 ::comphelper::WeakComponentImplHelper< XDocumentEventListener
+ > DocumentEventNotifier_Impl_Base;
+
+ namespace {
+
+ enum ListenerAction
+ {
+ RegisterListener,
+ RemoveListener
+ };
+
+ }
+
+ /** impl class for DocumentEventNotifier
+ */
+ class DocumentEventNotifier::Impl : 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;
+
+ // WeakComponentImplHelper
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ private:
+ /// determines whether the instance is already disposed
+ bool impl_isDisposed_nothrow(std::unique_lock<std::mutex>& /*rGuard*/) const { return m_pListener == nullptr; }
+
+ /// disposes the instance
+ void impl_dispose_nothrow(std::unique_lock<std::mutex>& rGuard);
+
+ /// registers or revokes the instance as listener at the global event broadcaster
+ void impl_listenerAction_nothrow( std::unique_lock<std::mutex>& rGuard, ListenerAction _eAction );
+
+ private:
+ DocumentEventListener* m_pListener;
+ Reference< XModel > m_xModel;
+ };
+
+ DocumentEventNotifier::Impl::Impl (DocumentEventListener& rListener, Reference<XModel> const& rxDocument) :
+ m_pListener(&rListener),
+ m_xModel(rxDocument)
+ {
+ std::unique_lock aGuard(m_aMutex);
+ osl_atomic_increment( &m_refCount );
+ impl_listenerAction_nothrow( aGuard, RegisterListener );
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ DocumentEventNotifier::Impl::~Impl ()
+ {
+ std::unique_lock aGuard(m_aMutex);
+ if ( !impl_isDisposed_nothrow(aGuard) )
+ {
+ acquire();
+ dispose();
+ }
+ }
+
+ void SAL_CALL DocumentEventNotifier::Impl::documentEventOccured( const DocumentEvent& _rEvent )
+ {
+ std::unique_lock aGuard( m_aMutex );
+
+ OSL_PRECOND( !impl_isDisposed_nothrow(aGuard), "DocumentEventNotifier::Impl::notifyEvent: disposed, but still getting events?" );
+ if ( impl_isDisposed_nothrow(aGuard) )
+ 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;
+
+ // Listener implementations require that we hold the mutex, but to avoid lock ordering issues,
+ // we need to take the solar mutex before we take our own mutex.
+ aGuard.unlock();
+
+ // Listener implements require that we hold the solar mutex.
+ SolarMutexGuard aSolarGuard;
+
+ // Take the lock again, so we can check our local fields.
+ aGuard.lock();
+ if ( impl_isDisposed_nothrow(aGuard) )
+ // somebody took the chance to dispose us -> bail out
+ return;
+ DocumentEventListener* pListener = m_pListener;
+ ScriptDocument aDocument( xDocument );
+ // We cannot call the listener while holding our mutex because the listener
+ // call might trigger an event which call back into us.
+ aGuard.unlock();
+
+ (pListener->*aEvent.listenerMethod)( aDocument );
+
+ break;
+ }
+ }
+
+ void SAL_CALL DocumentEventNotifier::Impl::disposing( const css::lang::EventObject& /*Event*/ )
+ {
+ SolarMutexGuard aSolarGuard;
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( !impl_isDisposed_nothrow(aGuard) )
+ impl_dispose_nothrow(aGuard);
+ }
+
+ void DocumentEventNotifier::Impl::disposing(std::unique_lock<std::mutex>& rGuard)
+ {
+ impl_listenerAction_nothrow( rGuard, RemoveListener );
+ impl_dispose_nothrow(rGuard);
+ }
+
+ void DocumentEventNotifier::Impl::impl_dispose_nothrow(std::unique_lock<std::mutex>& /*rGuard*/)
+ {
+ m_pListener = nullptr;
+ m_xModel.clear();
+ }
+
+ void DocumentEventNotifier::Impl::impl_listenerAction_nothrow( std::unique_lock<std::mutex>& rGuard, 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;
+
+ rGuard.unlock();
+ (xBroadcaster.get()->*listenerAction)( this );
+ rGuard.lock();
+ }
+ 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 0000000000..08d7a1ab9c
--- /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 0000000000..d71e02139e
--- /dev/null
+++ b/basctl/source/basicide/documentenumeration.cxx
@@ -0,0 +1,157 @@
+/* -*- 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 <comphelper/diagnose_ex.hxx>
+
+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
+ DocumentEnumeration::DocumentEnumeration( Reference< css::uno::XComponentContext > const & _rContext, const IDocumentDescriptorFilter* _pFilter )
+ : m_xContext( _rContext )
+ , m_pFilter( _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_xContext );
+ 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_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 0000000000..dfd4d2e817
--- /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() {}
+ };
+
+
+ /** 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:
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ const IDocumentDescriptorFilter* m_pFilter;
+ };
+
+
+} // 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 0000000000..022045050e
--- /dev/null
+++ b/basctl/source/basicide/iderdll.cxx
@@ -0,0 +1,205 @@
+/* -*- 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 () :
+ 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 0000000000..99534119f8
--- /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 0000000000..e6b6676ed6
--- /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 0000000000..18420199e2
--- /dev/null
+++ b/basctl/source/basicide/linenumberwindow.cxx
@@ -0,0 +1,135 @@
+/* -*- 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)
+{
+ const Wallpaper aBackground(GetSettings().GetStyleSettings().GetWindowColor());
+ SetBackground(aBackground);
+ GetWindow(GetWindowType::Border)->SetBackground(aBackground);
+ 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;
+
+ 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)
+ {
+ const OUString aLineNumber = OUString::number(n);
+ // tdf#153798 - align line numbers to the right
+ rRenderContext.DrawText(
+ Point(m_nWidth - GetTextWidth(aLineNumber) - m_nBaseWidth / 2, y - m_nCurYOffset),
+ aLineNumber);
+ }
+
+ // Resize the parent after calculating the new width and height values
+ GetParent()->Resize();
+}
+
+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 0000000000..a2e457f711
--- /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 0000000000..68d2f63622
--- /dev/null
+++ b/basctl/source/basicide/localizationmgr.cxx
@@ -0,0 +1,1100 @@
+/* -*- 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>
+#include <o3tl/string_view.hxx>
+
+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 OUString aDot(u"."_ustr);
+constexpr OUString aEsc(u"&"_ustr);
+constexpr OUString aSemi(u";"_ustr);
+
+} // 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 OUString aToolBarResName = u"private:resource/toolbar/translationbar"_ustr;
+
+ 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( std::u16string_view 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 (o3tl::equalsAscii(aName, std::string_view(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
+ for(const auto& rCtrlName : xDialogModel->getElementNames()) {
+ Any aCtrl = xDialogModel->getByName( rCtrlName );
+ implHandleControlResourceProperties( aCtrl, aDlgName,
+ rCtrlName, 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
+ for(const auto& rCtrlName : xDialogModel->getElementNames()) {
+ Any aCtrl = xDialogModel->getByName( rCtrlName );
+ implHandleControlResourceProperties( aCtrl, aDlgName,
+ rCtrlName, 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
+ for(const auto& rCtrlName : xDialogModel->getElementNames()){
+ Any aCtrl = xDialogModel->getByName( rCtrlName );
+ implHandleControlResourceProperties( aCtrl, aDummyName,
+ rCtrlName, 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
+ for(const auto& rCtrlName : xDialogModel->getElementNames()) {
+ Any aCtrl = xDialogModel->getByName( rCtrlName );
+ implHandleControlResourceProperties( aCtrl, aDummyName,
+ rCtrlName, 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
+ for(const auto& rCtrlName : xDialogModel->getElementNames()) {
+ Any aCtrl = xDialogModel->getByName( rCtrlName );
+ implHandleControlResourceProperties( aCtrl, aDialogName,
+ rCtrlName, 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
+ for(const auto& rCtrlName : xDialogModel->getElementNames()) {
+ Any aCtrl = xDialogModel->getByName( rCtrlName );
+ 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 0000000000..6b4afb79f7
--- /dev/null
+++ b/basctl/source/basicide/macrodlg.cxx
@@ -0,0 +1,879 @@
+/* -*- 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()
+{
+ // The following call is a workaround to ensure the last used macro is scrolled to in kf5
+ m_xDialog->resize_to_request();
+
+ EntryDescriptor aDesc;
+ if (Shell* pShell = GetShell())
+ {
+ if (BaseWindow* pCurWin = pShell->GetCurWindow())
+ aDesc = pCurWin->CreateEntryDescriptor();
+ }
+ else
+ {
+ if (ExtraData* pData = basctl::GetExtraData())
+ aDesc = pData->GetLastEntryDescriptor();
+ }
+
+ 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_CONFIGACCEL, 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(), nullptr, 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());
+
+ OUString 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 0000000000..0e50ee5de0
--- /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 0000000000..1221b00942
--- /dev/null
+++ b/basctl/source/basicide/moduldl2.cxx
@@ -0,0 +1,1373 @@
+/* -*- 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 <comphelper/diagnose_ex.hxx>
+#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);
+
+ // tdf#151741 - store all libraries to the file system, otherwise they
+ // cannot be renamed/moved since the SfxLibraryContainer::renameLibrary
+ // moves the folders/files on the file system
+ Reference<script::XLibraryContainer2> xModLibContainer(
+ rDocument.getLibraryContainer(E_SCRIPTS), UNO_QUERY);
+ Reference<script::XLibraryContainer2> xDlgLibContainer(
+ rDocument.getLibraryContainer(E_DIALOGS), UNO_QUERY);
+ Reference<script::XPersistentLibraryContainer> xModPersLibContainer(xModLibContainer,
+ UNO_QUERY);
+ if (xModPersLibContainer.is())
+ xModPersLibContainer->storeLibraries();
+ Reference<script::XPersistentLibraryContainer> xDlgPersLibContainer(xDlgLibContainer,
+ UNO_QUERY);
+ if (xDlgPersLibContainer.is())
+ xDlgPersLibContainer->storeLibraries();
+
+ 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 ? RID_BMP_DLGLIB : 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 0000000000..4b67e320b5
--- /dev/null
+++ b/basctl/source/basicide/moduldlg.cxx
@@ -0,0 +1,1052 @@
+/* -*- 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 <com/sun/star/frame/XController.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 <comphelper/diagnose_ex.hxx>
+#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 >() );
+}
+
+void OrganizeDialog::SetCurrentEntry(const css::uno::Reference<css::frame::XFrame>& xDocFrame)
+{
+ if (!xDocFrame)
+ return;
+ Reference<css::frame::XController> xController(xDocFrame->getController());
+ if (!xController)
+ return;
+ Reference<css::frame::XModel> xModel(xController->getModel());
+ if (!xModel)
+ return;
+ ScriptDocument aScriptDocument(xModel);
+ EntryDescriptor aDesc(aScriptDocument, LIBRARY_LOCATION_DOCUMENT, OUString(), OUString(), OUString(), OBJ_TYPE_DOCUMENT);
+ m_xModulePage->SetCurrentEntry(aDesc);
+ m_xDialogPage->SetCurrentEntry(aDesc);
+}
+
+// OrganizeDialog
+OrganizeDialog::OrganizeDialog(weld::Window* pParent, const css::uno::Reference<css::frame::XFrame>& xDocFrame, 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));
+
+ SetCurrentEntry(xDocFrame);
+
+ OUString 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 OUString&, 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 OUString &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()))
+ return;
+ 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 OUString &rName, BrowseMode nMode, OrganizeDialog* pDialog)
+ : OrganizePage(pParent, "modules/BasicIDE/ui/" + rName.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 0000000000..4f4cbcbda3
--- /dev/null
+++ b/basctl/source/basicide/moduldlg.hxx
@@ -0,0 +1,226 @@
+/* -*- 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 OUString &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 OUString& rName, BrowseMode nMode, OrganizeDialog* pDialog);
+ virtual ~ObjectPage() override;
+
+ void SetCurrentEntry(const EntryDescriptor& rDesc) { m_xBasicBox->SetCurrentEntry(rDesc); }
+
+ 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 OUString&, void);
+
+ void SetCurrentEntry(const css::uno::Reference<css::frame::XFrame>& xDocFrame);
+
+public:
+ OrganizeDialog(weld::Window* pParent, const css::uno::Reference<css::frame::XFrame>& xDocFrame, 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 0000000000..39c86b1d08
--- /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 0000000000..c435d7a57d
--- /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 <comphelper/diagnose_ex.hxx>
+#include <config_folders.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 aDecodedURL = xUriRef->getAuthority();
+ if (aDecodedURL.startsWithIgnoreAsciiCase("vnd.sun.star.expand:", &aDecodedURL))
+ {
+ 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( LIBO_SHARE_FOLDER "/basic" ) >= 0 ||
+ aCanonicalFileURL.indexOf( LIBO_SHARE_FOLDER "/uno_packages" ) >= 0 ||
+ aCanonicalFileURL.indexOf( LIBO_SHARE_FOLDER "/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 0000000000..421468a279
--- /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::XVclWindowPeer> 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 0000000000..e29c4a412d
--- /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 XVclWindowPeer;
+}
+class TextView;
+
+namespace basctl
+{
+css::uno::Reference<css::awt::XVclWindowPeer> 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 0000000000..b875b1eced
--- /dev/null
+++ b/basctl/source/basicide/uiobject.cxx
@@ -0,0 +1,50 @@
+/* -*- 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) + "\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 0000000000..f3a1e5ec88
--- /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 0000000000..5d3946b426
--- /dev/null
+++ b/basctl/source/basicide/unomodel.cxx
@@ -0,0 +1,131 @@
+/* -*- 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 ::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 0000000000..b478730056
--- /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: */
diff --git a/basctl/source/dlged/dlged.cxx b/basctl/source/dlged/dlged.cxx
new file mode 100644
index 0000000000..2eb099718b
--- /dev/null
+++ b/basctl/source/dlged/dlged.cxx
@@ -0,0 +1,1236 @@
+/* -*- 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 <dlged.hxx>
+#include <dlgedclip.hxx>
+#include <dlgeddef.hxx>
+#include <dlgedfac.hxx>
+#include <dlgedfunc.hxx>
+#include <dlgedmod.hxx>
+#include <dlgedobj.hxx>
+#include <dlgedpage.hxx>
+#include <dlgedview.hxx>
+#include <localizationmgr.hxx>
+#include <baside3.hxx>
+
+#include <com/sun/star/awt/Toolkit.hpp>
+#include <com/sun/star/awt/UnoControlDialog.hpp>
+#include <com/sun/star/awt/XVclWindowPeer.hpp>
+#include <com/sun/star/resource/StringResource.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+#include <com/sun/star/util/NumberFormatsSupplier.hpp>
+#include <comphelper/types.hxx>
+#include <comphelper/processfactory.hxx>
+#include <tools/debug.hxx>
+#include <svl/itempool.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/svdpagv.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/print.hxx>
+#include <vcl/svapp.hxx>
+#include <xmlscript/xml_helper.hxx>
+#include <xmlscript/xmldlg_imexp.hxx>
+#include <osl/diagnose.h>
+
+namespace basctl
+{
+
+using namespace comphelper;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::io;
+
+constexpr OUString aResourceResolverPropName = u"ResourceResolver"_ustr;
+constexpr OUString aDecorationPropName = u"Decoration"_ustr;
+
+
+// DlgEdHint
+
+
+DlgEdHint::DlgEdHint(Kind eHint)
+ : eKind(eHint)
+ , pDlgEdObj(nullptr)
+{
+}
+
+DlgEdHint::DlgEdHint(Kind eHint, DlgEdObj* pObj)
+ : eKind(eHint)
+ , pDlgEdObj(pObj)
+{
+}
+
+DlgEdHint::~DlgEdHint()
+{
+}
+
+
+// DlgEditor
+
+
+void DlgEditor::ShowDialog()
+{
+ uno::Reference< uno::XComponentContext > xContext = getProcessComponentContext();
+
+ // create a dialog
+ uno::Reference< awt::XUnoControlDialog > xDlg = awt::UnoControlDialog::create( xContext );
+
+ // clone the dialog model
+ uno::Reference< util::XCloneable > xC( m_xUnoControlDialogModel, uno::UNO_QUERY );
+ uno::Reference< util::XCloneable > xNew = xC->createClone();
+ uno::Reference< awt::XControlModel > xDlgMod( xNew, uno::UNO_QUERY );
+
+ uno::Reference< beans::XPropertySet > xSrcDlgModPropSet( m_xUnoControlDialogModel, uno::UNO_QUERY );
+ uno::Reference< beans::XPropertySet > xNewDlgModPropSet( xDlgMod, uno::UNO_QUERY );
+ if( xNewDlgModPropSet.is() )
+ {
+ if( xSrcDlgModPropSet.is() )
+ {
+ try
+ {
+ Any aResourceResolver = xSrcDlgModPropSet->getPropertyValue( aResourceResolverPropName );
+ xNewDlgModPropSet->setPropertyValue( aResourceResolverPropName, aResourceResolver );
+ }
+ catch(const UnknownPropertyException& )
+ {
+ OSL_FAIL( "DlgEditor::ShowDialog(): No ResourceResolver property" );
+ }
+ }
+
+ // Disable decoration
+ try
+ {
+ bool bDecoration = true;
+
+ Any aDecorationAny = xSrcDlgModPropSet->getPropertyValue( aDecorationPropName );
+ aDecorationAny >>= bDecoration;
+ if( !bDecoration )
+ {
+ xNewDlgModPropSet->setPropertyValue( aDecorationPropName, Any( true ) );
+ xNewDlgModPropSet->setPropertyValue( "Title", Any( OUString() ) );
+ }
+ }
+ catch(const UnknownPropertyException& )
+ {}
+ }
+
+ // set the model
+ xDlg->setModel( xDlgMod );
+
+ // create a peer
+ uno::Reference< awt::XToolkit> xToolkit = awt::Toolkit::create( xContext );
+ xDlg->createPeer( xToolkit, rWindow.GetComponentInterface() );
+
+ xDlg->execute();
+
+ // need to cast because of multiple inheritance
+ Reference<awt::XControl>(xDlg)->dispose();
+}
+
+
+bool DlgEditor::UnmarkDialog()
+{
+ SdrObject* pDlgObj = pDlgEdModel->GetPage(0)->GetObj(0);
+ SdrPageView* pPgView = pDlgEdView->GetSdrPageView();
+
+ bool bWasMarked = pDlgEdView->IsObjMarked( pDlgObj );
+
+ if( bWasMarked )
+ pDlgEdView->MarkObj( pDlgObj, pPgView, true );
+
+ return bWasMarked;
+}
+
+
+bool DlgEditor::RemarkDialog()
+{
+ SdrObject* pDlgObj = pDlgEdModel->GetPage(0)->GetObj(0);
+ SdrPageView* pPgView = pDlgEdView->GetSdrPageView();
+
+ bool bWasMarked = pDlgEdView->IsObjMarked( pDlgObj );
+
+ if( !bWasMarked )
+ pDlgEdView->MarkObj( pDlgObj, pPgView );
+
+ return bWasMarked;
+}
+
+
+DlgEditor::DlgEditor (
+ vcl::Window& rWindow_, DialogWindowLayout& rLayout_,
+ css::uno::Reference<css::frame::XModel> const& xModel,
+ css::uno::Reference<css::container::XNameContainer> const & xDialogModel
+)
+ :pHScroll(nullptr)
+ ,pVScroll(nullptr)
+ ,pDlgEdModel(new DlgEdModel())
+ ,pDlgEdPage(new DlgEdPage(*pDlgEdModel))
+ // set clipboard data flavors
+ ,m_ClipboardDataFlavors{ { /* MimeType */ "application/vnd.sun.xml.dialog",
+ /* HumanPresentableName */ "Dialog 6.0",
+ /* DataType */ cppu::UnoType<Sequence< sal_Int8 >>::get() } }
+ ,m_ClipboardDataFlavorsResource{ m_ClipboardDataFlavors[0],
+ { /* MimeType */ "application/vnd.sun.xml.dialogwithresource",
+ /* HumanPresentableName */ "Dialog 8.0",
+ /* DataType */ cppu::UnoType<Sequence< sal_Int8 >>::get() } }
+ ,pObjFac(new DlgEdFactory(xModel))
+ ,rWindow(rWindow_)
+ ,pFunc(new DlgEdFuncSelect(*this))
+ ,rLayout(rLayout_)
+ ,eMode( DlgEditor::SELECT )
+ ,eActObj( SdrObjKind::BasicDialogPushButton )
+ ,bFirstDraw(false)
+ ,bCreateOK(true)
+ ,bDialogModelChanged(false)
+ ,aMarkIdle("basctl DlgEditor Mark")
+ ,mnPaintGuard(0)
+ ,m_xDocument( xModel )
+{
+ pDlgEdModel->GetItemPool().FreezeIdRanges();
+ pDlgEdView.reset(new DlgEdView(*pDlgEdModel, *rWindow_.GetOutDev(), *this));
+ pDlgEdModel->SetScaleUnit( MapUnit::Map100thMM );
+
+ SdrLayerAdmin& rAdmin = pDlgEdModel->GetLayerAdmin();
+ rAdmin.NewLayer( rAdmin.GetControlLayerName() );
+ rAdmin.NewLayer( "HiddenLayer" );
+
+ pDlgEdModel->InsertPage(pDlgEdPage);
+
+ aMarkIdle.SetInvokeHandler( LINK( this, DlgEditor, MarkTimeout ) );
+
+ rWindow.SetMapMode( MapMode( MapUnit::Map100thMM ) );
+ pDlgEdPage->SetSize( rWindow.PixelToLogic( Size(DLGED_PAGE_WIDTH_MIN, DLGED_PAGE_HEIGHT_MIN) ) );
+
+ pDlgEdView->ShowSdrPage(pDlgEdView->GetModel().GetPage(0));
+ pDlgEdView->SetLayerVisible( "HiddenLayer", false );
+ pDlgEdView->SetMoveSnapOnlyTopLeft(true);
+ pDlgEdView->SetWorkArea( tools::Rectangle( Point( 0, 0 ), pDlgEdPage->GetSize() ) );
+
+ Size aGridSize( 100, 100 ); // 100TH_MM
+ pDlgEdView->SetGridCoarse( aGridSize );
+ pDlgEdView->SetSnapGridWidth(Fraction(aGridSize.Width(), 1), Fraction(aGridSize.Height(), 1));
+ pDlgEdView->SetGridSnap( true );
+ pDlgEdView->SetGridVisible( false );
+ pDlgEdView->SetDragStripes(false);
+
+ pDlgEdView->SetDesignMode();
+
+ ::comphelper::disposeComponent( m_xControlContainer );
+
+ SetDialog(xDialogModel);
+}
+
+DlgEditor::~DlgEditor()
+{
+ aMarkIdle.Stop();
+
+ ::comphelper::disposeComponent( m_xControlContainer );
+}
+
+Reference< awt::XControlContainer > const & DlgEditor::GetWindowControlContainer()
+{
+ if (!m_xControlContainer.is())
+ m_xControlContainer = VCLUnoHelper::CreateControlContainer(&rWindow);
+ return m_xControlContainer;
+}
+
+void DlgEditor::SetScrollBars(ScrollAdaptor* pHS, ScrollAdaptor* pVS)
+{
+ pHScroll = pHS;
+ pVScroll = pVS;
+
+ InitScrollBars();
+}
+
+void DlgEditor::InitScrollBars()
+{
+ DBG_ASSERT( pHScroll, "DlgEditor::InitScrollBars: no horizontal scroll bar!" );
+ DBG_ASSERT( pVScroll, "DlgEditor::InitScrollBars: no vertical scroll bar!" );
+ if ( !pHScroll || !pVScroll )
+ return;
+
+ Size aOutSize = rWindow.GetOutDev()->GetOutputSize();
+ Size aPgSize = pDlgEdPage->GetSize();
+
+ pHScroll->SetRange( Range( 0, aPgSize.Width() ));
+ pVScroll->SetRange( Range( 0, aPgSize.Height() ));
+ pHScroll->SetVisibleSize( aOutSize.Width() );
+ pVScroll->SetVisibleSize( aOutSize.Height() );
+
+ pHScroll->SetLineSize( aOutSize.Width() / 10 );
+ pVScroll->SetLineSize( aOutSize.Height() / 10 );
+ pHScroll->SetPageSize( aOutSize.Width() / 2 );
+ pVScroll->SetPageSize( aOutSize.Height() / 2 );
+
+ DoScroll();
+}
+
+
+void DlgEditor::DoScroll()
+{
+ if( !pHScroll || !pVScroll )
+ return;
+
+ MapMode aMap = rWindow.GetMapMode();
+ Point aOrg = aMap.GetOrigin();
+
+ Size aScrollPos( pHScroll->GetThumbPos(), pVScroll->GetThumbPos() );
+ aScrollPos = rWindow.LogicToPixel( aScrollPos );
+ aScrollPos = rWindow.PixelToLogic( aScrollPos );
+
+ tools::Long nX = aScrollPos.Width() + aOrg.X();
+ tools::Long nY = aScrollPos.Height() + aOrg.Y();
+
+ if( !nX && !nY )
+ return;
+
+ rWindow.PaintImmediately();
+
+ // #i31562#
+ // When scrolling, someone was rescuing the Wallpaper and forced the window scroll to
+ // be done without background refresh. I do not know why, but that causes the repaint
+ // problems. Taking that out.
+ // Wallpaper aOldBackground = rWindow.GetBackground();
+ // rWindow.SetBackground();
+
+ // #i74769# children should be scrolled
+ rWindow.Scroll( -nX, -nY, ScrollFlags::Children);
+ aMap.SetOrigin( Point( -aScrollPos.Width(), -aScrollPos.Height() ) );
+ rWindow.SetMapMode( aMap );
+ rWindow.PaintImmediately();
+
+ DlgEdHint aHint( DlgEdHint::WINDOWSCROLLED );
+ Broadcast( aHint );
+}
+
+
+void DlgEditor::UpdateScrollBars()
+{
+ MapMode aMap = rWindow.GetMapMode();
+ Point aOrg = aMap.GetOrigin();
+
+ if ( pHScroll )
+ pHScroll->SetThumbPos( -aOrg.X() );
+
+ if ( pVScroll )
+ pVScroll->SetThumbPos( -aOrg.Y() );
+}
+
+
+void DlgEditor::SetDialog( const uno::Reference< container::XNameContainer >& xUnoControlDialogModel )
+{
+ // set dialog model
+ m_xUnoControlDialogModel = xUnoControlDialogModel;
+
+ // create dialog form
+ pDlgEdForm = new DlgEdForm(*pDlgEdModel, *this);
+ uno::Reference< awt::XControlModel > xDlgMod( m_xUnoControlDialogModel , uno::UNO_QUERY );
+ pDlgEdForm->SetUnoControlModel(xDlgMod);
+ static_cast<DlgEdPage*>(pDlgEdModel->GetPage(0))->SetDlgEdForm( pDlgEdForm.get() );
+ pDlgEdModel->GetPage(0)->InsertObject( pDlgEdForm.get() );
+ AdjustPageSize();
+ pDlgEdForm->SetRectFromProps();
+ pDlgEdForm->UpdateTabIndices(); // for backward compatibility
+ pDlgEdForm->StartListening();
+
+ // create controls
+ if ( m_xUnoControlDialogModel.is() )
+ {
+ // get sequence of control names
+ Sequence< OUString > aNames = m_xUnoControlDialogModel->getElementNames();
+ const OUString* pNames = aNames.getConstArray();
+ sal_Int32 nCtrls = aNames.getLength();
+
+ // create a map of tab indices and control names, sorted by tab index
+ IndexToNameMap aIndexToNameMap;
+ for ( sal_Int32 i = 0; i < nCtrls; ++i )
+ {
+ // get name
+ OUString aName( pNames[i] );
+
+ // get tab index
+ sal_Int16 nTabIndex = -1;
+ Any aCtrl = m_xUnoControlDialogModel->getByName( aName );
+ Reference< css::beans::XPropertySet > xPSet;
+ aCtrl >>= xPSet;
+ if ( xPSet.is() )
+ xPSet->getPropertyValue( DLGED_PROP_TABINDEX ) >>= nTabIndex;
+
+ // insert into map
+ aIndexToNameMap.emplace( nTabIndex, aName );
+ }
+
+ // create controls and insert them into drawing page
+ for (auto const& indexToName : aIndexToNameMap)
+ {
+ Any aCtrl = m_xUnoControlDialogModel->getByName( indexToName.second );
+ Reference< css::awt::XControlModel > xCtrlModel;
+ aCtrl >>= xCtrlModel;
+ rtl::Reference<DlgEdObj> pCtrlObj = new DlgEdObj(*pDlgEdModel);
+ pCtrlObj->SetUnoControlModel( xCtrlModel );
+ pCtrlObj->SetDlgEdForm( pDlgEdForm.get() );
+ pDlgEdForm->AddChild( pCtrlObj.get() );
+ pDlgEdModel->GetPage(0)->InsertObject( pCtrlObj.get() );
+ pCtrlObj->SetRectFromProps();
+ pCtrlObj->UpdateStep();
+ pCtrlObj->StartListening();
+ }
+ }
+
+ bFirstDraw = true;
+
+ pDlgEdModel->SetChanged(false);
+}
+
+void DlgEditor::ResetDialog ()
+{
+ DlgEdForm* pOldDlgEdForm = pDlgEdForm.get();
+ DlgEdPage* pPage = static_cast<DlgEdPage*>(pDlgEdModel->GetPage(0));
+ SdrPageView* pPgView = pDlgEdView->GetSdrPageView();
+ bool bWasMarked = pDlgEdView->IsObjMarked( pOldDlgEdForm );
+ pDlgEdView->UnmarkAll();
+
+ // clear SdrObjects with broadcasting
+ pPage->ClearSdrObjList();
+
+ pPage->SetDlgEdForm( nullptr );
+ SetDialog( m_xUnoControlDialogModel );
+ if( bWasMarked )
+ pDlgEdView->MarkObj( pDlgEdForm.get(), pPgView );
+}
+
+
+Reference< util::XNumberFormatsSupplier > const & DlgEditor::GetNumberFormatsSupplier()
+{
+ if ( !m_xSupplier.is() )
+ {
+ Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ Reference< util::XNumberFormatsSupplier > xSupplier( util::NumberFormatsSupplier::createWithDefaultLocale(xContext) );
+
+ ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
+ if ( !m_xSupplier.is() )
+ {
+ m_xSupplier = xSupplier;
+ }
+ }
+ return m_xSupplier;
+}
+
+
+void DlgEditor::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ rWindow.GrabFocus();
+ pFunc->MouseButtonDown( rMEvt );
+}
+
+
+void DlgEditor::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ bool bRet = pFunc->MouseButtonUp( rMEvt );
+
+ if( eMode == DlgEditor::INSERT )
+ bCreateOK = bRet;
+}
+
+
+void DlgEditor::MouseMove( const MouseEvent& rMEvt )
+{
+ pFunc->MouseMove( rMEvt );
+}
+
+
+bool DlgEditor::KeyInput( const KeyEvent& rKEvt )
+{
+ return pFunc->KeyInput( rKEvt );
+}
+
+
+void DlgEditor::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ aPaintRect = rRect;
+ mnPaintGuard++;
+
+ if (bFirstDraw && rWindow.IsVisible() && (rRenderContext.GetOutputSize() != Size()))
+ {
+ bFirstDraw = false;
+
+ // get property set
+ css::uno::Reference<css::beans::XPropertySet> xPSet(pDlgEdForm->GetUnoControlModel(), css::uno::UNO_QUERY);
+
+ if (xPSet.is())
+ {
+ // get dialog size from properties
+ sal_Int32 nWidth = 0, nHeight = 0;
+ xPSet->getPropertyValue( DLGED_PROP_WIDTH ) >>= nWidth;
+ xPSet->getPropertyValue( DLGED_PROP_HEIGHT ) >>= nHeight;
+
+ if (nWidth == 0 && nHeight == 0)
+ {
+ Size aSize = rRenderContext.PixelToLogic( Size( 400, 300 ) );
+
+ // align with grid
+ Size aGridSize_(tools::Long(pDlgEdView->GetSnapGridWidthX()), tools::Long(pDlgEdView->GetSnapGridWidthY()));
+ aSize.AdjustWidth( -(aSize.Width() % aGridSize_.Width()) );
+ aSize.AdjustHeight( -(aSize.Height() % aGridSize_.Height()) );
+
+ Point aPos;
+ Size aOutSize = rRenderContext.GetOutputSize();
+ aPos.setX( (aOutSize.Width()>>1) - (aSize.Width()>>1) );
+ aPos.setY( (aOutSize.Height()>>1) - (aSize.Height()>>1) );
+
+ // align with grid
+ aPos.AdjustX( -(aPos.X() % aGridSize_.Width()) );
+ aPos.AdjustY( -(aPos.Y() % aGridSize_.Height()) );
+
+ // don't put in the corner
+ Point aMinPos = rRenderContext.PixelToLogic( Point( 30, 20 ) );
+ if( (aPos.X() < aMinPos.X()) || (aPos.Y() < aMinPos.Y()) )
+ {
+ aPos = aMinPos;
+ aPos.AdjustX( -(aPos.X() % aGridSize_.Width()) );
+ aPos.AdjustY( -(aPos.Y() % aGridSize_.Height()) );
+ }
+
+ // set dialog position and size
+ pDlgEdForm->SetSnapRect( tools::Rectangle( aPos, aSize ) );
+ pDlgEdForm->EndListening(false);
+ pDlgEdForm->SetPropsFromRect();
+ pDlgEdForm->GetDlgEditor().SetDialogModelChanged();
+ pDlgEdForm->StartListening();
+
+ // set position and size of controls
+ for (const rtl::Reference<SdrObject>& pObj : *pDlgEdPage)
+ {
+ if (DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj.get()))
+ {
+ if (!dynamic_cast<DlgEdForm*>(pDlgEdObj))
+ {
+ pDlgEdObj->SetRectFromProps();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // repaint, get PageView and prepare Region
+ SdrPageView* pPgView = pDlgEdView->GetSdrPageView();
+ const vcl::Region aPaintRectRegion(aPaintRect);
+
+ // #i74769#
+ SdrPaintWindow* pTargetPaintWindow = nullptr;
+
+ // mark repaint start
+ if (pPgView)
+ {
+ pTargetPaintWindow = pPgView->GetView().BeginDrawLayers(&rRenderContext, aPaintRectRegion);
+ OSL_ENSURE(pTargetPaintWindow, "BeginDrawLayers: Got no SdrPaintWindow (!)");
+ }
+
+ // draw background self using wallpaper
+ // #i79128# ...and use correct OutDev for that
+ if (pTargetPaintWindow)
+ {
+ Color maBackColor = rRenderContext.GetSettings().GetStyleSettings().GetLightColor();
+ OutputDevice& rTargetOutDev = pTargetPaintWindow->GetTargetOutputDevice();
+ rTargetOutDev.DrawWallpaper(aPaintRect, Wallpaper(maBackColor));
+ }
+
+ // do paint (unbuffered) and mark repaint end
+ if (pPgView)
+ {
+ // paint of control layer is done in EndDrawLayers anyway...
+ pPgView->GetView().EndDrawLayers(*pTargetPaintWindow, true);
+ }
+
+ mnPaintGuard--;
+}
+
+
+IMPL_LINK_NOARG(DlgEditor, MarkTimeout, Timer *, void)
+{
+ rLayout.UpdatePropertyBrowser();
+}
+
+
+void DlgEditor::SetMode (Mode eNewMode )
+{
+ if ( eNewMode != eMode )
+ {
+ if ( eNewMode == INSERT )
+ pFunc.reset(new DlgEdFuncInsert(*this));
+ else
+ pFunc.reset(new DlgEdFuncSelect(*this));
+
+ if ( eNewMode == READONLY )
+ pDlgEdModel->SetReadOnly( true );
+ else
+ pDlgEdModel->SetReadOnly( false );
+ }
+
+ if ( eNewMode == TEST )
+ ShowDialog();
+
+ eMode = eNewMode;
+}
+
+
+void DlgEditor::SetInsertObj(SdrObjKind eObj)
+{
+ eActObj = eObj;
+
+ pDlgEdView->SetCurrentObj( eActObj, SdrInventor::BasicDialog );
+}
+
+void DlgEditor::CreateDefaultObject()
+{
+ // create object by factory
+ rtl::Reference<SdrObject> pObj = SdrObjFactory::MakeNewObject(
+ *pDlgEdModel,
+ pDlgEdView->GetCurrentObjInventor(),
+ pDlgEdView->GetCurrentObjIdentifier());
+
+ DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj.get());
+ if (!pDlgEdObj)
+ return;
+
+ // set position and size
+ Size aSize = rWindow.PixelToLogic( Size( 96, 24 ) );
+ Point aPoint = pDlgEdForm->GetSnapRect().Center();
+ aPoint.AdjustX( -(aSize.Width() / 2) );
+ aPoint.AdjustY( -(aSize.Height() / 2) );
+ pDlgEdObj->SetSnapRect( tools::Rectangle( aPoint, aSize ) );
+
+ // set default property values
+ pDlgEdObj->SetDefaults();
+
+ // insert object into drawing page
+ SdrPageView* pPageView = pDlgEdView->GetSdrPageView();
+ if (pDlgEdView->InsertObjectAtView(pDlgEdObj, *pPageView))
+ {
+ // start listening
+ pDlgEdObj->StartListening();
+ }
+}
+
+void DlgEditor::Cut()
+{
+ Copy();
+ Delete();
+}
+
+static void implCopyStreamToByteSequence( const Reference< XInputStream >& xStream,
+ Sequence< sal_Int8 >& bytes )
+{
+ xStream->readBytes( bytes, xStream->available() );
+ for (;;)
+ {
+ Sequence< sal_Int8 > readBytes;
+ sal_Int32 nRead = xStream->readBytes( readBytes, 1024 );
+ if (! nRead)
+ break;
+
+ sal_Int32 nPos = bytes.getLength();
+ bytes.realloc( nPos + nRead );
+ memcpy( bytes.getArray() + nPos, readBytes.getConstArray(), static_cast<sal_uInt32>(nRead) );
+ }
+}
+
+void DlgEditor::Copy()
+{
+ if( !pDlgEdView->AreObjectsMarked() )
+ return;
+
+ // stop all drawing actions
+ pDlgEdView->BrkAction();
+
+ // create an empty clipboard dialog model
+ Reference< util::XCloneable > xClone( m_xUnoControlDialogModel, UNO_QUERY );
+ Reference< util::XCloneable > xNewClone = xClone->createClone();
+ Reference< container::XNameContainer > xClipDialogModel( xNewClone, UNO_QUERY );
+
+ if ( xClipDialogModel.is() )
+ {
+ Sequence< OUString > aNames = xClipDialogModel->getElementNames();
+ const OUString* pNames = aNames.getConstArray();
+ sal_uInt32 nCtrls = aNames.getLength();
+
+ for ( sal_uInt32 n = 0; n < nCtrls; n++ )
+ {
+ xClipDialogModel->removeByName( pNames[n] );
+ }
+ }
+
+ // insert control models of marked objects into clipboard dialog model
+ const size_t nMark = pDlgEdView->GetMarkedObjectList().GetMarkCount();
+ for( size_t i = 0; i < nMark; ++i )
+ {
+ SdrObject* pObj = pDlgEdView->GetMarkedObjectList().GetMark(i)->GetMarkedSdrObj();
+ DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj);
+
+ if (pDlgEdObj && !dynamic_cast<DlgEdForm*>(pDlgEdObj))
+ {
+ OUString aName;
+ Reference< beans::XPropertySet > xMarkPSet(pDlgEdObj->GetUnoControlModel(), uno::UNO_QUERY);
+ if (xMarkPSet.is())
+ {
+ xMarkPSet->getPropertyValue( DLGED_PROP_NAME ) >>= aName;
+ }
+
+ if ( m_xUnoControlDialogModel.is() && m_xUnoControlDialogModel->hasByName(aName) )
+ {
+ Any aCtrl = m_xUnoControlDialogModel->getByName( aName );
+
+ // clone control model
+ Reference< util::XCloneable > xCtrl;
+ aCtrl >>= xCtrl;
+ Reference< util::XCloneable > xNewCtrl = xCtrl->createClone();
+ Any aNewCtrl;
+ aNewCtrl <<= xNewCtrl;
+
+ if (xClipDialogModel.is())
+ xClipDialogModel->insertByName( aName , aNewCtrl );
+ }
+ }
+ }
+
+ // export clipboard dialog model to xml
+ Reference< XComponentContext > xContext(
+ comphelper::getProcessComponentContext() );
+ Reference< XInputStreamProvider > xISP = ::xmlscript::exportDialogModel( xClipDialogModel, xContext, m_xDocument );
+ Reference< XInputStream > xStream( xISP->createInputStream() );
+ Sequence< sal_Int8 > DialogModelBytes;
+ implCopyStreamToByteSequence( xStream, DialogModelBytes );
+ xStream->closeInput();
+
+ // set clipboard content
+ Reference< datatransfer::clipboard::XClipboard > xClipboard = GetWindow().GetClipboard();
+ if ( !xClipboard.is() )
+ return;
+
+ // With resource?
+ uno::Reference< beans::XPropertySet > xDialogModelPropSet( m_xUnoControlDialogModel, uno::UNO_QUERY );
+ uno::Reference< resource::XStringResourcePersistence > xStringResourcePersistence;
+ if( xDialogModelPropSet.is() )
+ {
+ try
+ {
+ Any aResourceResolver = xDialogModelPropSet->getPropertyValue( aResourceResolverPropName );
+ aResourceResolver >>= xStringResourcePersistence;
+ }
+ catch(const UnknownPropertyException& )
+ {}
+ }
+
+ rtl::Reference<DlgEdTransferableImpl> pTrans;
+ if( xStringResourcePersistence.is() )
+ {
+ // With resource, support old and new format
+
+ // Export xClipDialogModel another time with ids replaced by current language string
+ LocalizationMgr::resetResourceForDialog( xClipDialogModel, xStringResourcePersistence );
+ Reference< XInputStreamProvider > xISP2 = ::xmlscript::exportDialogModel( xClipDialogModel, xContext, m_xDocument );
+ Reference< XInputStream > xStream2( xISP2->createInputStream() );
+ Sequence< sal_Int8 > NoResourceDialogModelBytes;
+ implCopyStreamToByteSequence( xStream2, NoResourceDialogModelBytes );
+ xStream2->closeInput();
+
+ // Old format contains dialog with replaced ids
+ Any aNoResourceDialogModelBytesAny;
+ aNoResourceDialogModelBytesAny <<= NoResourceDialogModelBytes;
+
+ // New format contains dialog and resource
+ Sequence< sal_Int8 > aResData = xStringResourcePersistence->exportBinary();
+
+ // Create sequence for combined dialog and resource
+ sal_Int32 nDialogDataLen = DialogModelBytes.getLength();
+ sal_Int32 nResDataLen = aResData.getLength();
+
+ // Combined data = 4 Bytes 32Bit Offset to begin of resource data, lowest byte first
+ // + nDialogDataLen bytes dialog data + nResDataLen resource data
+ sal_Int32 nTotalLen = 4 + nDialogDataLen + nResDataLen;
+ sal_Int32 nResOffset = 4 + nDialogDataLen;
+ Sequence< sal_Int8 > aCombinedData( nTotalLen );
+ sal_Int8* pCombinedData = aCombinedData.getArray();
+
+ // Write offset
+ sal_Int32 n = nResOffset;
+ for( sal_Int16 i = 0 ; i < 4 ; i++ )
+ {
+ pCombinedData[i] = sal_Int8( n & 0xff );
+ n >>= 8;
+ }
+ memcpy( pCombinedData + 4, DialogModelBytes.getConstArray(), nDialogDataLen );
+ memcpy( pCombinedData + nResOffset, aResData.getConstArray(), nResDataLen );
+
+ Sequence< Any > aSeqData
+ {
+ aNoResourceDialogModelBytesAny,
+ Any(aCombinedData)
+ };
+
+ pTrans = new DlgEdTransferableImpl( m_ClipboardDataFlavorsResource, aSeqData );
+ }
+ else
+ {
+ // No resource, support only old format
+ pTrans = new DlgEdTransferableImpl( m_ClipboardDataFlavors , { Any(DialogModelBytes) } );
+ }
+ SolarMutexReleaser aReleaser;
+ xClipboard->setContents( pTrans , pTrans );
+}
+
+
+void DlgEditor::Paste()
+{
+ // stop all drawing actions
+ pDlgEdView->BrkAction();
+
+ // unmark all objects
+ pDlgEdView->UnmarkAll();
+
+ // get clipboard
+ Reference< datatransfer::clipboard::XClipboard > xClipboard = GetWindow().GetClipboard();
+ if ( !xClipboard.is() )
+ return;
+
+ Reference< datatransfer::XTransferable > xTransf;
+ {
+ SolarMutexReleaser aReleaser;
+ // get clipboard content
+ xTransf = xClipboard->getContents();
+ }
+ if ( !xTransf.is() )
+ return;
+
+ // Is target dialog (library) localized?
+ uno::Reference< beans::XPropertySet > xDialogModelPropSet( m_xUnoControlDialogModel, uno::UNO_QUERY );
+ uno::Reference< resource::XStringResourceManager > xStringResourceManager;
+ if( xDialogModelPropSet.is() )
+ {
+ try
+ {
+ Any aResourceResolver = xDialogModelPropSet->getPropertyValue( aResourceResolverPropName );
+ aResourceResolver >>= xStringResourceManager;
+ }
+ catch(const UnknownPropertyException& )
+ {}
+ }
+ bool bLocalized = false;
+ if( xStringResourceManager.is() )
+ bLocalized = xStringResourceManager->getLocales().hasElements();
+
+ if ( !xTransf->isDataFlavorSupported( m_ClipboardDataFlavors[0] ) )
+ return;
+
+ // create clipboard dialog model from xml
+ Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
+ Reference< container::XNameContainer > xClipDialogModel( xContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.awt.UnoControlDialogModel", xContext ), uno::UNO_QUERY );
+
+ bool bSourceIsLocalized = false;
+ Sequence< sal_Int8 > DialogModelBytes;
+ Sequence< sal_Int8 > aResData;
+ if( bLocalized && xTransf->isDataFlavorSupported( m_ClipboardDataFlavorsResource[1] ) )
+ {
+ bSourceIsLocalized = true;
+
+ Any aCombinedDataAny = xTransf->getTransferData( m_ClipboardDataFlavorsResource[1] );
+ Sequence< sal_Int8 > aCombinedData;
+ aCombinedDataAny >>= aCombinedData;
+ const sal_Int8* pCombinedData = aCombinedData.getConstArray();
+
+ sal_Int32 nTotalLen = aCombinedData.getLength();
+
+ // Reading offset
+ sal_Int32 nResOffset = 0;
+ sal_Int32 nFactor = 1;
+ for( sal_Int16 i = 0; i < 4; i++ )
+ {
+ nResOffset += nFactor * sal_uInt8( pCombinedData[i] );
+ nFactor *= 256;
+ }
+
+ sal_Int32 nResDataLen = nTotalLen - nResOffset;
+ sal_Int32 nDialogDataLen = nTotalLen - nResDataLen - 4;
+
+ DialogModelBytes.realloc( nDialogDataLen );
+ memcpy( DialogModelBytes.getArray(), pCombinedData + 4, nDialogDataLen );
+
+ aResData.realloc( nResDataLen );
+ memcpy( aResData.getArray(), pCombinedData + nResOffset, nResDataLen );
+ }
+ else
+ {
+ Any aAny = xTransf->getTransferData( m_ClipboardDataFlavors[0] );
+ aAny >>= DialogModelBytes;
+ }
+
+ if ( xClipDialogModel.is() )
+ {
+ Reference<XInputStream> xIn = ::xmlscript::createInputStream( DialogModelBytes.getConstArray(), DialogModelBytes.getLength() );
+ ::xmlscript::importDialogModel( xIn , xClipDialogModel, xContext, m_xDocument );
+ }
+
+ // get control models from clipboard dialog model
+ if ( !xClipDialogModel.is() )
+ return;
+
+ Sequence< OUString > aNames = xClipDialogModel->getElementNames();
+ const OUString* pNames = aNames.getConstArray();
+ sal_uInt32 nCtrls = aNames.getLength();
+
+ Reference< resource::XStringResourcePersistence > xStringResourcePersistence;
+ if( nCtrls > 0 && bSourceIsLocalized )
+ {
+ xStringResourcePersistence = css::resource::StringResource::create( getProcessComponentContext() );
+ xStringResourcePersistence->importBinary( aResData );
+ }
+ for( sal_uInt32 n = 0; n < nCtrls; n++ )
+ {
+ Any aA = xClipDialogModel->getByName( pNames[n] );
+ Reference< css::awt::XControlModel > xCM;
+ aA >>= xCM;
+
+ // clone the control model
+ Reference< util::XCloneable > xClone( xCM, uno::UNO_QUERY );
+ Reference< awt::XControlModel > xCtrlModel( xClone->createClone(), uno::UNO_QUERY );
+
+ rtl::Reference<DlgEdObj> pCtrlObj = new DlgEdObj(*pDlgEdModel);
+ pCtrlObj->SetDlgEdForm(pDlgEdForm.get()); // set parent form
+ pDlgEdForm->AddChild(pCtrlObj.get()); // add child to parent form
+ pCtrlObj->SetUnoControlModel( xCtrlModel ); // set control model
+
+ // set new name
+ OUString aOUniqueName( pCtrlObj->GetUniqueName() );
+ Reference< beans::XPropertySet > xPSet( xCtrlModel , UNO_QUERY );
+ xPSet->setPropertyValue( DLGED_PROP_NAME, Any(aOUniqueName) );
+
+ // set tabindex
+ Sequence< OUString > aNames_ = m_xUnoControlDialogModel->getElementNames();
+ xPSet->setPropertyValue( DLGED_PROP_TABINDEX, Any(static_cast<sal_Int16>(aNames_.getLength())) );
+
+ if( bLocalized )
+ {
+ Any aControlAny;
+ aControlAny <<= xCtrlModel;
+ if( bSourceIsLocalized && xStringResourcePersistence.is() )
+ {
+ LocalizationMgr::copyResourcesForPastedEditorObject( this,
+ aControlAny, aOUniqueName, xStringResourcePersistence );
+ }
+ else
+ {
+ LocalizationMgr::setControlResourceIDsForNewEditorObject
+ ( this, aControlAny, aOUniqueName );
+ }
+ }
+
+ // insert control model in editor dialog model
+ Any aCtrlModel;
+ aCtrlModel <<= xCtrlModel;
+ m_xUnoControlDialogModel->insertByName( aOUniqueName , aCtrlModel );
+
+ // insert object into drawing page
+ pDlgEdModel->GetPage(0)->InsertObject( pCtrlObj.get() );
+ pCtrlObj->SetRectFromProps();
+ pCtrlObj->UpdateStep();
+ pDlgEdForm->UpdateTabOrderAndGroups();
+ pCtrlObj->StartListening(); // start listening
+
+ // mark object
+ SdrPageView* pPgView = pDlgEdView->GetSdrPageView();
+ pDlgEdView->MarkObj( pCtrlObj.get(), pPgView, false, true);
+ }
+
+ // center marked objects in dialog editor form
+ Point aMarkCenter = pDlgEdView->GetMarkedObjRect().Center();
+ Point aFormCenter = pDlgEdForm->GetSnapRect().Center();
+ Point aPoint = aFormCenter - aMarkCenter;
+ Size aSize( aPoint.X() , aPoint.Y() );
+ pDlgEdView->MoveMarkedObj( aSize ); // update of control model properties (position + size) in NbcMove
+ pDlgEdView->MarkListHasChanged();
+
+ // dialog model changed
+ SetDialogModelChanged();
+}
+
+
+void DlgEditor::Delete()
+{
+ if( !pDlgEdView->AreObjectsMarked() )
+ return;
+
+ // remove control models of marked objects from dialog model
+ const size_t nMark = pDlgEdView->GetMarkedObjectList().GetMarkCount();
+
+ for( size_t i = 0; i < nMark; ++i )
+ {
+ SdrObject* pObj = pDlgEdView->GetMarkedObjectList().GetMark(i)->GetMarkedSdrObj();
+ DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj);
+
+ if ( pDlgEdObj && !dynamic_cast<DlgEdForm*>(pDlgEdObj) )
+ {
+ // get name from property
+ OUString aName;
+ uno::Reference< beans::XPropertySet > xPSet(pDlgEdObj->GetUnoControlModel(), uno::UNO_QUERY);
+ if (xPSet.is())
+ {
+ xPSet->getPropertyValue( DLGED_PROP_NAME ) >>= aName;
+ }
+
+ // remove control from dialog model
+ Reference< css::container::XNameAccess > xNameAcc(pDlgEdObj->GetDlgEdForm()->GetUnoControlModel(), UNO_QUERY );
+ if ( xNameAcc.is() && xNameAcc->hasByName(aName) )
+ {
+ Reference< css::container::XNameContainer > xCont(xNameAcc, UNO_QUERY );
+ if ( xCont.is() )
+ {
+ if( xCont->hasByName( aName ) )
+ {
+ Any aAny = xCont->getByName( aName );
+ LocalizationMgr::deleteControlResourceIDsForDeletedEditorObject( this, aAny, aName );
+ }
+ xCont->removeByName( aName );
+ }
+ }
+
+ // remove child from parent form
+ pDlgEdForm->RemoveChild( pDlgEdObj );
+ }
+ }
+
+ // update tab indices
+ pDlgEdForm->UpdateTabIndices();
+
+ pDlgEdView->BrkAction();
+
+ bool const bDlgMarked = UnmarkDialog();
+ pDlgEdView->DeleteMarked();
+ if( bDlgMarked )
+ RemarkDialog();
+}
+
+
+bool DlgEditor::IsPasteAllowed()
+{
+ // get clipboard
+ Reference< datatransfer::clipboard::XClipboard > xClipboard = GetWindow().GetClipboard();
+ if ( xClipboard.is() )
+ {
+ Reference< datatransfer::XTransferable > xTransf;
+ {
+ SolarMutexReleaser aReleaser;
+ // get clipboard content
+ xTransf = xClipboard->getContents();
+ }
+ if (xTransf.is())
+ return xTransf->isDataFlavorSupported(m_ClipboardDataFlavors[0]);
+ }
+ return false;
+}
+
+
+void DlgEditor::ShowProperties()
+{
+ rLayout.ShowPropertyBrowser();
+}
+
+
+void DlgEditor::UpdatePropertyBrowserDelayed()
+{
+ aMarkIdle.Start();
+}
+
+
+bool DlgEditor::IsModified() const
+{
+ return pDlgEdModel->IsChanged() || bDialogModelChanged;
+}
+
+
+void DlgEditor::ClearModifyFlag()
+{
+ pDlgEdModel->SetChanged(false);
+ bDialogModelChanged = false;
+}
+
+
+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;
+}
+
+static void lcl_PrintHeader( Printer* pPrinter, const OUString& rTitle ) // not working yet
+{
+
+ pPrinter->Push();
+
+ Size const aSz = pPrinter->GetOutputSize();
+
+ pPrinter->SetLineColor( COL_BLACK );
+ pPrinter->SetFillColor();
+
+ vcl::Font aFont( pPrinter->GetFont() );
+ aFont.SetWeight( WEIGHT_BOLD );
+ aFont.SetAlignment( ALIGN_BOTTOM );
+ pPrinter->SetFont( aFont );
+
+ tools::Long const nFontHeight = pPrinter->GetTextHeight();
+
+ // 1st border => line, 2+3 border = free space
+ tools::Long const nYTop = Print::nTopMargin - 3*Print::nBorder - nFontHeight;
+
+ tools::Long const nXLeft = Print::nLeftMargin - Print::nBorder;
+ tools::Long const nXRight = aSz.Width() - Print::nRightMargin + Print::nBorder;
+
+ 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);
+ pPrinter->DrawText( aPos, rTitle );
+
+ nY = Print::nTopMargin - Print::nBorder;
+ pPrinter->DrawLine( Point( nXLeft, nY ), Point( nXRight, nY ) );
+
+ pPrinter->Pop();
+}
+
+
+void DlgEditor::printPage( sal_Int32 nPage, Printer* pPrinter, const OUString& rTitle )
+{
+ if( nPage == 0 )
+ Print( pPrinter, rTitle );
+}
+
+
+void DlgEditor::Print( Printer* pPrinter, const OUString& rTitle ) // not working yet
+{
+ MapMode aOldMap( pPrinter->GetMapMode());
+ vcl::Font aOldFont( pPrinter->GetFont() );
+
+ MapMode aMap( MapUnit::Map100thMM );
+ pPrinter->SetMapMode( aMap );
+ vcl::Font aFont;
+ aFont.SetAlignment( ALIGN_BOTTOM );
+ aFont.SetFontSize( Size( 0, 360 ));
+ pPrinter->SetFont( aFont );
+
+ Size aPaperSz = pPrinter->GetOutputSize();
+ aPaperSz.AdjustWidth( -(Print::nLeftMargin + Print::nRightMargin) );
+ aPaperSz.AdjustHeight( -(Print::nTopMargin + Print::nBottomMargin) );
+
+ lcl_PrintHeader( pPrinter, rTitle );
+
+ BitmapEx aDlgEx;
+ Size aBmpSz( pPrinter->PixelToLogic( aDlgEx.GetSizePixel() ) );
+ double nPaperSzWidth = aPaperSz.Width();
+ double nPaperSzHeight = aPaperSz.Height();
+ double nBmpSzWidth = aBmpSz.Width();
+ double nBmpSzHeight = aBmpSz.Height();
+ double nScaleX = nPaperSzWidth / nBmpSzWidth;
+ double nScaleY = nPaperSzHeight / nBmpSzHeight;
+
+ Size aOutputSz;
+ if( nBmpSzHeight * nScaleX <= nPaperSzHeight )
+ {
+ aOutputSz.setWidth( static_cast<tools::Long>(nBmpSzWidth * nScaleX) );
+ aOutputSz.setHeight( static_cast<tools::Long>(nBmpSzHeight * nScaleX) );
+ }
+ else
+ {
+ aOutputSz.setWidth( static_cast<tools::Long>(nBmpSzWidth * nScaleY) );
+ aOutputSz.setHeight( static_cast<tools::Long>(nBmpSzHeight * nScaleY) );
+ }
+
+ Point aPosOffs(
+ (aPaperSz.Width() / 2) - (aOutputSz.Width() / 2),
+ (aPaperSz.Height()/ 2) - (aOutputSz.Height() / 2));
+
+ aPosOffs.AdjustX(Print::nLeftMargin );
+ aPosOffs.AdjustY(Print::nTopMargin );
+
+ pPrinter->DrawBitmapEx( aPosOffs, aOutputSz, aDlgEx );
+
+ pPrinter->SetMapMode( aOldMap );
+ pPrinter->SetFont( aOldFont );
+}
+
+
+bool DlgEditor::AdjustPageSize()
+{
+ bool bAdjustedPageSize = false;
+ Reference< beans::XPropertySet > xPSet( m_xUnoControlDialogModel, UNO_QUERY );
+ if ( xPSet.is() )
+ {
+ sal_Int32 nFormXIn = 0, nFormYIn = 0, nFormWidthIn = 0, nFormHeightIn = 0;
+ xPSet->getPropertyValue( DLGED_PROP_POSITIONX ) >>= nFormXIn;
+ xPSet->getPropertyValue( DLGED_PROP_POSITIONY ) >>= nFormYIn;
+ xPSet->getPropertyValue( DLGED_PROP_WIDTH ) >>= nFormWidthIn;
+ xPSet->getPropertyValue( DLGED_PROP_HEIGHT ) >>= nFormHeightIn;
+
+ sal_Int32 nFormX, nFormY, nFormWidth, nFormHeight;
+ if ( pDlgEdForm && pDlgEdForm->TransformFormToSdrCoordinates( nFormXIn, nFormYIn, nFormWidthIn, nFormHeightIn, nFormX, nFormY, nFormWidth, nFormHeight ) )
+ {
+ Size aPageSizeDelta( 400, 300 );
+ aPageSizeDelta = rWindow.PixelToLogic( aPageSizeDelta, MapMode( MapUnit::Map100thMM ) );
+
+ sal_Int32 nNewPageWidth = nFormX + nFormWidth + aPageSizeDelta.Width();
+ sal_Int32 nNewPageHeight = nFormY + nFormHeight + aPageSizeDelta.Height();
+
+ Size aPageSizeMin( DLGED_PAGE_WIDTH_MIN, DLGED_PAGE_HEIGHT_MIN );
+ aPageSizeMin = rWindow.PixelToLogic( aPageSizeMin, MapMode( MapUnit::Map100thMM ) );
+ sal_Int32 nPageWidthMin = aPageSizeMin.Width();
+ sal_Int32 nPageHeightMin = aPageSizeMin.Height();
+
+ if ( nNewPageWidth < nPageWidthMin )
+ nNewPageWidth = nPageWidthMin;
+
+ if ( nNewPageHeight < nPageHeightMin )
+ nNewPageHeight = nPageHeightMin;
+
+ if ( pDlgEdPage )
+ {
+ Size aPageSize = pDlgEdPage->GetSize();
+ if ( nNewPageWidth != aPageSize.Width() || nNewPageHeight != aPageSize.Height() )
+ {
+ Size aNewPageSize( nNewPageWidth, nNewPageHeight );
+ pDlgEdPage->SetSize( aNewPageSize );
+ pDlgEdView->SetWorkArea( tools::Rectangle( Point( 0, 0 ), aNewPageSize ) );
+ bAdjustedPageSize = true;
+ }
+ }
+ }
+ }
+
+ return bAdjustedPageSize;
+}
+
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/dlged/dlgedclip.cxx b/basctl/source/dlged/dlgedclip.cxx
new file mode 100644
index 0000000000..931f10afe5
--- /dev/null
+++ b/basctl/source/dlged/dlgedclip.cxx
@@ -0,0 +1,109 @@
+/* -*- 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 <dlgedclip.hxx>
+#include <vcl/svapp.hxx>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
+#include <com/sun/star/datatransfer/XMimeContentType.hpp>
+#include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
+
+namespace basctl
+{
+
+using namespace comphelper;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::datatransfer::clipboard;
+DlgEdTransferableImpl::DlgEdTransferableImpl( const Sequence< DataFlavor >& aSeqFlavors, const Sequence< Any >& aSeqData )
+{
+ m_SeqFlavors = aSeqFlavors;
+ m_SeqData = aSeqData;
+}
+DlgEdTransferableImpl::~DlgEdTransferableImpl()
+{
+}
+bool DlgEdTransferableImpl::compareDataFlavors( const DataFlavor& lFlavor, const DataFlavor& rFlavor )
+{
+ // compare mime content types
+ Reference< uno::XComponentContext > xContext = getProcessComponentContext();
+ Reference< datatransfer::XMimeContentTypeFactory >
+ xMCntTypeFactory = MimeContentTypeFactory::create(xContext);
+
+ // compare full media types
+ Reference< datatransfer::XMimeContentType > xLType = xMCntTypeFactory->createMimeContentType( lFlavor.MimeType );
+ Reference< datatransfer::XMimeContentType > xRType = xMCntTypeFactory->createMimeContentType( rFlavor.MimeType );
+
+ OUString aLFullMediaType = xLType->getFullMediaType();
+ OUString aRFullMediaType = xRType->getFullMediaType();
+
+ bool bRet = aLFullMediaType.equalsIgnoreAsciiCase( aRFullMediaType );
+
+ return bRet;
+}
+
+// XTransferable
+Any SAL_CALL DlgEdTransferableImpl::getTransferData( const DataFlavor& rFlavor )
+{
+ const SolarMutexGuard aGuard;
+
+ if ( !isDataFlavorSupported( rFlavor ) )
+ throw UnsupportedFlavorException();
+
+ Any aData;
+
+ for ( sal_Int32 i = 0; i < m_SeqFlavors.getLength(); i++ )
+ {
+ if ( compareDataFlavors( m_SeqFlavors[i] , rFlavor ) )
+ {
+ aData = m_SeqData[i];
+ break;
+ }
+ }
+
+ return aData;
+}
+Sequence< DataFlavor > SAL_CALL DlgEdTransferableImpl::getTransferDataFlavors( )
+{
+ const SolarMutexGuard aGuard;
+
+ return m_SeqFlavors;
+}
+sal_Bool SAL_CALL DlgEdTransferableImpl::isDataFlavorSupported( const DataFlavor& rFlavor )
+{
+ const SolarMutexGuard aGuard;
+
+ for ( auto const & i : std::as_const(m_SeqFlavors) )
+ if ( compareDataFlavors( i, rFlavor ) )
+ return true;
+ return false;
+}
+
+// XClipboardOwner
+void SAL_CALL DlgEdTransferableImpl::lostOwnership( const Reference< XClipboard >&, const Reference< XTransferable >& )
+{
+ const SolarMutexGuard aGuard;
+
+ m_SeqFlavors = Sequence< DataFlavor >();
+ m_SeqData = Sequence< Any >();
+}
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/dlged/dlgedfac.cxx b/basctl/source/dlged/dlgedfac.cxx
new file mode 100644
index 0000000000..65e2965491
--- /dev/null
+++ b/basctl/source/dlged/dlgedfac.cxx
@@ -0,0 +1,229 @@
+/* -*- 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 <dlgedfac.hxx>
+#include <dlgedobj.hxx>
+#include <dlgeddef.hxx>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/ScrollBarOrientation.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <comphelper/processfactory.hxx>
+#include <utility>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+
+
+DlgEdFactory::DlgEdFactory( css::uno::Reference< css::frame::XModel > xModel ) : mxModel(std::move( xModel ))
+{
+ SdrObjFactory::InsertMakeObjectHdl( LINK(this, DlgEdFactory, MakeObject) );
+}
+
+
+DlgEdFactory::~DlgEdFactory() COVERITY_NOEXCEPT_FALSE
+{
+ SdrObjFactory::RemoveMakeObjectHdl( LINK(this, DlgEdFactory, MakeObject) );
+}
+
+
+IMPL_LINK( DlgEdFactory, MakeObject, SdrObjCreatorParams, aParams, rtl::Reference<SdrObject> )
+{
+ static const uno::Reference<lang::XMultiServiceFactory> xDialogSFact = [] {
+ uno::Reference<lang::XMultiServiceFactory> xFact;
+ uno::Reference< uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
+ uno::Reference< container::XNameContainer > xC( xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.awt.UnoControlDialogModel", xContext ), uno::UNO_QUERY );
+ if (xC.is())
+ xFact.set(xC, uno::UNO_QUERY);
+ return xFact;
+ }();
+
+ rtl::Reference<SdrObject> pNewObj;
+ if( (aParams.nInventor == SdrInventor::BasicDialog) &&
+ (aParams.nObjIdentifier >= SdrObjKind::BasicDialogPushButton) &&
+ (aParams.nObjIdentifier <= SdrObjKind::BasicDialogFormHorizontalScroll) )
+ {
+ switch( aParams.nObjIdentifier )
+ {
+ case SdrObjKind::BasicDialogPushButton:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlButtonModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogRadioButton:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlRadioButtonModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogFormRadio:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.RadioButton", xDialogSFact );
+ static_cast< DlgEdObj* >( pNewObj.get() )->MakeDataAware( mxModel );
+ break;
+ case SdrObjKind::BasicDialogCheckbox:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlCheckBoxModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogFormCheck:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.CheckBox", xDialogSFact );
+ static_cast< DlgEdObj* >( pNewObj.get() )->MakeDataAware( mxModel );
+ break;
+ case SdrObjKind::BasicDialogListbox:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlListBoxModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogFormList:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.ListBox", xDialogSFact );
+ static_cast< DlgEdObj* >( pNewObj.get() )->MakeDataAware( mxModel );
+ break;
+ case SdrObjKind::BasicDialogFormCombo:
+ case SdrObjKind::BasicDialogCombobox:
+ {
+ rtl::Reference<DlgEdObj> pNew;
+ if ( aParams.nObjIdentifier == SdrObjKind::BasicDialogCombobox )
+ pNew = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlComboBoxModel", xDialogSFact );
+ else
+ {
+ pNew = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.ComboBox", xDialogSFact );
+ pNew->MakeDataAware( mxModel );
+ }
+ pNewObj = pNew;
+ try
+ {
+ uno::Reference< beans::XPropertySet > xPSet(pNew->GetUnoControlModel(), uno::UNO_QUERY);
+ if (xPSet.is())
+ {
+ xPSet->setPropertyValue( DLGED_PROP_DROPDOWN, uno::Any(true));
+ }
+ }
+ catch(...)
+ {
+ }
+ }
+ break;
+ case SdrObjKind::BasicDialogGroupBox:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlGroupBoxModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogEdit:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlEditModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogFixedText:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlFixedTextModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogImageControl:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlImageControlModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogProgressbar:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlProgressBarModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogHorizontalScrollbar:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlScrollBarModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogFormHorizontalScroll:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.ScrollBar", xDialogSFact );
+ static_cast< DlgEdObj* >( pNewObj.get() )->MakeDataAware( mxModel );
+ break;
+ case SdrObjKind::BasicDialogFormVerticalScroll:
+ case SdrObjKind::BasicDialogVerticalScrollbar:
+ {
+ rtl::Reference<DlgEdObj> pNew;
+ if ( aParams.nObjIdentifier == SdrObjKind::BasicDialogVerticalScrollbar )
+ pNew = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlScrollBarModel", xDialogSFact );
+ else
+ {
+ pNew = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.ScrollBar", xDialogSFact );
+ pNew->MakeDataAware( mxModel );
+ }
+ pNewObj = pNew;
+ // set vertical orientation
+ try
+ {
+ uno::Reference< beans::XPropertySet > xPSet(pNew->GetUnoControlModel(), uno::UNO_QUERY);
+ if (xPSet.is())
+ {
+ xPSet->setPropertyValue( DLGED_PROP_ORIENTATION, uno::Any(sal_Int32(css::awt::ScrollBarOrientation::VERTICAL)) );
+ }
+ }
+ catch(...)
+ {
+ }
+ } break;
+ case SdrObjKind::BasicDialogHorizontalFixedLine:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlFixedLineModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogVerticalFixedLine:
+ {
+ rtl::Reference<DlgEdObj> pNew = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlFixedLineModel", xDialogSFact );
+ pNewObj = pNew;
+ // set vertical orientation
+ try
+ {
+ uno::Reference< beans::XPropertySet > xPSet(pNew->GetUnoControlModel(), uno::UNO_QUERY);
+ if (xPSet.is())
+ {
+ xPSet->setPropertyValue( DLGED_PROP_ORIENTATION, uno::Any(sal_Int32(1)) );
+ }
+ }
+ catch(...)
+ {
+ }
+ } break;
+ case SdrObjKind::BasicDialogDateField:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlDateFieldModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogTimeField:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlTimeFieldModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogNumericField:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlNumericFieldModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogCurencyField:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlCurrencyFieldModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogFormattedField:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlFormattedFieldModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogPatternField:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlPatternFieldModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogFileControl:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlFileControlModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogSpinButton:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlSpinButtonModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogFormSpin:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.SpinButton", xDialogSFact );
+ static_cast< DlgEdObj* >( pNewObj.get() )->MakeDataAware( mxModel );
+ break;
+ case SdrObjKind::BasicDialogTreeControl:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.tree.TreeControlModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogGridControl:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.grid.UnoControlGridModel", xDialogSFact );
+ break;
+ case SdrObjKind::BasicDialogHyperlinkControl:
+ pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlFixedHyperlinkModel", xDialogSFact );
+ break;
+ default:
+ break;
+
+ }
+ }
+ return pNewObj;
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/dlged/dlgedfunc.cxx b/basctl/source/dlged/dlgedfunc.cxx
new file mode 100644
index 0000000000..7f1a0388ee
--- /dev/null
+++ b/basctl/source/dlged/dlgedfunc.cxx
@@ -0,0 +1,548 @@
+/* -*- 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 <svtools/scrolladaptor.hxx>
+#include <svx/svdview.hxx>
+#include <dlgedfunc.hxx>
+#include <dlged.hxx>
+#include <dlgedview.hxx>
+#include <vcl/seleng.hxx>
+
+namespace basctl
+{
+
+IMPL_LINK_NOARG( DlgEdFunc, ScrollTimeout, Timer *, void )
+{
+ vcl::Window& rWindow = rParent.GetWindow();
+ Point aPos = rWindow.ScreenToOutputPixel( rWindow.GetPointerPosPixel() );
+ aPos = rWindow.PixelToLogic( aPos );
+ ForceScroll( aPos );
+}
+
+void DlgEdFunc::ForceScroll( const Point& rPos )
+{
+ aScrollTimer.Stop();
+
+ vcl::Window& rWindow = rParent.GetWindow();
+
+ static const Point aDefPoint;
+ tools::Rectangle aOutRect( aDefPoint, rWindow.GetOutputSizePixel() );
+ aOutRect = rWindow.PixelToLogic( aOutRect );
+
+ ScrollAdaptor* pHScroll = rParent.GetHScroll();
+ ScrollAdaptor* pVScroll = rParent.GetVScroll();
+ tools::Long nDeltaX = pHScroll->GetLineSize();
+ tools::Long nDeltaY = pVScroll->GetLineSize();
+
+ if( !aOutRect.Contains( rPos ) )
+ {
+ if( rPos.X() < aOutRect.Left() )
+ nDeltaX = -nDeltaX;
+ else if( rPos.X() <= aOutRect.Right() )
+ nDeltaX = 0;
+
+ if( rPos.Y() < aOutRect.Top() )
+ nDeltaY = -nDeltaY;
+ else if( rPos.Y() <= aOutRect.Bottom() )
+ nDeltaY = 0;
+
+ if( nDeltaX )
+ pHScroll->SetThumbPos( pHScroll->GetThumbPos() + nDeltaX );
+ if( nDeltaY )
+ pVScroll->SetThumbPos( pVScroll->GetThumbPos() + nDeltaY );
+
+ if( nDeltaX )
+ rParent.DoScroll();
+ if( nDeltaY )
+ rParent.DoScroll();
+ }
+
+ aScrollTimer.Start();
+}
+
+DlgEdFunc::DlgEdFunc (DlgEditor& rParent_) :
+ rParent(rParent_), aScrollTimer("basctl DlgEdFunc aScrollTimer")
+{
+ aScrollTimer.SetInvokeHandler( LINK( this, DlgEdFunc, ScrollTimeout ) );
+ aScrollTimer.SetTimeout( SELENG_AUTOREPEAT_INTERVAL );
+}
+
+DlgEdFunc::~DlgEdFunc()
+{
+}
+
+void DlgEdFunc::MouseButtonDown( const MouseEvent& )
+{
+}
+
+bool DlgEdFunc::MouseButtonUp( const MouseEvent& )
+{
+ aScrollTimer.Stop();
+ return true;
+}
+
+void DlgEdFunc::MouseMove( const MouseEvent& )
+{
+}
+
+bool DlgEdFunc::KeyInput( const KeyEvent& rKEvt )
+{
+ bool bReturn = false;
+
+ SdrView& rView = rParent.GetView();
+ vcl::Window& rWindow = rParent.GetWindow();
+
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+ sal_uInt16 nCode = aCode.GetCode();
+
+ switch ( nCode )
+ {
+ case KEY_ESCAPE:
+ {
+ if ( rView.IsAction() )
+ {
+ rView.BrkAction();
+ bReturn = true;
+ }
+ else if ( rView.AreObjectsMarked() )
+ {
+ const SdrHdlList& rHdlList = rView.GetHdlList();
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+ if ( pHdl )
+ const_cast<SdrHdlList&>(rHdlList).ResetFocusHdl();
+ else
+ rView.UnmarkAll();
+
+ bReturn = true;
+ }
+ }
+ break;
+ case KEY_TAB:
+ {
+ if ( !aCode.IsMod1() && !aCode.IsMod2() )
+ {
+ // mark next object
+ if ( !rView.MarkNextObj( !aCode.IsShift() ) )
+ {
+ // if no next object, mark first/last
+ rView.UnmarkAllObj();
+ rView.MarkNextObj( !aCode.IsShift() );
+ }
+
+ if ( rView.AreObjectsMarked() )
+ rView.MakeVisible( rView.GetAllMarkedRect(), rWindow );
+
+ bReturn = true;
+ }
+ else if ( aCode.IsMod1() )
+ {
+ // selected handle
+ const SdrHdlList& rHdlList = rView.GetHdlList();
+ const_cast<SdrHdlList&>(rHdlList).TravelFocusHdl( !aCode.IsShift() );
+
+ // guarantee visibility of focused handle
+ if (SdrHdl* pHdl = rHdlList.GetFocusHdl())
+ {
+ Point aHdlPosition( pHdl->GetPos() );
+ tools::Rectangle aVisRect( aHdlPosition - Point( 100, 100 ), Size( 200, 200 ) );
+ rView.MakeVisible( aVisRect, rWindow );
+ }
+
+ bReturn = true;
+ }
+ }
+ break;
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ {
+ tools::Long nX = 0;
+ tools::Long nY = 0;
+
+ if ( nCode == KEY_UP )
+ {
+ // scroll up
+ nX = 0;
+ nY = -1;
+ }
+ else if ( nCode == KEY_DOWN )
+ {
+ // scroll down
+ nX = 0;
+ nY = 1;
+ }
+ else if ( nCode == KEY_LEFT )
+ {
+ // scroll left
+ nX = -1;
+ nY = 0;
+ }
+ else if ( nCode == KEY_RIGHT )
+ {
+ // scroll right
+ nX = 1;
+ nY = 0;
+ }
+
+ if ( rView.AreObjectsMarked() && !aCode.IsMod1() )
+ {
+ if ( aCode.IsMod2() )
+ {
+ // move in 1 pixel distance
+ Size aPixelSize = rWindow.PixelToLogic(Size(1, 1));
+ nX *= aPixelSize.Width();
+ nY *= aPixelSize.Height();
+ }
+ else
+ {
+ // move in 1 mm distance
+ nX *= 100;
+ nY *= 100;
+ }
+
+ const SdrHdlList& rHdlList = rView.GetHdlList();
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+
+ if ( pHdl == nullptr )
+ {
+ // no handle selected
+ if ( rView.IsMoveAllowed() )
+ {
+ // restrict movement to work area
+ const tools::Rectangle& rWorkArea = rView.GetWorkArea();
+
+ if ( !rWorkArea.IsEmpty() )
+ {
+ tools::Rectangle aMarkRect( rView.GetMarkedObjRect() );
+ aMarkRect.Move( nX, nY );
+
+ if ( !rWorkArea.Contains( aMarkRect ) )
+ {
+ if ( aMarkRect.Left() < rWorkArea.Left() )
+ nX += rWorkArea.Left() - aMarkRect.Left();
+
+ if ( aMarkRect.Right() > rWorkArea.Right() )
+ nX -= aMarkRect.Right() - rWorkArea.Right();
+
+ if ( aMarkRect.Top() < rWorkArea.Top() )
+ nY += rWorkArea.Top() - aMarkRect.Top();
+
+ if ( aMarkRect.Bottom() > rWorkArea.Bottom() )
+ nY -= aMarkRect.Bottom() - rWorkArea.Bottom();
+ }
+ }
+
+ if ( nX != 0 || nY != 0 )
+ {
+ rView.MoveAllMarked( Size( nX, nY ) );
+ rView.MakeVisible( rView.GetAllMarkedRect(), rWindow );
+ }
+ }
+ }
+ else if (nX || nY)
+ {
+ Point aStartPoint(pHdl->GetPos());
+ Point aEndPoint(pHdl->GetPos() + Point(nX, nY));
+ const SdrDragStat& rDragStat = rView.GetDragStat();
+
+ // start dragging
+ rView.BegDragObj(aStartPoint, nullptr, pHdl, 0);
+
+ if (rView.IsDragObj())
+ {
+ bool const bWasNoSnap = rDragStat.IsNoSnap();
+ bool const bWasSnapEnabled = rView.IsSnapEnabled();
+
+ // switch snapping off
+ if (!bWasNoSnap)
+ const_cast<SdrDragStat&>(rDragStat).SetNoSnap();
+ if (bWasSnapEnabled)
+ rView.SetSnapEnabled(false);
+
+ rView.MovAction(aEndPoint);
+ rView.EndDragObj();
+
+ // restore snap
+ if (!bWasNoSnap)
+ const_cast<SdrDragStat&>(rDragStat).SetNoSnap(bWasNoSnap);
+ if (bWasSnapEnabled)
+ rView.SetSnapEnabled(bWasSnapEnabled);
+ }
+
+ // make moved handle visible
+ tools::Rectangle aVisRect(aEndPoint - Point(100, 100), Size(200, 200));
+ rView.MakeVisible(aVisRect, rWindow);
+ }
+ }
+ else
+ {
+ // scroll page
+ ScrollAdaptor* pScrollBar = ( nX != 0 ) ? rParent.GetHScroll() : rParent.GetVScroll();
+ if ( pScrollBar )
+ {
+ tools::Long nRangeMin = pScrollBar->GetRangeMin();
+ tools::Long nRangeMax = pScrollBar->GetRangeMax();
+ tools::Long nThumbPos = pScrollBar->GetThumbPos() + ( ( nX != 0 ) ? nX : nY ) * pScrollBar->GetLineSize();
+ if ( nThumbPos < nRangeMin )
+ nThumbPos = nRangeMin;
+ if ( nThumbPos > nRangeMax )
+ nThumbPos = nRangeMax;
+ pScrollBar->SetThumbPos( nThumbPos );
+ rParent.DoScroll();
+ }
+ }
+
+ bReturn = true;
+ }
+ break;
+ default:
+ {
+ }
+ break;
+ }
+
+ if ( bReturn )
+ rWindow.ReleaseMouse();
+
+ return bReturn;
+}
+
+DlgEdFuncInsert::DlgEdFuncInsert (DlgEditor& rParent_) :
+ DlgEdFunc(rParent_)
+{
+ rParent.GetView().SetCreateMode();
+}
+
+DlgEdFuncInsert::~DlgEdFuncInsert()
+{
+ rParent.GetView().SetEditMode();
+}
+
+void DlgEdFuncInsert::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if( !rMEvt.IsLeft() )
+ return;
+
+ SdrView& rView = rParent.GetView();
+ vcl::Window& rWindow = rParent.GetWindow();
+ rView.SetActualWin(rWindow.GetOutDev());
+
+ Point aPos = rWindow.PixelToLogic( rMEvt.GetPosPixel() );
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width());
+ sal_uInt16 nDrgLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width());
+
+ rWindow.CaptureMouse();
+
+ if ( rMEvt.IsLeft() && rMEvt.GetClicks() == 1 )
+ {
+ SdrHdl* pHdl = rView.PickHandle(aPos);
+
+ // if selected object was hit, drag object
+ if ( pHdl!=nullptr || rView.IsMarkedHit(aPos, nHitLog) )
+ rView.BegDragObj(aPos, nullptr, pHdl, nDrgLog);
+ else if ( rView.AreObjectsMarked() )
+ rView.UnmarkAll();
+
+ // if no action, create object
+ if ( !rView.IsAction() )
+ rView.BegCreateObj(aPos);
+ }
+ else if ( rMEvt.IsLeft() && rMEvt.GetClicks() == 2 )
+ {
+ // if object was hit, show property browser
+ if ( rView.IsMarkedHit(aPos, nHitLog) && rParent.GetMode() != DlgEditor::READONLY )
+ rParent.ShowProperties();
+ }
+}
+
+bool DlgEdFuncInsert::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ DlgEdFunc::MouseButtonUp( rMEvt );
+
+ SdrView& rView = rParent.GetView();
+ vcl::Window& rWindow = rParent.GetWindow();
+ rView.SetActualWin(rWindow.GetOutDev());
+
+ rWindow.ReleaseMouse();
+
+ // object creation active?
+ if ( rView.IsCreateObj() )
+ {
+ rView.EndCreateObj(SdrCreateCmd::ForceEnd);
+
+ if ( !rView.AreObjectsMarked() )
+ {
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width());
+ Point aPos( rWindow.PixelToLogic( rMEvt.GetPosPixel() ) );
+ rView.MarkObj(aPos, nHitLog);
+ }
+
+ return rView.AreObjectsMarked();
+ }
+ else
+ {
+ if ( rView.IsDragObj() )
+ rView.EndDragObj( rMEvt.IsMod1() );
+ return true;
+ }
+}
+
+void DlgEdFuncInsert::MouseMove( const MouseEvent& rMEvt )
+{
+ SdrView& rView = rParent.GetView();
+ vcl::Window& rWindow = rParent.GetWindow();
+ rView.SetActualWin(rWindow.GetOutDev());
+
+ Point aPos = rWindow.PixelToLogic(rMEvt.GetPosPixel());
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width());
+
+ if (rView.IsAction())
+ {
+ ForceScroll(aPos);
+ rView.MovAction(aPos);
+ }
+
+ rWindow.SetPointer( rView.GetPreferredPointer( aPos, rWindow.GetOutDev(), nHitLog ) );
+}
+
+DlgEdFuncSelect::DlgEdFuncSelect (DlgEditor& rParent_) :
+ DlgEdFunc(rParent_)
+{
+}
+
+DlgEdFuncSelect::~DlgEdFuncSelect()
+{
+}
+
+void DlgEdFuncSelect::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ // get view from parent
+ SdrView& rView = rParent.GetView();
+ vcl::Window& rWindow = rParent.GetWindow();
+ rView.SetActualWin(rWindow.GetOutDev());
+
+ sal_uInt16 nDrgLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width());
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width());
+ Point aMDPos = rWindow.PixelToLogic(rMEvt.GetPosPixel());
+
+ if ( rMEvt.IsLeft() && rMEvt.GetClicks() == 1 )
+ {
+ SdrHdl* pHdl = rView.PickHandle(aMDPos);
+
+ // hit selected object?
+ if ( pHdl!=nullptr || rView.IsMarkedHit(aMDPos, nHitLog) )
+ {
+ rView.BegDragObj(aMDPos, nullptr, pHdl, nDrgLog);
+ }
+ else
+ {
+ // if not multi selection, unmark all
+ if ( !rMEvt.IsShift() )
+ rView.UnmarkAll();
+ else
+ {
+ SdrPageView* pPV;
+ SdrObject* pObj = rView.PickObj(aMDPos, nHitLog, pPV);
+ if (pObj)
+ {
+ //if (dynamic_cast<DlgEdForm*>(pObj))
+ // rView.UnmarkAll();
+ //else
+ // rParent.UnmarkDialog();
+ }
+ }
+
+ if ( rView.MarkObj(aMDPos, nHitLog) )
+ {
+ // drag object
+ pHdl = rView.PickHandle(aMDPos);
+ rView.BegDragObj(aMDPos, nullptr, pHdl, nDrgLog);
+ }
+ else
+ {
+ // select object
+ rView.BegMarkObj(aMDPos);
+ }
+ }
+ }
+ else if ( rMEvt.IsLeft() && rMEvt.GetClicks() == 2 )
+ {
+ // if object was hit, show property browser
+ if ( rView.IsMarkedHit(aMDPos, nHitLog) && rParent.GetMode() != DlgEditor::READONLY )
+ rParent.ShowProperties();
+ }
+}
+
+bool DlgEdFuncSelect::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ DlgEdFunc::MouseButtonUp( rMEvt );
+
+ // get view from parent
+ SdrView& rView = rParent.GetView();
+ vcl::Window& rWindow = rParent.GetWindow();
+ rView.SetActualWin(rWindow.GetOutDev());
+
+ Point aPnt = rWindow.PixelToLogic(rMEvt.GetPosPixel());
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width());
+
+ if ( rMEvt.IsLeft() )
+ {
+ if (rView.IsDragObj())
+ {
+ // object was dragged
+ rView.EndDragObj( rMEvt.IsMod1() );
+ rView.ForceMarkedToAnotherPage();
+ }
+ else if (rView.IsAction())
+ {
+ rView.EndAction();
+ }
+ }
+
+ rWindow.SetPointer( rView.GetPreferredPointer( aPnt, rWindow.GetOutDev(), nHitLog ) );
+ rWindow.ReleaseMouse();
+
+ return true;
+}
+
+void DlgEdFuncSelect::MouseMove( const MouseEvent& rMEvt )
+{
+ SdrView& rView = rParent.GetView();
+ vcl::Window& rWindow = rParent.GetWindow();
+ rView.SetActualWin(rWindow.GetOutDev());
+
+ Point aPnt = rWindow.PixelToLogic(rMEvt.GetPosPixel());
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width());
+
+ if ( rView.IsAction() )
+ {
+ Point aPix = rMEvt.GetPosPixel();
+ Point aPnt_ = rWindow.PixelToLogic(aPix);
+
+ ForceScroll(aPnt_);
+ rView.MovAction(aPnt_);
+ }
+
+ rWindow.SetPointer( rView.GetPreferredPointer( aPnt, rWindow.GetOutDev(), nHitLog ) );
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/dlged/dlgedlist.cxx b/basctl/source/dlged/dlgedlist.cxx
new file mode 100644
index 0000000000..6b9cebfe89
--- /dev/null
+++ b/basctl/source/dlged/dlgedlist.cxx
@@ -0,0 +1,80 @@
+/* -*- 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 <dlgedlist.hxx>
+#include <dlgedobj.hxx>
+
+namespace basctl
+{
+
+// DlgEdPropListenerImpl
+DlgEdPropListenerImpl::DlgEdPropListenerImpl (DlgEdObj& rObj) :
+ rDlgEdObj(rObj)
+{
+}
+
+DlgEdPropListenerImpl::~DlgEdPropListenerImpl()
+{
+}
+
+// XEventListener
+void SAL_CALL DlgEdPropListenerImpl::disposing( const css::lang::EventObject& )
+{
+}
+
+// XPropertyChangeListener
+void SAL_CALL DlgEdPropListenerImpl::propertyChange( const css::beans::PropertyChangeEvent& evt )
+{
+ rDlgEdObj._propertyChange( evt );
+}
+
+// DlgEdEvtContListenerImpl
+DlgEdEvtContListenerImpl::DlgEdEvtContListenerImpl (DlgEdObj& rObj) :
+ rDlgEdObj(rObj)
+{
+}
+
+DlgEdEvtContListenerImpl::~DlgEdEvtContListenerImpl()
+{
+}
+
+// XEventListener
+void SAL_CALL DlgEdEvtContListenerImpl::disposing( const css::lang::EventObject& )
+{
+}
+
+// XContainerListener
+void SAL_CALL DlgEdEvtContListenerImpl::elementInserted(const css::container::ContainerEvent& /*Event*/)
+{
+ rDlgEdObj._elementInserted();
+}
+
+void SAL_CALL DlgEdEvtContListenerImpl::elementReplaced(const css::container::ContainerEvent& /*Event*/)
+{
+ rDlgEdObj._elementReplaced();
+}
+
+void SAL_CALL DlgEdEvtContListenerImpl::elementRemoved(const css::container::ContainerEvent& /*Event*/)
+{
+ rDlgEdObj._elementRemoved();
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/dlged/dlgedmod.cxx b/basctl/source/dlged/dlgedmod.cxx
new file mode 100644
index 0000000000..017e4b16c7
--- /dev/null
+++ b/basctl/source/dlged/dlgedmod.cxx
@@ -0,0 +1,36 @@
+/* -*- 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 <dlgedmod.hxx>
+#include <dlgedpage.hxx>
+
+namespace basctl
+{
+DlgEdModel::DlgEdModel() {}
+
+DlgEdModel::~DlgEdModel() {}
+
+rtl::Reference<SdrPage> DlgEdModel::AllocPage(bool bMasterPage)
+{
+ return new DlgEdPage(*this, bMasterPage);
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/dlged/dlgedobj.cxx b/basctl/source/dlged/dlgedobj.cxx
new file mode 100644
index 0000000000..5b87393e51
--- /dev/null
+++ b/basctl/source/dlged/dlgedobj.cxx
@@ -0,0 +1,1705 @@
+/* -*- 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 <sal/log.hxx>
+
+#include <cassert>
+
+#include <dlged.hxx>
+#include <dlgeddef.hxx>
+#include <dlgedlist.hxx>
+#include <dlgedobj.hxx>
+#include <dlgedpage.hxx>
+#include <dlgedview.hxx>
+#include <localizationmgr.hxx>
+#include <strings.hxx>
+
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/form/binding/XBindableValue.hpp>
+#include <com/sun/star/form/binding/XValueBinding.hpp>
+#include <com/sun/star/form/binding/XListEntrySink.hpp>
+#include <com/sun/star/awt/XUnoControlContainer.hpp>
+#include <com/sun/star/awt/XVclContainerPeer.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/script/XScriptEventsSupplier.hpp>
+#include <com/sun/star/table/CellAddress.hpp>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/functional.hxx>
+#include <svx/svdpagv.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/debug.hxx>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::script;
+
+
+DlgEditor& DlgEdObj::GetDialogEditor ()
+{
+ if (DlgEdForm* pFormThis = dynamic_cast<DlgEdForm*>(this))
+ return pFormThis->GetDlgEditor();
+ else
+ return pDlgEdForm->GetDlgEditor();
+}
+
+DlgEdObj::DlgEdObj(SdrModel& rSdrModel)
+: SdrUnoObj(rSdrModel, OUString())
+ ,bIsListening(false)
+{
+}
+
+DlgEdObj::DlgEdObj(SdrModel& rSdrModel, DlgEdObj const & rSource)
+: SdrUnoObj(rSdrModel, rSource)
+ ,bIsListening(false)
+{
+ // set parent form
+ pDlgEdForm = rSource.pDlgEdForm;
+
+ // add child to parent form
+ pDlgEdForm->AddChild( this );
+
+ Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY );
+ if ( xPSet.is() )
+ {
+ // set new name
+ OUString aOUniqueName( GetUniqueName() );
+ Any aUniqueName;
+ aUniqueName <<= aOUniqueName;
+ xPSet->setPropertyValue( DLGED_PROP_NAME, aUniqueName );
+
+ Reference< container::XNameContainer > xCont( GetDlgEdForm()->GetUnoControlModel() , UNO_QUERY );
+ if ( xCont.is() )
+ {
+ // set tabindex
+ Sequence< OUString > aNames = xCont->getElementNames();
+ xPSet->setPropertyValue( DLGED_PROP_TABINDEX, Any(static_cast<sal_Int16>(aNames.getLength())) );
+
+ // insert control model in dialog model
+ Reference< awt::XControlModel > xCtrl( xPSet , UNO_QUERY );
+ xCont->insertByName( aOUniqueName, Any(xCtrl) );
+
+ pDlgEdForm->UpdateTabOrderAndGroups();
+ }
+ }
+
+ // start listening
+ StartListening();
+}
+
+DlgEdObj::DlgEdObj(
+ SdrModel& rSdrModel,
+ const OUString& rModelName,
+ const css::uno::Reference< css::lang::XMultiServiceFactory >& rxSFac)
+: SdrUnoObj(rSdrModel, rModelName, rxSFac)
+ ,bIsListening(false)
+{
+}
+
+DlgEdObj::~DlgEdObj()
+{
+ if ( isListening() )
+ EndListening(true);
+}
+
+namespace
+{
+ /* returns the DlgEdForm which the given DlgEdObj belongs to
+ (which might in fact be the object itself)
+
+ Failure to obtain the form will be reported with an assertion in the non-product
+ version.
+ */
+ bool lcl_getDlgEdForm( DlgEdObj* _pObject, DlgEdForm*& _out_pDlgEdForm )
+ {
+ _out_pDlgEdForm = dynamic_cast< DlgEdForm* >( _pObject );
+ if ( !_out_pDlgEdForm )
+ _out_pDlgEdForm = _pObject->GetDlgEdForm();
+ DBG_ASSERT( _out_pDlgEdForm, "lcl_getDlgEdForm: no form!" );
+ return ( _out_pDlgEdForm != nullptr );
+ }
+}
+
+uno::Reference< awt::XControl > DlgEdObj::GetControl() const
+{
+ uno::Reference< awt::XControl > xControl;
+ if (DlgEdForm const* pForm = GetDlgEdForm())
+ {
+ DlgEditor const& rEditor = pForm->GetDlgEditor();
+ xControl = GetUnoControl(rEditor.GetView(), *rEditor.GetWindow().GetOutDev());
+ }
+ return xControl;
+}
+
+bool DlgEdObj::TransformSdrToControlCoordinates(
+ sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn,
+ sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut )
+{
+ // input position and size
+ Size aPos( nXIn, nYIn );
+ Size aSize( nWidthIn, nHeightIn );
+
+ // form position
+ DlgEdForm* pForm = nullptr;
+ if ( !lcl_getDlgEdForm( this, pForm ) )
+ return false;
+ tools::Rectangle aFormRect = pForm->GetSnapRect();
+ Size aFormPos( aFormRect.Left(), aFormRect.Top() );
+
+ // convert 100th_mm to pixel
+ OutputDevice* pDevice = Application::GetDefaultDevice();
+ DBG_ASSERT( pDevice, "DlgEdObj::TransformSdrToControlCoordinates: missing default device!" );
+ if ( !pDevice )
+ return false;
+ aPos = pDevice->LogicToPixel( aPos, MapMode( MapUnit::Map100thMM ) );
+ aSize = pDevice->LogicToPixel( aSize, MapMode( MapUnit::Map100thMM ) );
+ aFormPos = pDevice->LogicToPixel( aFormPos, MapMode( MapUnit::Map100thMM ) );
+
+ // subtract form position
+ aPos.AdjustWidth( -(aFormPos.Width()) );
+ aPos.AdjustHeight( -(aFormPos.Height()) );
+
+ // take window borders into account
+ Reference< beans::XPropertySet > xPSetForm( pForm->GetUnoControlModel(), UNO_QUERY );
+ DBG_ASSERT( xPSetForm.is(), "DlgEdObj::TransformFormToSdrCoordinates: no form property set!" );
+ if ( !xPSetForm.is() )
+ return false;
+ bool bDecoration = true;
+ xPSetForm->getPropertyValue( DLGED_PROP_DECORATION ) >>= bDecoration;
+ if( bDecoration )
+ {
+ awt::DeviceInfo aDeviceInfo = pForm->getDeviceInfo();
+ aPos.AdjustWidth( -(aDeviceInfo.LeftInset) );
+ aPos.AdjustHeight( -(aDeviceInfo.TopInset) );
+ }
+
+ // convert pixel to logic units
+ aPos = pDevice->PixelToLogic(aPos, MapMode(MapUnit::MapAppFont));
+ aSize = pDevice->PixelToLogic(aSize, MapMode(MapUnit::MapAppFont));
+
+ // set out parameters
+ nXOut = aPos.Width();
+ nYOut = aPos.Height();
+ nWidthOut = aSize.Width();
+ nHeightOut = aSize.Height();
+
+ return true;
+}
+
+bool DlgEdObj::TransformSdrToFormCoordinates(
+ sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn,
+ sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut )
+{
+ // input position and size
+ Size aPos( nXIn, nYIn );
+ Size aSize( nWidthIn, nHeightIn );
+
+ // convert 100th_mm to pixel
+ OutputDevice* pDevice = Application::GetDefaultDevice();
+ DBG_ASSERT( pDevice, "DlgEdObj::TransformSdrToFormCoordinates: missing default device!" );
+ if ( !pDevice )
+ return false;
+ aPos = pDevice->LogicToPixel( aPos, MapMode( MapUnit::Map100thMM ) );
+ aSize = pDevice->LogicToPixel( aSize, MapMode( MapUnit::Map100thMM ) );
+
+ // take window borders into account
+ DlgEdForm* pForm = nullptr;
+ if ( !lcl_getDlgEdForm( this, pForm ) )
+ return false;
+
+ // take window borders into account
+ Reference< beans::XPropertySet > xPSetForm( pForm->GetUnoControlModel(), UNO_QUERY );
+ DBG_ASSERT( xPSetForm.is(), "DlgEdObj::TransformFormToSdrCoordinates: no form property set!" );
+ if ( !xPSetForm.is() )
+ return false;
+ bool bDecoration = true;
+ xPSetForm->getPropertyValue( DLGED_PROP_DECORATION ) >>= bDecoration;
+ if( bDecoration )
+ {
+ awt::DeviceInfo aDeviceInfo = pForm->getDeviceInfo();
+ aSize.AdjustWidth( -(aDeviceInfo.LeftInset + aDeviceInfo.RightInset) );
+ aSize.AdjustHeight( -(aDeviceInfo.TopInset + aDeviceInfo.BottomInset) );
+ }
+ // convert pixel to logic units
+ aPos = pDevice->PixelToLogic(aPos, MapMode(MapUnit::MapAppFont));
+ aSize = pDevice->PixelToLogic(aSize, MapMode(MapUnit::MapAppFont));
+
+ // set out parameters
+ nXOut = aPos.Width();
+ nYOut = aPos.Height();
+ nWidthOut = aSize.Width();
+ nHeightOut = aSize.Height();
+
+ return true;
+}
+
+bool DlgEdObj::TransformControlToSdrCoordinates(
+ sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn,
+ sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut )
+{
+ // input position and size
+ Size aPos( nXIn, nYIn );
+ Size aSize( nWidthIn, nHeightIn );
+
+ // form position
+ DlgEdForm* pForm = nullptr;
+ if ( !lcl_getDlgEdForm( this, pForm ) )
+ return false;
+
+ Reference< beans::XPropertySet > xPSetForm( pForm->GetUnoControlModel(), UNO_QUERY );
+ DBG_ASSERT( xPSetForm.is(), "DlgEdObj::TransformControlToSdrCoordinates: no form property set!" );
+ if ( !xPSetForm.is() )
+ return false;
+ sal_Int32 nFormX = 0, nFormY = 0;
+ xPSetForm->getPropertyValue( DLGED_PROP_POSITIONX ) >>= nFormX;
+ xPSetForm->getPropertyValue( DLGED_PROP_POSITIONY ) >>= nFormY;
+ Size aFormPos( nFormX, nFormY );
+
+ // convert logic units to pixel
+ OutputDevice* pDevice = Application::GetDefaultDevice();
+ DBG_ASSERT( pDevice, "DlgEdObj::TransformControlToSdrCoordinates: missing default device!" );
+ if ( !pDevice )
+ return false;
+ aPos = pDevice->LogicToPixel(aPos, MapMode(MapUnit::MapAppFont));
+ aSize = pDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont));
+ aFormPos = pDevice->LogicToPixel(aFormPos, MapMode(MapUnit::MapAppFont));
+
+ // add form position
+ aPos.AdjustWidth(aFormPos.Width() );
+ aPos.AdjustHeight(aFormPos.Height() );
+
+ // take window borders into account
+ bool bDecoration = true;
+ xPSetForm->getPropertyValue( DLGED_PROP_DECORATION ) >>= bDecoration;
+ if( bDecoration )
+ {
+ awt::DeviceInfo aDeviceInfo = pForm->getDeviceInfo();
+ aPos.AdjustWidth(aDeviceInfo.LeftInset );
+ aPos.AdjustHeight(aDeviceInfo.TopInset );
+ }
+
+ // convert pixel to 100th_mm
+ aPos = pDevice->PixelToLogic( aPos, MapMode( MapUnit::Map100thMM ) );
+ aSize = pDevice->PixelToLogic( aSize, MapMode( MapUnit::Map100thMM ) );
+
+ // set out parameters
+ nXOut = aPos.Width();
+ nYOut = aPos.Height();
+ nWidthOut = aSize.Width();
+ nHeightOut = aSize.Height();
+
+ return true;
+}
+
+bool DlgEdObj::TransformFormToSdrCoordinates(
+ sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn,
+ sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut )
+{
+ // input position and size
+ Size aPos( nXIn, nYIn );
+ Size aSize( nWidthIn, nHeightIn );
+
+ // convert logic units to pixel
+ OutputDevice* pDevice = Application::GetDefaultDevice();
+ DBG_ASSERT( pDevice, "DlgEdObj::TransformFormToSdrCoordinates: missing default device!" );
+ if ( !pDevice )
+ return false;
+
+ // take window borders into account
+ DlgEdForm* pForm = nullptr;
+ if ( !lcl_getDlgEdForm( this, pForm ) )
+ return false;
+
+ aPos = pDevice->LogicToPixel(aPos, MapMode(MapUnit::MapAppFont));
+ aSize = pDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont));
+
+ // take window borders into account
+ Reference< beans::XPropertySet > xPSetForm( pForm->GetUnoControlModel(), UNO_QUERY );
+ DBG_ASSERT( xPSetForm.is(), "DlgEdObj::TransformFormToSdrCoordinates: no form property set!" );
+ if ( !xPSetForm.is() )
+ return false;
+ bool bDecoration = true;
+ xPSetForm->getPropertyValue( DLGED_PROP_DECORATION ) >>= bDecoration;
+ if( bDecoration )
+ {
+ awt::DeviceInfo aDeviceInfo = pForm->getDeviceInfo();
+ aSize.AdjustWidth(aDeviceInfo.LeftInset + aDeviceInfo.RightInset );
+ aSize.AdjustHeight(aDeviceInfo.TopInset + aDeviceInfo.BottomInset );
+ }
+
+ // convert pixel to 100th_mm
+ aPos = pDevice->PixelToLogic( aPos, MapMode( MapUnit::Map100thMM ) );
+ aSize = pDevice->PixelToLogic( aSize, MapMode( MapUnit::Map100thMM ) );
+
+ // set out parameters
+ nXOut = aPos.Width();
+ nYOut = aPos.Height();
+ nWidthOut = aSize.Width();
+ nHeightOut = aSize.Height();
+
+ return true;
+}
+
+void DlgEdObj::SetRectFromProps()
+{
+ // get control position and size from properties
+ Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY );
+ if ( !xPSet.is() )
+ return;
+
+ sal_Int32 nXIn = 0, nYIn = 0, nWidthIn = 0, nHeightIn = 0;
+ xPSet->getPropertyValue( DLGED_PROP_POSITIONX ) >>= nXIn;
+ xPSet->getPropertyValue( DLGED_PROP_POSITIONY ) >>= nYIn;
+ xPSet->getPropertyValue( DLGED_PROP_WIDTH ) >>= nWidthIn;
+ xPSet->getPropertyValue( DLGED_PROP_HEIGHT ) >>= nHeightIn;
+
+ // transform coordinates
+ sal_Int32 nXOut, nYOut, nWidthOut, nHeightOut;
+ if ( TransformControlToSdrCoordinates( nXIn, nYIn, nWidthIn, nHeightIn, nXOut, nYOut, nWidthOut, nHeightOut ) )
+ {
+ // set rectangle position and size
+ Point aPoint( nXOut, nYOut );
+ Size aSize( nWidthOut, nHeightOut );
+ SetSnapRect( tools::Rectangle( aPoint, aSize ) );
+ }
+}
+
+void DlgEdObj::SetPropsFromRect()
+{
+ // get control position and size from rectangle
+ tools::Rectangle aRect_ = GetSnapRect();
+ sal_Int32 nXIn = aRect_.Left();
+ sal_Int32 nYIn = aRect_.Top();
+ sal_Int32 nWidthIn = aRect_.GetWidth();
+ sal_Int32 nHeightIn = aRect_.GetHeight();
+
+ // transform coordinates
+ sal_Int32 nXOut, nYOut, nWidthOut, nHeightOut;
+ if ( TransformSdrToControlCoordinates( nXIn, nYIn, nWidthIn, nHeightIn, nXOut, nYOut, nWidthOut, nHeightOut ) )
+ {
+ // set properties
+ Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY );
+ if ( xPSet.is() )
+ {
+ xPSet->setPropertyValue( DLGED_PROP_POSITIONX, Any(nXOut) );
+ xPSet->setPropertyValue( DLGED_PROP_POSITIONY, Any(nYOut) );
+ xPSet->setPropertyValue( DLGED_PROP_WIDTH, Any(nWidthOut) );
+ xPSet->setPropertyValue( DLGED_PROP_HEIGHT, Any(nHeightOut) );
+ }
+ }
+}
+
+void DlgEdObj::PositionAndSizeChange( const beans::PropertyChangeEvent& evt )
+{
+ DBG_ASSERT( pDlgEdForm, "DlgEdObj::PositionAndSizeChange: no form!" );
+ DlgEdPage& rPage = pDlgEdForm->GetDlgEditor().GetPage();
+ {
+ Size aPageSize = rPage.GetSize();
+ sal_Int32 nPageWidthIn = aPageSize.Width();
+ sal_Int32 nPageHeightIn = aPageSize.Height();
+ sal_Int32 nPageX, nPageY, nPageWidth, nPageHeight;
+ if ( TransformSdrToControlCoordinates( 0/*nPageXIn*/, 0/*nPageYIn*/, nPageWidthIn, nPageHeightIn, nPageX, nPageY, nPageWidth, nPageHeight ) )
+ {
+ Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY );
+ if ( xPSet.is() )
+ {
+ sal_Int32 nX = 0, nY = 0, nWidth = 0, nHeight = 0;
+ xPSet->getPropertyValue( DLGED_PROP_POSITIONX ) >>= nX;
+ xPSet->getPropertyValue( DLGED_PROP_POSITIONY ) >>= nY;
+ xPSet->getPropertyValue( DLGED_PROP_WIDTH ) >>= nWidth;
+ xPSet->getPropertyValue( DLGED_PROP_HEIGHT ) >>= nHeight;
+
+ sal_Int32 nValue = 0;
+ evt.NewValue >>= nValue;
+ sal_Int32 nNewValue = nValue;
+
+ if ( evt.PropertyName == DLGED_PROP_POSITIONX )
+ {
+ if ( nNewValue + nWidth > nPageX + nPageWidth )
+ nNewValue = nPageX + nPageWidth - nWidth;
+ if ( nNewValue < nPageX )
+ nNewValue = nPageX;
+ }
+ else if ( evt.PropertyName == DLGED_PROP_POSITIONY )
+ {
+ if ( nNewValue + nHeight > nPageY + nPageHeight )
+ nNewValue = nPageY + nPageHeight - nHeight;
+ if ( nNewValue < nPageY )
+ nNewValue = nPageY;
+ }
+ else if ( evt.PropertyName == DLGED_PROP_WIDTH )
+ {
+ if ( nX + nNewValue > nPageX + nPageWidth )
+ nNewValue = nPageX + nPageWidth - nX;
+ if ( nNewValue < 1 )
+ nNewValue = 1;
+ }
+ else if ( evt.PropertyName == DLGED_PROP_HEIGHT )
+ {
+ if ( nY + nNewValue > nPageY + nPageHeight )
+ nNewValue = nPageY + nPageHeight - nY;
+ if ( nNewValue < 1 )
+ nNewValue = 1;
+ }
+
+ if ( nNewValue != nValue )
+ {
+ EndListening( false );
+ xPSet->setPropertyValue( evt.PropertyName, Any(nNewValue) );
+ StartListening();
+ }
+ }
+ }
+ }
+
+ SetRectFromProps();
+}
+
+void DlgEdObj::NameChange( const css::beans::PropertyChangeEvent& evt )
+{
+ // get old name
+ OUString aOldName;
+ evt.OldValue >>= aOldName;
+
+ // get new name
+ OUString aNewName;
+ evt.NewValue >>= aNewName;
+
+ if ( aNewName == aOldName )
+ return;
+
+ Reference< container::XNameAccess > xNameAcc((GetDlgEdForm()->GetUnoControlModel()), UNO_QUERY);
+ if ( !(xNameAcc.is() && xNameAcc->hasByName(aOldName)) )
+ return;
+
+ if (!xNameAcc->hasByName(aNewName) && !aNewName.isEmpty())
+ {
+ // remove the control by the old name and insert the control by the new name in the container
+ Reference< container::XNameContainer > xCont(xNameAcc, UNO_QUERY );
+ if ( xCont.is() )
+ {
+ Reference< awt::XControlModel > xCtrl = GetUnoControlModel();
+ Any aAny;
+ aAny <<= xCtrl;
+ xCont->removeByName( aOldName );
+ xCont->insertByName( aNewName , aAny );
+
+ LocalizationMgr::renameControlResourceIDsForEditorObject(
+ &GetDialogEditor(), aAny, aNewName
+ );
+ }
+ }
+ else
+ {
+ // set old name property
+ EndListening(false);
+ Reference< beans::XPropertySet > xPSet(GetUnoControlModel(), UNO_QUERY);
+ xPSet->setPropertyValue( DLGED_PROP_NAME, Any(aOldName) );
+ StartListening();
+ }
+}
+
+sal_Int32 DlgEdObj::GetStep() const
+{
+ // get step property
+ sal_Int32 nStep = 0;
+ uno::Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), uno::UNO_QUERY );
+ if (xPSet.is())
+ {
+ xPSet->getPropertyValue( DLGED_PROP_STEP ) >>= nStep;
+ }
+ return nStep;
+}
+
+void DlgEdObj::UpdateStep()
+{
+ sal_Int32 nCurStep = GetDlgEdForm()->GetStep();
+ sal_Int32 nStep = GetStep();
+
+ SdrLayerAdmin& rLayerAdmin(getSdrModelFromSdrObject().GetLayerAdmin());
+ SdrLayerID nHiddenLayerId = rLayerAdmin.GetLayerID( "HiddenLayer" );
+ SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID( rLayerAdmin.GetControlLayerName() );
+
+ if( nCurStep )
+ {
+ if ( nStep && (nStep != nCurStep) )
+ {
+ SetLayer( nHiddenLayerId );
+ }
+ else
+ {
+ SetLayer( nControlLayerId );
+ }
+ }
+ else
+ {
+ SetLayer( nControlLayerId );
+ }
+}
+
+void DlgEdObj::TabIndexChange( const beans::PropertyChangeEvent& evt )
+{
+ DlgEdForm* pForm = GetDlgEdForm();
+ if ( !pForm )
+ return;
+
+ // stop listening with all children
+ std::vector<DlgEdObj*> aChildList = pForm->GetChildren();
+ for (auto const& child : aChildList)
+ {
+ child->EndListening( false );
+ }
+
+ Reference< container::XNameAccess > xNameAcc( pForm->GetUnoControlModel() , UNO_QUERY );
+ if ( xNameAcc.is() )
+ {
+ // get sequence of control names
+ Sequence< OUString > aNames = xNameAcc->getElementNames();
+ const OUString* pNames = aNames.getConstArray();
+ sal_Int32 nCtrls = aNames.getLength();
+
+ // create a map of tab indices and control names, sorted by tab index
+ IndexToNameMap aIndexToNameMap;
+ for ( sal_Int32 i = 0; i < nCtrls; ++i )
+ {
+ // get control name
+ OUString aName( pNames[i] );
+
+ // get tab index
+ sal_Int16 nTabIndex = -1;
+ Any aCtrl = xNameAcc->getByName( aName );
+ Reference< beans::XPropertySet > xPSet;
+ aCtrl >>= xPSet;
+ if ( xPSet.is() && xPSet == Reference< beans::XPropertySet >( evt.Source, UNO_QUERY ) )
+ evt.OldValue >>= nTabIndex;
+ else if ( xPSet.is() )
+ xPSet->getPropertyValue( DLGED_PROP_TABINDEX ) >>= nTabIndex;
+
+ // insert into map
+ aIndexToNameMap.emplace( nTabIndex, aName );
+ }
+
+ // create a helper list of control names, sorted by tab index
+ std::vector< OUString > aNameList( aIndexToNameMap.size() );
+ std::transform(
+ aIndexToNameMap.begin(), aIndexToNameMap.end(),
+ aNameList.begin(),
+ ::o3tl::select2nd< IndexToNameMap::value_type >( )
+ );
+
+ // check tab index
+ sal_Int16 nOldTabIndex = 0;
+ evt.OldValue >>= nOldTabIndex;
+ sal_Int16 nNewTabIndex = 0;
+ evt.NewValue >>= nNewTabIndex;
+ if ( nNewTabIndex < 0 )
+ nNewTabIndex = 0;
+ else if ( nNewTabIndex > nCtrls - 1 )
+ nNewTabIndex = sal::static_int_cast<sal_Int16>( nCtrls - 1 );
+
+ // reorder helper list
+ OUString aCtrlName = aNameList[nOldTabIndex];
+ aNameList.erase( aNameList.begin() + nOldTabIndex );
+ aNameList.insert( aNameList.begin() + nNewTabIndex , aCtrlName );
+
+ // set new tab indices
+ for ( sal_Int32 i = 0; i < nCtrls; ++i )
+ {
+ Any aCtrl = xNameAcc->getByName( aNameList[i] );
+ Reference< beans::XPropertySet > xPSet;
+ aCtrl >>= xPSet;
+ if ( xPSet.is() )
+ {
+ assert(i >= SAL_MIN_INT16);
+ if (i > SAL_MAX_INT16)
+ {
+ SAL_WARN("basctl", "tab " << i << " > SAL_MAX_INT16");
+ continue;
+ }
+ xPSet->setPropertyValue( DLGED_PROP_TABINDEX, Any(static_cast<sal_Int16>(i)) );
+ }
+ }
+
+ // reorder objects in drawing page
+ getSdrModelFromSdrObject().GetPage(0)->SetObjectOrdNum( nOldTabIndex + 1, nNewTabIndex + 1 );
+
+ pForm->UpdateTabOrderAndGroups();
+ }
+
+ // start listening with all children
+ for (auto const& child : aChildList)
+ {
+ child->StartListening();
+ }
+}
+
+bool DlgEdObj::supportsService( OUString const & serviceName ) const
+{
+ bool bSupports = false;
+
+ Reference< lang::XServiceInfo > xServiceInfo( GetUnoControlModel() , UNO_QUERY );
+ // TODO: cache xServiceInfo as member?
+ if ( xServiceInfo.is() )
+ bSupports = xServiceInfo->supportsService( serviceName );
+
+ return bSupports;
+}
+
+OUString DlgEdObj::GetDefaultName() const
+{
+ OUString sResId;
+ OUString aDefaultName;
+ if ( supportsService( "com.sun.star.awt.UnoControlDialogModel" ) )
+ {
+ sResId = RID_STR_CLASS_DIALOG;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlButtonModel" ) )
+ {
+ sResId = RID_STR_CLASS_BUTTON;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlRadioButtonModel" ) )
+ {
+ sResId = RID_STR_CLASS_RADIOBUTTON;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlCheckBoxModel" ) )
+ {
+ sResId = RID_STR_CLASS_CHECKBOX;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlListBoxModel" ) )
+ {
+ sResId = RID_STR_CLASS_LISTBOX;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlComboBoxModel" ) )
+ {
+ sResId = RID_STR_CLASS_COMBOBOX;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlGroupBoxModel" ) )
+ {
+ sResId = RID_STR_CLASS_GROUPBOX;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlEditModel" ) )
+ {
+ sResId = RID_STR_CLASS_EDIT;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlFixedTextModel" ) )
+ {
+ sResId = RID_STR_CLASS_FIXEDTEXT;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlImageControlModel" ) )
+ {
+ sResId = RID_STR_CLASS_IMAGECONTROL;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlProgressBarModel" ) )
+ {
+ sResId = RID_STR_CLASS_PROGRESSBAR;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlScrollBarModel" ) )
+ {
+ sResId = RID_STR_CLASS_SCROLLBAR;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlFixedLineModel" ) )
+ {
+ sResId = RID_STR_CLASS_FIXEDLINE;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlDateFieldModel" ) )
+ {
+ sResId = RID_STR_CLASS_DATEFIELD;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlTimeFieldModel" ) )
+ {
+ sResId = RID_STR_CLASS_TIMEFIELD;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlNumericFieldModel" ) )
+ {
+ sResId = RID_STR_CLASS_NUMERICFIELD;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlCurrencyFieldModel" ) )
+ {
+ sResId = RID_STR_CLASS_CURRENCYFIELD;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlFormattedFieldModel" ) )
+ {
+ sResId = RID_STR_CLASS_FORMATTEDFIELD;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlPatternFieldModel" ) )
+ {
+ sResId = RID_STR_CLASS_PATTERNFIELD;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlFileControlModel" ) )
+ {
+ sResId = RID_STR_CLASS_FILECONTROL;
+ }
+ else if ( supportsService( "com.sun.star.awt.tree.TreeControlModel" ) )
+ {
+ sResId = RID_STR_CLASS_TREECONTROL;
+ }
+ else if ( supportsService( "com.sun.star.awt.grid.UnoControlGridModel" ) )
+ {
+ sResId = RID_STR_CLASS_GRIDCONTROL;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlFixedHyperlinkModel" ) )
+ {
+ sResId = RID_STR_CLASS_HYPERLINKCONTROL;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlSpinButtonModel" ) )
+ {
+ sResId = RID_STR_CLASS_SPINCONTROL;
+ }
+ else
+ {
+ sResId = RID_STR_CLASS_CONTROL;
+ }
+
+ if (!sResId.isEmpty())
+ aDefaultName = sResId;
+
+ return aDefaultName;
+}
+
+OUString DlgEdObj::GetUniqueName() const
+{
+ OUString aUniqueName;
+ uno::Reference< container::XNameAccess > xNameAcc((GetDlgEdForm()->GetUnoControlModel()), uno::UNO_QUERY);
+
+ if ( xNameAcc.is() )
+ {
+ sal_Int32 n = 0;
+ OUString aDefaultName = GetDefaultName();
+
+ do
+ {
+ aUniqueName = aDefaultName + OUString::number(++n);
+ } while (xNameAcc->hasByName(aUniqueName));
+ }
+
+ return aUniqueName;
+}
+
+SdrInventor DlgEdObj::GetObjInventor() const
+{
+ return SdrInventor::BasicDialog;
+}
+
+SdrObjKind DlgEdObj::GetObjIdentifier() const
+{
+ if ( supportsService( "com.sun.star.awt.UnoControlDialogModel" ))
+ {
+ return SdrObjKind::BasicDialogDialog;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlButtonModel" ))
+ {
+ return SdrObjKind::BasicDialogPushButton;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlRadioButtonModel" ))
+ {
+ return SdrObjKind::BasicDialogRadioButton;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlCheckBoxModel" ))
+ {
+ return SdrObjKind::BasicDialogCheckbox;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlListBoxModel" ))
+ {
+ return SdrObjKind::BasicDialogListbox;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlComboBoxModel" ))
+ {
+ return SdrObjKind::BasicDialogCombobox;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlGroupBoxModel" ))
+ {
+ return SdrObjKind::BasicDialogGroupBox;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlEditModel" ))
+ {
+ return SdrObjKind::BasicDialogEdit;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlFixedTextModel" ))
+ {
+ return SdrObjKind::BasicDialogFixedText;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlImageControlModel" ))
+ {
+ return SdrObjKind::BasicDialogImageControl;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlProgressBarModel" ))
+ {
+ return SdrObjKind::BasicDialogProgressbar;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlScrollBarModel" ))
+ {
+ return SdrObjKind::BasicDialogHorizontalScrollbar;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlFixedLineModel" ))
+ {
+ return SdrObjKind::BasicDialogHorizontalFixedLine;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlDateFieldModel" ))
+ {
+ return SdrObjKind::BasicDialogDateField;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlTimeFieldModel" ))
+ {
+ return SdrObjKind::BasicDialogTimeField;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlNumericFieldModel" ))
+ {
+ return SdrObjKind::BasicDialogNumericField;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlCurrencyFieldModel" ))
+ {
+ return SdrObjKind::BasicDialogCurencyField;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlFormattedFieldModel" ))
+ {
+ return SdrObjKind::BasicDialogFormattedField;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlPatternFieldModel" ))
+ {
+ return SdrObjKind::BasicDialogPatternField;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlFileControlModel" ))
+ {
+ return SdrObjKind::BasicDialogFileControl;
+ }
+ else if ( supportsService( "com.sun.star.awt.tree.TreeControlModel" ))
+ {
+ return SdrObjKind::BasicDialogTreeControl;
+ }
+ else if ( supportsService( "com.sun.star.awt.grid.UnoControlGridModel" ))
+ {
+ return SdrObjKind::BasicDialogGridControl;
+ }
+ else if ( supportsService( "com.sun.star.awt.UnoControlFixedHyperlinkModel" ))
+ {
+ return SdrObjKind::BasicDialogHyperlinkControl;
+ }
+ else
+ {
+ return SdrObjKind::BasicDialogControl;
+ }
+}
+
+rtl::Reference<SdrObject> DlgEdObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new DlgEdObj(rTargetModel, *this);
+}
+
+rtl::Reference<SdrObject> DlgEdObj::getFullDragClone() const
+{
+ // no need to really add the clone for dragging, it's a temporary
+ // object
+ return rtl::Reference<SdrObject>(new SdrUnoObj(getSdrModelFromSdrObject(), *this));
+}
+
+void DlgEdObj::NbcMove( const Size& rSize )
+{
+ SdrUnoObj::NbcMove( rSize );
+
+ // stop listening
+ EndListening(false);
+
+ // set geometry properties
+ SetPropsFromRect();
+
+ // start listening
+ StartListening();
+
+ // dialog model changed
+ GetDlgEdForm()->GetDlgEditor().SetDialogModelChanged();
+}
+
+void DlgEdObj::NbcResize(const Point& rRef, const Fraction& xFract, const Fraction& yFract)
+{
+ SdrUnoObj::NbcResize( rRef, xFract, yFract );
+
+ // stop listening
+ EndListening(false);
+
+ // set geometry properties
+ SetPropsFromRect();
+
+ // start listening
+ StartListening();
+
+ // dialog model changed
+ GetDlgEdForm()->GetDlgEditor().SetDialogModelChanged();
+}
+
+bool DlgEdObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ bool bResult = SdrUnoObj::EndCreate(rStat, eCmd);
+
+ // tdf#120674 after interactive creation, the SdrObject (this) has no SdrPage yet
+ // due to not being inserted. Usually this should be handled in a ::handlePageChange
+ // implementation. For historical reasons, the SdrPage (which is the DlgEdPage) was
+ // already set. For now, get it from the SdrDragStat and use it to access and set
+ // the local pDlgEdForm
+ if(!pDlgEdForm && nullptr != rStat.GetPageView())
+ {
+ const DlgEdPage* pDlgEdPage(dynamic_cast<const DlgEdPage*>(rStat.GetPageView()->GetPage()));
+
+ if(nullptr != pDlgEdPage)
+ {
+ // set parent form
+ pDlgEdForm = pDlgEdPage->GetDlgEdForm();
+ }
+ }
+
+ SetDefaults();
+ StartListening();
+
+ return bResult;
+}
+
+void DlgEdObj::SetDefaults()
+{
+ if ( !pDlgEdForm )
+ return;
+
+ // add child to parent form
+ pDlgEdForm->AddChild( this );
+
+ Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY );
+ if ( xPSet.is() )
+ {
+ // get unique name
+ OUString aOUniqueName( GetUniqueName() );
+
+ // set name property
+ xPSet->setPropertyValue( DLGED_PROP_NAME, Any(aOUniqueName) );
+
+ // set labels
+ if ( supportsService( "com.sun.star.awt.UnoControlButtonModel" ) ||
+ supportsService( "com.sun.star.awt.UnoControlRadioButtonModel" ) ||
+ supportsService( "com.sun.star.awt.UnoControlCheckBoxModel" ) ||
+ supportsService( "com.sun.star.awt.UnoControlGroupBoxModel" ) ||
+ supportsService( "com.sun.star.awt.UnoControlFixedTextModel" ) )
+ {
+ xPSet->setPropertyValue( DLGED_PROP_LABEL, Any(aOUniqueName) );
+ }
+
+ // set number formats supplier for formatted field
+ if ( supportsService( "com.sun.star.awt.UnoControlFormattedFieldModel" ) )
+ {
+ Reference< util::XNumberFormatsSupplier > xSupplier = GetDlgEdForm()->GetDlgEditor().GetNumberFormatsSupplier();
+ if ( xSupplier.is() )
+ {
+ xPSet->setPropertyValue( DLGED_PROP_FORMATSSUPPLIER, Any(xSupplier) );
+ }
+ }
+
+ // set geometry properties
+ SetPropsFromRect();
+
+ Reference< container::XNameContainer > xCont( GetDlgEdForm()->GetUnoControlModel() , UNO_QUERY );
+ if ( xCont.is() )
+ {
+ // set tabindex
+ Sequence< OUString > aNames = xCont->getElementNames();
+ uno::Any aTabIndex;
+ aTabIndex <<= static_cast<sal_Int16>(aNames.getLength());
+ xPSet->setPropertyValue( DLGED_PROP_TABINDEX, aTabIndex );
+
+ // set step
+ Reference< beans::XPropertySet > xPSetForm( xCont, UNO_QUERY );
+ if ( xPSetForm.is() )
+ {
+ Any aStep = xPSetForm->getPropertyValue( DLGED_PROP_STEP );
+ xPSet->setPropertyValue( DLGED_PROP_STEP, aStep );
+ }
+
+ // insert control model in dialog model
+ Reference< awt::XControlModel > xCtrl( xPSet , UNO_QUERY );
+ Any aAny;
+ aAny <<= xCtrl;
+ xCont->insertByName( aOUniqueName , aAny );
+
+ LocalizationMgr::setControlResourceIDsForNewEditorObject(
+ &GetDialogEditor(), aAny, aOUniqueName
+ );
+
+ pDlgEdForm->UpdateTabOrderAndGroups();
+ }
+ }
+
+ // dialog model changed
+ pDlgEdForm->GetDlgEditor().SetDialogModelChanged();
+}
+
+void DlgEdObj::StartListening()
+{
+ DBG_ASSERT(!isListening(), "DlgEdObj::StartListening: already listening!");
+
+ if (isListening())
+ return;
+
+ bIsListening = true;
+
+ // XPropertyChangeListener
+ Reference< XPropertySet > xControlModel( GetUnoControlModel() , UNO_QUERY );
+ if (!m_xPropertyChangeListener.is() && xControlModel.is())
+ {
+ // create listener
+ m_xPropertyChangeListener = new DlgEdPropListenerImpl(*this);
+
+ // register listener to properties
+ xControlModel->addPropertyChangeListener( OUString() , m_xPropertyChangeListener );
+ }
+
+ // XContainerListener
+ Reference< XScriptEventsSupplier > xEventsSupplier( GetUnoControlModel() , UNO_QUERY );
+ if( !m_xContainerListener.is() && xEventsSupplier.is() )
+ {
+ // create listener
+ m_xContainerListener = new DlgEdEvtContListenerImpl(*this);
+
+ // register listener to script event container
+ Reference< XNameContainer > xEventCont = xEventsSupplier->getEvents();
+ DBG_ASSERT(xEventCont.is(), "DlgEdObj::StartListening: control model has no script event container!");
+ Reference< XContainer > xCont( xEventCont , UNO_QUERY );
+ if (xCont.is())
+ xCont->addContainerListener( m_xContainerListener );
+ }
+}
+
+void DlgEdObj::EndListening(bool bRemoveListener)
+{
+ DBG_ASSERT(isListening(), "DlgEdObj::EndListening: not listening currently!");
+
+ if (!isListening())
+ return;
+
+ bIsListening = false;
+
+ if (!bRemoveListener)
+ return;
+
+ // XPropertyChangeListener
+ Reference< XPropertySet > xControlModel(GetUnoControlModel(), UNO_QUERY);
+ if ( m_xPropertyChangeListener.is() && xControlModel.is() )
+ {
+ // remove listener
+ xControlModel->removePropertyChangeListener( OUString() , m_xPropertyChangeListener );
+ }
+ m_xPropertyChangeListener.clear();
+
+ // XContainerListener
+ Reference< XScriptEventsSupplier > xEventsSupplier( GetUnoControlModel() , UNO_QUERY );
+ if( m_xContainerListener.is() && xEventsSupplier.is() )
+ {
+ // remove listener
+ Reference< XNameContainer > xEventCont = xEventsSupplier->getEvents();
+ DBG_ASSERT(xEventCont.is(), "DlgEdObj::EndListening: control model has no script event container!");
+ Reference< XContainer > xCont( xEventCont , UNO_QUERY );
+ if (xCont.is())
+ xCont->removeContainerListener( m_xContainerListener );
+ }
+ m_xContainerListener.clear();
+}
+
+void DlgEdObj::_propertyChange( const css::beans::PropertyChangeEvent& evt )
+{
+ if (!isListening())
+ return;
+
+ DlgEdForm* pRealDlgEdForm = dynamic_cast<DlgEdForm*>(this);
+ if (!pRealDlgEdForm)
+ pRealDlgEdForm = GetDlgEdForm();
+ if (!pRealDlgEdForm)
+ return;
+ DlgEditor& rDlgEditor = pRealDlgEdForm->GetDlgEditor();
+ if (rDlgEditor.isInPaint())
+ return;
+
+ // dialog model changed
+ rDlgEditor.SetDialogModelChanged();
+
+ // update position and size
+ if ( evt.PropertyName == DLGED_PROP_POSITIONX || evt.PropertyName == DLGED_PROP_POSITIONY ||
+ evt.PropertyName == DLGED_PROP_WIDTH || evt.PropertyName == DLGED_PROP_HEIGHT ||
+ evt.PropertyName == DLGED_PROP_DECORATION )
+ {
+ PositionAndSizeChange( evt );
+
+ if ( evt.PropertyName == DLGED_PROP_DECORATION )
+ GetDialogEditor().ResetDialog();
+ }
+ // change name of control in dialog model
+ else if ( evt.PropertyName == DLGED_PROP_NAME )
+ {
+ if (!dynamic_cast<DlgEdForm*>(this))
+ {
+ try
+ {
+ NameChange(evt);
+ }
+ catch (container::NoSuchElementException const&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException("", nullptr,
+ anyEx);
+ }
+ }
+ }
+ // update step
+ else if ( evt.PropertyName == DLGED_PROP_STEP )
+ {
+ UpdateStep();
+ }
+ // change tabindex
+ else if ( evt.PropertyName == DLGED_PROP_TABINDEX )
+ {
+ if (!dynamic_cast<DlgEdForm*>(this))
+ TabIndexChange(evt);
+ }
+}
+
+void DlgEdObj::_elementInserted()
+{
+ if (isListening())
+ {
+ // dialog model changed
+ GetDialogEditor().SetDialogModelChanged();
+ }
+}
+
+void DlgEdObj::_elementReplaced()
+{
+ if (isListening())
+ {
+ // dialog model changed
+ GetDialogEditor().SetDialogModelChanged();
+ }
+}
+
+void DlgEdObj::_elementRemoved()
+{
+ if (isListening())
+ {
+ // dialog model changed
+ GetDialogEditor().SetDialogModelChanged();
+ }
+}
+
+void DlgEdObj::SetLayer(SdrLayerID nLayer)
+{
+ SdrLayerID nOldLayer = GetLayer();
+
+ if ( nLayer != nOldLayer )
+ {
+ SdrUnoObj::SetLayer( nLayer );
+
+ DlgEdHint aHint( DlgEdHint::LAYERCHANGED, this );
+ GetDlgEdForm()->GetDlgEditor().Broadcast( aHint );
+ }
+}
+
+DlgEdForm::DlgEdForm(
+ SdrModel& rSdrModel,
+ DlgEditor& rDlgEditor_)
+: DlgEdObj(rSdrModel),
+ rDlgEditor(rDlgEditor_)
+{
+}
+
+DlgEdForm::~DlgEdForm()
+{
+}
+
+void DlgEdForm::SetRectFromProps()
+{
+ // get form position and size from properties
+ Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY );
+ if ( !xPSet.is() )
+ return;
+
+ sal_Int32 nXIn = 0, nYIn = 0, nWidthIn = 0, nHeightIn = 0;
+ xPSet->getPropertyValue( DLGED_PROP_POSITIONX ) >>= nXIn;
+ xPSet->getPropertyValue( DLGED_PROP_POSITIONY ) >>= nYIn;
+ xPSet->getPropertyValue( DLGED_PROP_WIDTH ) >>= nWidthIn;
+ xPSet->getPropertyValue( DLGED_PROP_HEIGHT ) >>= nHeightIn;
+
+ // transform coordinates
+ sal_Int32 nXOut, nYOut, nWidthOut, nHeightOut;
+ if ( TransformFormToSdrCoordinates( nXIn, nYIn, nWidthIn, nHeightIn, nXOut, nYOut, nWidthOut, nHeightOut ) )
+ {
+ // set rectangle position and size
+ Point aPoint( nXOut, nYOut );
+ Size aSize( nWidthOut, nHeightOut );
+ SetSnapRect( tools::Rectangle( aPoint, aSize ) );
+ }
+}
+
+void DlgEdForm::SetPropsFromRect()
+{
+ // get form position and size from rectangle
+ tools::Rectangle aRect_ = GetSnapRect();
+ sal_Int32 nXIn = aRect_.Left();
+ sal_Int32 nYIn = aRect_.Top();
+ sal_Int32 nWidthIn = aRect_.GetWidth();
+ sal_Int32 nHeightIn = aRect_.GetHeight();
+
+ // transform coordinates
+ sal_Int32 nXOut, nYOut, nWidthOut, nHeightOut;
+ if ( TransformSdrToFormCoordinates( nXIn, nYIn, nWidthIn, nHeightIn, nXOut, nYOut, nWidthOut, nHeightOut ) )
+ {
+ // set properties
+ Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY );
+ if ( xPSet.is() )
+ {
+ xPSet->setPropertyValue( DLGED_PROP_POSITIONX, Any(nXOut) );
+ xPSet->setPropertyValue( DLGED_PROP_POSITIONY, Any(nYOut) );
+ xPSet->setPropertyValue( DLGED_PROP_WIDTH, Any(nWidthOut) );
+ xPSet->setPropertyValue( DLGED_PROP_HEIGHT, Any(nHeightOut) );
+ }
+ }
+}
+
+void DlgEdForm::AddChild( DlgEdObj* pDlgEdObj )
+{
+ pChildren.push_back( pDlgEdObj );
+}
+
+void DlgEdForm::RemoveChild( DlgEdObj* pDlgEdObj )
+{
+ std::erase(pChildren, pDlgEdObj);
+}
+
+void DlgEdForm::PositionAndSizeChange( const beans::PropertyChangeEvent& evt )
+{
+ DlgEditor& rEditor = GetDlgEditor();
+ DlgEdPage& rPage = rEditor.GetPage();
+
+ sal_Int32 nPageXIn = 0;
+ sal_Int32 nPageYIn = 0;
+ Size aPageSize = rPage.GetSize();
+ sal_Int32 nPageWidthIn = aPageSize.Width();
+ sal_Int32 nPageHeightIn = aPageSize.Height();
+ sal_Int32 nPageX, nPageY, nPageWidth, nPageHeight;
+ if ( TransformSdrToFormCoordinates( nPageXIn, nPageYIn, nPageWidthIn, nPageHeightIn, nPageX, nPageY, nPageWidth, nPageHeight ) )
+ {
+ Reference< beans::XPropertySet > xPSetForm( GetUnoControlModel(), UNO_QUERY );
+ if ( xPSetForm.is() )
+ {
+ sal_Int32 nValue = 0;
+ evt.NewValue >>= nValue;
+ sal_Int32 nNewValue = nValue;
+
+ if ( evt.PropertyName == DLGED_PROP_POSITIONX )
+ {
+ if ( nNewValue < nPageX )
+ nNewValue = nPageX;
+ }
+ else if ( evt.PropertyName == DLGED_PROP_POSITIONY )
+ {
+ if ( nNewValue < nPageY )
+ nNewValue = nPageY;
+ }
+ else if ( evt.PropertyName == DLGED_PROP_WIDTH )
+ {
+ if ( nNewValue < 1 )
+ nNewValue = 1;
+ }
+ else if ( evt.PropertyName == DLGED_PROP_HEIGHT )
+ {
+ if ( nNewValue < 1 )
+ nNewValue = 1;
+ }
+
+ if ( nNewValue != nValue )
+ {
+ EndListening( false );
+ xPSetForm->setPropertyValue( evt.PropertyName, Any(nNewValue) );
+ StartListening();
+ }
+ }
+ }
+
+ bool bAdjustedPageSize = rEditor.AdjustPageSize();
+ SetRectFromProps();
+ std::vector<DlgEdObj*> const& aChildList = GetChildren();
+
+ if ( bAdjustedPageSize )
+ {
+ rEditor.InitScrollBars();
+ aPageSize = rPage.GetSize();
+ nPageWidthIn = aPageSize.Width();
+ nPageHeightIn = aPageSize.Height();
+ if ( TransformSdrToControlCoordinates( nPageXIn, nPageYIn, nPageWidthIn, nPageHeightIn, nPageX, nPageY, nPageWidth, nPageHeight ) )
+ {
+ for (auto const& child : aChildList)
+ {
+ Reference< beans::XPropertySet > xPSet( child->GetUnoControlModel(), UNO_QUERY );
+ if ( xPSet.is() )
+ {
+ sal_Int32 nX = 0, nY = 0, nWidth = 0, nHeight = 0;
+ xPSet->getPropertyValue( DLGED_PROP_POSITIONX ) >>= nX;
+ xPSet->getPropertyValue( DLGED_PROP_POSITIONY ) >>= nY;
+ xPSet->getPropertyValue( DLGED_PROP_WIDTH ) >>= nWidth;
+ xPSet->getPropertyValue( DLGED_PROP_HEIGHT ) >>= nHeight;
+
+ sal_Int32 nNewX = nX;
+ if ( nX + nWidth > nPageX + nPageWidth )
+ {
+ nNewX = nPageX + nPageWidth - nWidth;
+ if ( nNewX < nPageX )
+ nNewX = nPageX;
+ }
+ if ( nNewX != nX )
+ {
+ EndListening( false );
+ xPSet->setPropertyValue( DLGED_PROP_POSITIONX, Any(nNewX) );
+ StartListening();
+ }
+
+ sal_Int32 nNewY = nY;
+ if ( nY + nHeight > nPageY + nPageHeight )
+ {
+ nNewY = nPageY + nPageHeight - nHeight;
+ if ( nNewY < nPageY )
+ nNewY = nPageY;
+ }
+ if ( nNewY != nY )
+ {
+ EndListening( false );
+ xPSet->setPropertyValue( DLGED_PROP_POSITIONY, Any(nNewY) );
+ StartListening();
+ }
+ }
+ }
+ }
+ }
+
+ for (auto const& child : aChildList)
+ child->SetRectFromProps();
+}
+
+void DlgEdForm::UpdateStep()
+{
+ SdrPage* pSdrPage = getSdrPageFromSdrObject();
+
+ if ( pSdrPage )
+ {
+ for (const rtl::Reference<SdrObject>& pObj : *pSdrPage)
+ {
+ DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj.get());
+ if (pDlgEdObj && !dynamic_cast<DlgEdForm*>(pDlgEdObj))
+ pDlgEdObj->UpdateStep();
+ }
+ }
+}
+
+void DlgEdForm::UpdateTabIndices()
+{
+ // stop listening with all children
+ for (auto const& child : pChildren)
+ {
+ child->EndListening( false );
+ }
+
+ Reference< css::container::XNameAccess > xNameAcc( GetUnoControlModel() , UNO_QUERY );
+ if ( xNameAcc.is() )
+ {
+ // get sequence of control names
+ Sequence< OUString > aNames = xNameAcc->getElementNames();
+ const OUString* pNames = aNames.getConstArray();
+ sal_Int32 nCtrls = aNames.getLength();
+
+ // create a map of tab indices and control names, sorted by tab index
+ IndexToNameMap aIndexToNameMap;
+ for ( sal_Int32 i = 0; i < nCtrls; ++i )
+ {
+ // get name
+ OUString aName( pNames[i] );
+
+ // get tab index
+ sal_Int16 nTabIndex = -1;
+ Any aCtrl = xNameAcc->getByName( aName );
+ Reference< css::beans::XPropertySet > xPSet;
+ aCtrl >>= xPSet;
+ if ( xPSet.is() )
+ xPSet->getPropertyValue( DLGED_PROP_TABINDEX ) >>= nTabIndex;
+
+ // insert into map
+ aIndexToNameMap.emplace( nTabIndex, aName );
+ }
+
+ // set new tab indices
+ sal_Int16 nNewTabIndex = 0;
+ for (auto const& indexToName : aIndexToNameMap)
+ {
+ Any aCtrl = xNameAcc->getByName( indexToName.second );
+ Reference< beans::XPropertySet > xPSet;
+ aCtrl >>= xPSet;
+ if ( xPSet.is() )
+ {
+ xPSet->setPropertyValue( DLGED_PROP_TABINDEX, Any(nNewTabIndex) );
+ nNewTabIndex++;
+ }
+ }
+
+ UpdateTabOrderAndGroups();
+ }
+
+ // start listening with all children
+ for (auto const& child : pChildren)
+ {
+ child->StartListening();
+ }
+}
+
+void DlgEdForm::UpdateTabOrder()
+{
+ // When the tabindex of a control model changes, the dialog control is
+ // notified about those changes. Due to #109067# (bad performance of
+ // dialog editor) the dialog control doesn't activate the tab order
+ // in design mode. When the dialog editor has reordered all
+ // tabindices, this method allows to activate the taborder afterwards.
+
+ Reference< awt::XUnoControlContainer > xCont( GetControl(), UNO_QUERY );
+ if ( xCont.is() )
+ {
+ Sequence< Reference< awt::XTabController > > aSeqTabCtrls = xCont->getTabControllers();
+ const Reference< awt::XTabController >* pTabCtrls = aSeqTabCtrls.getConstArray();
+ sal_Int32 nCount = aSeqTabCtrls.getLength();
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ pTabCtrls[i]->activateTabOrder();
+ }
+}
+
+void DlgEdForm::UpdateGroups()
+{
+ // The grouping of radio buttons in a dialog is done by vcl.
+ // In the dialog editor we have two views (=controls) for one
+ // radio button model. One control is owned by the dialog control,
+ // but not visible in design mode. The other control is owned by
+ // the drawing layer object. Whereas the grouping of the first
+ // control is done by vcl, the grouping of the control in the
+ // drawing layer has to be done here.
+
+ Reference< awt::XTabControllerModel > xTabModel( GetUnoControlModel() , UNO_QUERY );
+ if ( !xTabModel.is() )
+ return;
+
+ // create a global list of controls that belong to the dialog
+ std::vector<DlgEdObj*> aChildList = GetChildren();
+ sal_uInt32 nSize = aChildList.size();
+ Sequence< Reference< awt::XControl > > aSeqControls( nSize );
+ for ( sal_uInt32 i = 0; i < nSize; ++i )
+ aSeqControls.getArray()[i] = aChildList[i]->GetControl();
+
+ sal_Int32 nGroupCount = xTabModel->getGroupCount();
+ for ( sal_Int32 nGroup = 0; nGroup < nGroupCount; ++nGroup )
+ {
+ // get a list of control models that belong to this group
+ OUString aName;
+ Sequence< Reference< awt::XControlModel > > aSeqModels;
+ xTabModel->getGroup( nGroup, aSeqModels, aName );
+ const Reference< awt::XControlModel >* pModels = aSeqModels.getConstArray();
+ sal_Int32 nModelCount = aSeqModels.getLength();
+
+ // create a list of peers that belong to this group
+ Sequence< Reference< awt::XWindow > > aSeqPeers( nModelCount );
+ for ( sal_Int32 nModel = 0; nModel < nModelCount; ++nModel )
+ {
+ // for each control model find the corresponding control in the global list
+ const Reference< awt::XControl >* pControls = aSeqControls.getConstArray();
+ sal_Int32 nControlCount = aSeqControls.getLength();
+ for ( sal_Int32 nControl = 0; nControl < nControlCount; ++nControl )
+ {
+ const Reference< awt::XControl > xCtrl( pControls[nControl] );
+ if ( xCtrl.is() )
+ {
+ Reference< awt::XControlModel > xCtrlModel( xCtrl->getModel() );
+ if ( xCtrlModel.get() == pModels[nModel].get() )
+ {
+ // get the control peer and insert into the list of peers
+ aSeqPeers.getArray()[ nModel ].set( xCtrl->getPeer(), UNO_QUERY );
+ break;
+ }
+ }
+ }
+ }
+
+ // set the group at the dialog peer
+ Reference< awt::XControl > xDlg = GetControl();
+ if ( xDlg.is() )
+ {
+ Reference< awt::XVclContainerPeer > xDlgPeer( xDlg->getPeer(), UNO_QUERY );
+ if ( xDlgPeer.is() )
+ xDlgPeer->setGroup( aSeqPeers );
+ }
+ }
+}
+
+void DlgEdForm::UpdateTabOrderAndGroups()
+{
+ UpdateTabOrder();
+ UpdateGroups();
+}
+
+void DlgEdForm::NbcMove( const Size& rSize )
+{
+ SdrUnoObj::NbcMove( rSize );
+
+ // set geometry properties of form
+ EndListening(false);
+ SetPropsFromRect();
+ StartListening();
+
+ // set geometry properties of all children
+ for (auto const& child : pChildren)
+ {
+ child->EndListening(false);
+ child->SetPropsFromRect();
+ child->StartListening();
+ }
+
+ // dialog model changed
+ GetDlgEditor().SetDialogModelChanged();
+}
+
+void DlgEdForm::NbcResize(const Point& rRef, const Fraction& xFract, const Fraction& yFract)
+{
+ SdrUnoObj::NbcResize( rRef, xFract, yFract );
+
+ // set geometry properties of form
+ EndListening(false);
+ SetPropsFromRect();
+ StartListening();
+
+ // set geometry properties of all children
+ for (auto const& child : pChildren)
+ {
+ child->EndListening(false);
+ child->SetPropsFromRect();
+ child->StartListening();
+ }
+
+ // dialog model changed
+ GetDlgEditor().SetDialogModelChanged();
+}
+
+bool DlgEdForm::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ bool bResult = SdrUnoObj::EndCreate(rStat, eCmd);
+
+ // stop listening
+ EndListening(false);
+
+ // set geometry properties
+ SetPropsFromRect();
+
+ // dialog model changed
+ GetDlgEditor().SetDialogModelChanged();
+
+ // start listening
+ StartListening();
+
+ return bResult;
+}
+
+awt::DeviceInfo DlgEdForm::getDeviceInfo() const
+{
+ awt::DeviceInfo aDeviceInfo;
+
+ DlgEditor& rEditor = GetDlgEditor();
+ vcl::Window& rWindow = rEditor.GetWindow();
+
+ // obtain an XControl
+ ::utl::SharedUNOComponent< awt::XControl > xDialogControl; // ensures auto-disposal, if needed
+ xDialogControl.reset( GetControl(), ::utl::SharedUNOComponent< awt::XControl >::NoTakeOwnership );
+ if ( !xDialogControl.is() )
+ {
+ // don't create a temporary control all the time, this method here is called
+ // way too often. Instead, use a cached DeviceInfo.
+ // #i74065#
+ if ( !!mpDeviceInfo )
+ return *mpDeviceInfo;
+
+ Reference< awt::XControlContainer > xEditorControlContainer( rEditor.GetWindowControlContainer() );
+ xDialogControl.reset(
+ GetTemporaryControlForWindow(rWindow, xEditorControlContainer),
+ utl::SharedUNOComponent< awt::XControl >::TakeOwnership
+ );
+ }
+
+ Reference< awt::XDevice > xDialogDevice;
+ if ( xDialogControl.is() )
+ xDialogDevice.set( xDialogControl->getPeer(), UNO_QUERY );
+ DBG_ASSERT( xDialogDevice.is(), "DlgEdForm::getDeviceInfo: no device!" );
+ if ( xDialogDevice.is() )
+ aDeviceInfo = xDialogDevice->getInfo();
+
+ mpDeviceInfo = aDeviceInfo;
+
+ return aDeviceInfo;
+}
+void DlgEdObj::MakeDataAware( const Reference< frame::XModel >& xModel )
+{
+ // Need to flesh this out, currently we will only support data-aware controls for calc
+ // and only handle a subset of functionality e.g. linked-cell and cell range data source. Of course later
+ // we need to disambiguate for writer ( and others ? ) and also support the generic form (db) bindings
+ // we need some more work in xmlscript to be able to handle that
+ Reference< lang::XMultiServiceFactory > xFac( xModel, UNO_QUERY );
+ Reference< form::binding::XBindableValue > xBindable( GetUnoControlModel(), UNO_QUERY );
+ Reference< form::binding::XListEntrySink > xListEntrySink( GetUnoControlModel(), UNO_QUERY );
+ if ( !xFac.is() )
+ return;
+
+ //tdf#90361 and tdf#104011 CellValueBinding and CellRangeListSource are unusable
+ //without being initialized, so use createInstanceWithArguments with a
+ //dummy BoundCell and CellRange instead of createInstance. This at least results in
+ //the dialog editor not falling.
+ css::beans::NamedValue aCellValue;
+ aCellValue.Name = "BoundCell";
+ css::table::CellAddress aCellAddress;
+ aCellValue.Value <<= aCellAddress;
+
+ css::beans::NamedValue aCellRange;
+ aCellRange.Name = "CellRange";
+ css::table::CellRangeAddress aRangeAddress;
+ aCellRange.Value <<= aRangeAddress;
+
+ Sequence< Any > aArgs{ Any(aCellValue), Any(aCellRange) };
+
+ if ( xBindable.is() )
+ {
+ Reference< form::binding::XValueBinding > xBinding( xFac->createInstanceWithArguments( "com.sun.star.table.CellValueBinding", aArgs ), UNO_QUERY );
+ xBindable->setValueBinding( xBinding );
+ }
+ if ( xListEntrySink.is() )
+ {
+ Reference< form::binding::XListEntrySource > xSource( xFac->createInstanceWithArguments( "com.sun.star.table.CellRangeListSource", aArgs ), UNO_QUERY );
+ xListEntrySink->setListEntrySource( xSource );
+ }
+}
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/dlged/dlgedpage.cxx b/basctl/source/dlged/dlgedpage.cxx
new file mode 100644
index 0000000000..760f885276
--- /dev/null
+++ b/basctl/source/dlged/dlgedpage.cxx
@@ -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 .
+ */
+
+#include <dlgedpage.hxx>
+#include <dlged.hxx>
+#include <dlgedmod.hxx>
+#include <dlgedobj.hxx>
+
+namespace basctl
+{
+
+
+DlgEdPage::DlgEdPage(DlgEdModel& rModel, bool bMasterPage)
+: SdrPage(rModel, bMasterPage)
+ ,pDlgEdForm(nullptr)
+{
+}
+
+DlgEdPage::~DlgEdPage()
+{
+ // clear SdrObjects with broadcasting
+ ClearSdrObjList();
+}
+
+rtl::Reference<SdrPage> DlgEdPage::CloneSdrPage(SdrModel& rTargetModel) const
+{
+ DlgEdModel& rDlgEdModel(static_cast< DlgEdModel& >(rTargetModel));
+ rtl::Reference<DlgEdPage> pClonedDlgEdPage =
+ new DlgEdPage(
+ rDlgEdModel,
+ IsMasterPage());
+ pClonedDlgEdPage->SdrPage::lateInit(*this);
+ return pClonedDlgEdPage;
+}
+
+
+SdrObject* DlgEdPage::SetObjectOrdNum(size_t nOldObjNum, size_t nNewObjNum)
+{
+ SdrObject* pObj = SdrPage::SetObjectOrdNum( nOldObjNum, nNewObjNum );
+
+ DlgEdHint aHint( DlgEdHint::OBJORDERCHANGED );
+ if ( pDlgEdForm )
+ pDlgEdForm->GetDlgEditor().Broadcast( aHint );
+
+ return pObj;
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/dlged/dlgedview.cxx b/basctl/source/dlged/dlgedview.cxx
new file mode 100644
index 0000000000..81271d38f8
--- /dev/null
+++ b/basctl/source/dlged/dlgedview.cxx
@@ -0,0 +1,184 @@
+/* -*- 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 <dlgedview.hxx>
+#include <dlged.hxx>
+#include <dlgedpage.hxx>
+
+#include <svtools/scrolladaptor.hxx>
+#include <vcl/canvastools.hxx>
+
+#include <dlgedobj.hxx>
+
+namespace basctl
+{
+
+DlgEdView::DlgEdView(
+ SdrModel& rSdrModel,
+ OutputDevice& rOut,
+ DlgEditor& rEditor)
+: SdrView(rSdrModel, &rOut),
+ rDlgEditor(rEditor)
+{
+ SetBufferedOutputAllowed(true);
+ SetBufferedOverlayAllowed(true);
+}
+
+DlgEdView::~DlgEdView()
+{
+}
+
+void DlgEdView::MarkListHasChanged()
+{
+ SdrView::MarkListHasChanged();
+
+ DlgEdHint aHint( DlgEdHint::SELECTIONCHANGED );
+ rDlgEditor.Broadcast( aHint );
+ rDlgEditor.UpdatePropertyBrowserDelayed();
+}
+
+void DlgEdView::MakeVisible( const tools::Rectangle& rRect, vcl::Window& rWin )
+{
+ // visible area
+ MapMode aMap( rWin.GetMapMode() );
+ Point aOrg( aMap.GetOrigin() );
+ Size aVisSize( rWin.GetOutDev()->GetOutputSize() );
+ tools::Rectangle RectTmp( Point(-aOrg.X(),-aOrg.Y()), aVisSize );
+ tools::Rectangle aVisRect( RectTmp );
+
+ // check, if rectangle is inside visible area
+ if ( aVisRect.Contains( rRect ) )
+ return;
+
+ // calculate scroll distance; the rectangle must be inside the visible area
+ sal_Int32 nScrollX = 0, nScrollY = 0;
+
+ sal_Int32 nVisLeft = aVisRect.Left();
+ sal_Int32 nVisRight = aVisRect.Right();
+ sal_Int32 nVisTop = aVisRect.Top();
+ sal_Int32 nVisBottom = aVisRect.Bottom();
+
+ sal_Int32 nDeltaX = rDlgEditor.GetHScroll()->GetLineSize();
+ sal_Int32 nDeltaY = rDlgEditor.GetVScroll()->GetLineSize();
+
+ while ( rRect.Right() > nVisRight + nScrollX )
+ nScrollX += nDeltaX;
+
+ while ( rRect.Left() < nVisLeft + nScrollX )
+ nScrollX -= nDeltaX;
+
+ while ( rRect.Bottom() > nVisBottom + nScrollY )
+ nScrollY += nDeltaY;
+
+ while ( rRect.Top() < nVisTop + nScrollY )
+ nScrollY -= nDeltaY;
+
+ // don't scroll beyond the page size
+ Size aPageSize = rDlgEditor.GetPage().GetSize();
+ sal_Int32 nPageWidth = aPageSize.Width();
+ sal_Int32 nPageHeight = aPageSize.Height();
+
+ if ( nVisRight + nScrollX > nPageWidth )
+ nScrollX = nPageWidth - nVisRight;
+
+ if ( nVisLeft + nScrollX < 0 )
+ nScrollX = -nVisLeft;
+
+ if ( nVisBottom + nScrollY > nPageHeight )
+ nScrollY = nPageHeight - nVisBottom;
+
+ if ( nVisTop + nScrollY < 0 )
+ nScrollY = -nVisTop;
+
+ // scroll window
+ rWin.PaintImmediately();
+ rWin.Scroll( -nScrollX, -nScrollY );
+ aMap.SetOrigin( Point( aOrg.X() - nScrollX, aOrg.Y() - nScrollY ) );
+ rWin.SetMapMode( aMap );
+ rWin.Invalidate();
+
+ // update scroll bars
+ rDlgEditor.UpdateScrollBars();
+
+ DlgEdHint aHint( DlgEdHint::WINDOWSCROLLED );
+ rDlgEditor.Broadcast( aHint );
+}
+
+static SdrObject* impLocalHitCorrection(SdrObject* pRetval, const Point& rPnt, sal_uInt16 nTol)
+{
+ DlgEdObj* pDlgEdObj = dynamic_cast< DlgEdObj* >(pRetval);
+
+ if(pDlgEdObj)
+ {
+ bool bExcludeInner(false);
+
+ if(dynamic_cast< DlgEdForm* >(pRetval) != nullptr)
+ {
+ // from DlgEdForm::CheckHit; exclude inner for DlgEdForm
+ bExcludeInner = true;
+ }
+ else if(pDlgEdObj->supportsService("com.sun.star.awt.UnoControlGroupBoxModel"))
+ {
+ // from DlgEdObj::CheckHit; exclude inner for group shapes
+ bExcludeInner = true;
+ }
+
+ if(bExcludeInner)
+ {
+ // use direct model data; it's a DlgEdObj, so GetLastBoundRect()
+ // will access aOutRect directly
+ const tools::Rectangle aOuterRectangle(pDlgEdObj->GetLastBoundRect());
+
+ if(!aOuterRectangle.IsEmpty())
+ {
+ basegfx::B2DRange aOuterRange = vcl::unotools::b2DRectangleFromRectangle(aOuterRectangle);
+
+ if(nTol)
+ {
+ aOuterRange.grow(-1.0 * nTol);
+ }
+
+ if(aOuterRange.isInside(basegfx::B2DPoint(rPnt.X(), rPnt.Y())))
+ {
+ pRetval = nullptr;
+ }
+ }
+ }
+ }
+
+ return pRetval;
+}
+
+SdrObject* DlgEdView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay) const
+{
+ // call parent
+ SdrObject* pRetval = SdrView::CheckSingleSdrObjectHit(rPnt, nTol, pObj, pPV, nOptions, pMVisLay);
+
+ if(pRetval)
+ {
+ // check hit object locally
+ pRetval = impLocalHitCorrection(pRetval, rPnt, nTol);
+ }
+
+ return pRetval;
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/dlged/managelang.cxx b/basctl/source/dlged/managelang.cxx
new file mode 100644
index 0000000000..69f366ed66
--- /dev/null
+++ b/basctl/source/dlged/managelang.cxx
@@ -0,0 +1,318 @@
+/* -*- 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 <basobj.hxx>
+#include <iderdll.hxx>
+#include <iderid.hxx>
+#include <localizationmgr.hxx>
+#include <managelang.hxx>
+
+#include <strings.hrc>
+
+#include <comphelper/sequence.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <svtools/langtab.hxx>
+#include <svx/langbox.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/settings.hxx>
+#include <tools/debug.hxx>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::resource;
+using namespace ::com::sun::star::uno;
+
+bool localesAreEqual( const Locale& rLocaleLeft, const Locale& rLocaleRight )
+{
+ bool bRet = ( rLocaleLeft.Language == rLocaleRight.Language &&
+ rLocaleLeft.Country == rLocaleRight.Country &&
+ rLocaleLeft.Variant == rLocaleRight.Variant );
+ return bRet;
+}
+
+ManageLanguageDialog::ManageLanguageDialog(weld::Window* pParent, std::shared_ptr<LocalizationMgr> xLMgr)
+ : GenericDialogController(pParent, "modules/BasicIDE/ui/managelanguages.ui", "ManageLanguagesDialog")
+ , m_xLocalizationMgr(std::move(xLMgr))
+ , m_sDefLangStr(IDEResId(RID_STR_DEF_LANG))
+ , m_sCreateLangStr(IDEResId(RID_STR_CREATE_LANG))
+ , m_xLanguageLB(m_xBuilder->weld_tree_view("treeview"))
+ , m_xAddPB(m_xBuilder->weld_button("add"))
+ , m_xDeletePB(m_xBuilder->weld_button("delete"))
+ , m_xMakeDefPB(m_xBuilder->weld_button("default"))
+{
+ m_xLanguageLB->set_size_request(m_xLanguageLB->get_approximate_digit_width() * 42,
+ m_xLanguageLB->get_height_rows(10));
+
+ Init();
+ FillLanguageBox();
+ SelectHdl( *m_xLanguageLB );
+}
+
+ManageLanguageDialog::~ManageLanguageDialog()
+{
+ ClearLanguageBox();
+}
+
+void ManageLanguageDialog::Init()
+{
+ // get current IDE
+ Shell* pShell = GetShell();
+ const OUString& sLibName = pShell->GetCurLibName();
+ // set dialog title with library name
+ OUString sText = m_xDialog->get_title();
+ sText = sText.replaceAll("$1", sLibName);
+ m_xDialog->set_title(sText);
+ // set handler
+ m_xAddPB->connect_clicked( LINK( this, ManageLanguageDialog, AddHdl ) );
+ m_xDeletePB->connect_clicked( LINK( this, ManageLanguageDialog, DeleteHdl ) );
+ m_xMakeDefPB->connect_clicked( LINK( this, ManageLanguageDialog, MakeDefHdl ) );
+ m_xLanguageLB->connect_changed( LINK( this, ManageLanguageDialog, SelectHdl ) );
+
+ m_xLanguageLB->set_selection_mode(SelectionMode::Multiple);
+}
+
+void ManageLanguageDialog::FillLanguageBox()
+{
+ DBG_ASSERT( m_xLocalizationMgr, "ManageLanguageDialog::FillLanguageBox(): no localization manager" );
+
+ if ( m_xLocalizationMgr->isLibraryLocalized() )
+ {
+ Locale aDefaultLocale = m_xLocalizationMgr->getStringResourceManager()->getDefaultLocale();
+ Sequence< Locale > aLocaleSeq = m_xLocalizationMgr->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] );
+ LanguageType eLangType = LanguageTag::convertToLanguageType( pLocale[i] );
+ OUString sLanguage = SvtLanguageTable::GetLanguageString( eLangType );
+ if ( bIsDefault )
+ {
+ sLanguage += " " + m_sDefLangStr;
+ }
+ LanguageEntry* pEntry = new LanguageEntry(pLocale[i], bIsDefault);
+ m_xLanguageLB->append(weld::toId(pEntry), sLanguage);
+ }
+ }
+ else
+ m_xLanguageLB->append_text(m_sCreateLangStr);
+}
+
+void ManageLanguageDialog::ClearLanguageBox()
+{
+ const sal_Int32 nCount = m_xLanguageLB->n_children();
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ LanguageEntry* pEntry = weld::fromId<LanguageEntry*>(m_xLanguageLB->get_id(i));
+ delete pEntry;
+ }
+ m_xLanguageLB->clear();
+}
+
+IMPL_LINK_NOARG(ManageLanguageDialog, AddHdl, weld::Button&, void)
+{
+ auto xDlg = std::make_shared<SetDefaultLanguageDialog>(m_xDialog.get(), m_xLocalizationMgr);
+ weld::DialogController::runAsync(xDlg, [xDlg,this](sal_Int32 nResult)
+ {
+ if (!nResult )
+ return;
+ // add new locales
+ Sequence< Locale > aLocaleSeq = xDlg->GetLocales();
+ m_xLocalizationMgr->handleAddLocales( aLocaleSeq );
+ // update listbox
+ ClearLanguageBox();
+ FillLanguageBox();
+
+ if (SfxBindings* pBindings = GetBindingsPtr())
+ pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG );
+ });
+}
+
+IMPL_LINK_NOARG(ManageLanguageDialog, DeleteHdl, weld::Button&, void)
+{
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xDialog.get(), "modules/BasicIDE/ui/deletelangdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("DeleteLangDialog"));
+ if (xQBox->run() != RET_OK)
+ return;
+
+ std::vector<int> aSelection = m_xLanguageLB->get_selected_rows();
+ int nCount = aSelection.size();
+ int nPos = m_xLanguageLB->get_selected_index();
+ // remove locales
+ Sequence< Locale > aLocaleSeq( nCount );
+ auto aLocaleSeqRange = asNonConstRange(aLocaleSeq);
+ for (int i = 0; i < nCount; ++i)
+ {
+ const sal_Int32 nSelPos = aSelection[i];
+ LanguageEntry* pEntry = weld::fromId<LanguageEntry*>(m_xLanguageLB->get_id(nSelPos));
+ if ( pEntry )
+ aLocaleSeqRange[i] = pEntry->m_aLocale;
+ }
+ m_xLocalizationMgr->handleRemoveLocales( aLocaleSeq );
+ // update listbox
+ ClearLanguageBox();
+ FillLanguageBox();
+ // reset selection
+ nCount = m_xLanguageLB->n_children();
+ if (nCount <= nPos)
+ nPos = nCount - 1;
+ m_xLanguageLB->select(nPos);
+ SelectHdl( *m_xLanguageLB );
+}
+
+IMPL_LINK_NOARG(ManageLanguageDialog, MakeDefHdl, weld::Button&, void)
+{
+ const sal_Int32 nPos = m_xLanguageLB->get_selected_index();
+ LanguageEntry* pSelectEntry = weld::fromId<LanguageEntry*>(m_xLanguageLB->get_id(nPos));
+ if (pSelectEntry && !pSelectEntry->m_bIsDefault)
+ {
+ // set new default entry
+ m_xLocalizationMgr->handleSetDefaultLocale( pSelectEntry->m_aLocale );
+ // update Listbox
+ ClearLanguageBox();
+ FillLanguageBox();
+ // reset selection
+ m_xLanguageLB->select(nPos);
+ SelectHdl( *m_xLanguageLB );
+ }
+}
+
+IMPL_LINK_NOARG(ManageLanguageDialog, SelectHdl, weld::TreeView&, void)
+{
+ const sal_Int32 nCount = m_xLanguageLB->n_children();
+ bool bEmpty = ( !nCount ||
+ m_xLanguageLB->find_text(m_sCreateLangStr) != -1 );
+ bool bSelect = ( m_xLanguageLB->get_selected_index() != -1 );
+ bool bEnable = !bEmpty && bSelect;
+
+ m_xDeletePB->set_sensitive(bEnable);
+ m_xMakeDefPB->set_sensitive(bEnable && nCount > 1 && m_xLanguageLB->count_selected_rows() == 1);
+}
+
+// class SetDefaultLanguageDialog -----------------------------------------------
+
+SetDefaultLanguageDialog::SetDefaultLanguageDialog(weld::Window* pParent, std::shared_ptr<LocalizationMgr> xLMgr)
+ : GenericDialogController(pParent, "modules/BasicIDE/ui/defaultlanguage.ui", "DefaultLanguageDialog")
+ , m_xLocalizationMgr(std::move(xLMgr))
+ , m_xLanguageFT(m_xBuilder->weld_label("defaultlabel"))
+ , m_xLanguageLB(m_xBuilder->weld_tree_view("entries"))
+ , m_xCheckLangFT(m_xBuilder->weld_label("checkedlabel"))
+ , m_xCheckLangLB(m_xBuilder->weld_tree_view("checkedentries"))
+ , m_xDefinedFT(m_xBuilder->weld_label("defined"))
+ , m_xAddedFT(m_xBuilder->weld_label("added"))
+ , m_xAltTitle(m_xBuilder->weld_label("alttitle"))
+ , m_xLanguageCB(new SvxLanguageBox(m_xBuilder->weld_combo_box("hidden")))
+{
+ m_xLanguageLB->set_size_request(-1, m_xLanguageLB->get_height_rows(10));
+ m_xCheckLangLB->set_size_request(-1, m_xCheckLangLB->get_height_rows(10));
+ m_xCheckLangLB->enable_toggle_buttons(weld::ColumnToggleType::Check);
+
+ if (m_xLocalizationMgr->isLibraryLocalized())
+ {
+ // change to "Add Interface Language" mode
+ m_xLanguageLB->hide();
+ m_xCheckLangLB->show();
+ m_xDialog->set_title(m_xAltTitle->get_label());
+ m_xLanguageFT->hide();
+ m_xCheckLangFT->show();
+ m_xDefinedFT->hide();
+ m_xAddedFT->show();
+ }
+
+ FillLanguageBox();
+}
+
+SetDefaultLanguageDialog::~SetDefaultLanguageDialog()
+{
+}
+
+void SetDefaultLanguageDialog::FillLanguageBox()
+{
+ // fill list with all languages
+ m_xLanguageCB->SetLanguageList(SvxLanguageListFlags::ALL, false);
+
+ if (m_xLocalizationMgr->isLibraryLocalized())
+ {
+ // remove the already localized languages
+ Sequence< Locale > aLocaleSeq = m_xLocalizationMgr->getStringResourceManager()->getLocales();
+ const Locale* pLocale = aLocaleSeq.getConstArray();
+ const sal_Int32 nCountLoc = aLocaleSeq.getLength();
+ for ( sal_Int32 i = 0; i < nCountLoc; ++i )
+ m_xLanguageCB->remove_id(LanguageTag::convertToLanguageType(pLocale[i]));
+
+ // fill checklistbox if not in default mode
+ const sal_Int32 nCountLang = m_xLanguageCB->get_count();
+ for (sal_Int32 j = 0; j < nCountLang; ++j)
+ {
+ LanguageType eLang = m_xLanguageCB->get_id(j);
+ m_xCheckLangLB->append();
+ const int nRow = m_xCheckLangLB->n_children() - 1;
+ m_xCheckLangLB->set_toggle(nRow, TRISTATE_FALSE);
+ m_xCheckLangLB->set_text(nRow, m_xLanguageCB->get_text(j), 0);
+ m_xCheckLangLB->set_id(nRow, OUString::number(eLang.get()));
+ }
+ m_xLanguageCB.reset();
+ m_xLanguageLB.reset();
+ }
+ else
+ {
+ const sal_Int32 nCountLang = m_xLanguageCB->get_count();
+ for (sal_Int32 j = 0; j < nCountLang; ++j)
+ {
+ LanguageType eLang = m_xLanguageCB->get_id(j);
+ m_xLanguageLB->append(OUString::number(eLang.get()), m_xLanguageCB->get_text(j));
+ }
+ m_xLanguageCB.reset();
+
+ // preselect current UI language
+ m_xLanguageLB->select_id(OUString::number(Application::GetSettings().GetUILanguageTag().getLanguageType().get()));
+ }
+}
+
+Sequence< Locale > SetDefaultLanguageDialog::GetLocales() const
+{
+ bool bNotLocalized = !m_xLocalizationMgr->isLibraryLocalized();
+ if (bNotLocalized)
+ {
+ LanguageType eType(m_xLanguageLB->get_selected_id().toUInt32());
+ return {LanguageTag(eType).getLocale()};
+ }
+ std::vector<Locale> aLocaleSeq;
+ const sal_Int32 nCount = m_xCheckLangLB->n_children();
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ if (m_xCheckLangLB->get_toggle(i) == TRISTATE_TRUE)
+ {
+ LanguageType eType(m_xCheckLangLB->get_id(i).toUInt32());
+ aLocaleSeq.push_back(LanguageTag::convertToLocale(eType));
+ }
+ }
+ return comphelper::containerToSequence(aLocaleSeq);
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/dlged/propbrw.cxx b/basctl/source/dlged/propbrw.cxx
new file mode 100644
index 0000000000..bb45d5f13e
--- /dev/null
+++ b/basctl/source/dlged/propbrw.cxx
@@ -0,0 +1,506 @@
+/* -*- 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 <propbrw.hxx>
+#include <basidesh.hxx>
+#include <dlgedobj.hxx>
+#include <iderid.hxx>
+#include <baside3.hxx>
+#include <strings.hrc>
+
+#include <strings.hxx>
+
+#include <com/sun/star/frame/Frame.hpp>
+#include <com/sun/star/inspection/XObjectInspector.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <comphelper/types.hxx>
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/component_context.hxx>
+#include <tools/debug.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdview.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <vcl/layout.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/weld.hxx>
+
+#include <memory>
+
+namespace basctl
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::comphelper;
+
+
+void PropBrw::Update( const SfxViewShell* pShell )
+{
+ Shell const* pIdeShell = dynamic_cast<Shell const*>(pShell);
+ OSL_ENSURE( pIdeShell || !pShell, "PropBrw::Update: invalid shell!" );
+ if (pIdeShell)
+ ImplUpdate(pIdeShell->GetCurrentDocument(), pIdeShell->GetCurDlgView());
+ else if (pShell)
+ ImplUpdate(nullptr, pShell->GetDrawView());
+ else
+ ImplUpdate(nullptr, nullptr);
+}
+
+
+namespace
+{
+
+const tools::Long STD_WIN_SIZE_X = 300;
+const tools::Long STD_WIN_SIZE_Y = 350;
+
+const tools::Long STD_MIN_SIZE_X = 250;
+const tools::Long STD_MIN_SIZE_Y = 250;
+
+const tools::Long WIN_BORDER = 2;
+
+} // namespace
+
+PropBrw::PropBrw (DialogWindowLayout& rLayout_):
+ DockingWindow(&rLayout_),
+ m_xContentArea(VclPtr<VclVBox>::Create(this)),
+ m_bInitialStateChange(true),
+ m_xContextDocument(SfxViewShell::Current() ? SfxViewShell::Current()->GetCurrentDocument() : Reference<XModel>()),
+ pView(nullptr)
+{
+ Size aPropWinSize(STD_WIN_SIZE_X,STD_WIN_SIZE_Y);
+ SetMinOutputSizePixel(Size(STD_MIN_SIZE_X,STD_MIN_SIZE_Y));
+ SetOutputSizePixel(aPropWinSize);
+
+ // turn off WB_CLIPCHILDREN otherwise the bg won't extend "under"
+ // transparent children of the widget
+ m_xContentArea->SetControlBackground(m_xContentArea->GetSettings().GetStyleSettings().GetWindowColor());
+ m_xContentArea->SetBackground(m_xContentArea->GetControlBackground());
+ m_xContentArea->SetStyle(m_xContentArea->GetStyle() & ~WB_CLIPCHILDREN);
+ m_xContentArea->Show();
+
+ try
+ {
+ // create a frame wrapper for myself
+ m_xMeAsFrame = frame::Frame::create( comphelper::getProcessComponentContext() );
+ m_xMeAsFrame->initialize(VCLUnoHelper::GetInterface(m_xContentArea));
+ m_xMeAsFrame->setName( "form property browser" ); // change name!
+ }
+ catch (const Exception&)
+ {
+ OSL_FAIL("PropBrw::PropBrw: could not create/initialize my frame!");
+ m_xMeAsFrame.clear();
+ }
+
+ ImplReCreateController();
+}
+
+
+void PropBrw::ImplReCreateController()
+{
+ OSL_PRECOND( m_xMeAsFrame.is(), "PropBrw::ImplCreateController: no frame for myself!" );
+ if ( !m_xMeAsFrame.is() )
+ return;
+
+ if ( m_xBrowserController.is() )
+ ImplDestroyController();
+
+ try
+ {
+ Reference< XComponentContext > xOwnContext = comphelper::getProcessComponentContext();
+
+ // a ComponentContext for the
+ ::cppu::ContextEntry_Init aHandlerContextInfo[] =
+ {
+ ::cppu::ContextEntry_Init( "DialogParentWindow", Any(VCLUnoHelper::GetInterface(this))),
+ ::cppu::ContextEntry_Init( "ContextDocument", Any( m_xContextDocument ) )
+ };
+ Reference< XComponentContext > xInspectorContext(
+ ::cppu::createComponentContext( aHandlerContextInfo, std::size( aHandlerContextInfo ), xOwnContext ) );
+
+ // create a property browser controller
+ Reference< XMultiComponentFactory > xFactory( xInspectorContext->getServiceManager(), UNO_SET_THROW );
+ static constexpr OUString s_sControllerServiceName = u"com.sun.star.awt.PropertyBrowserController"_ustr;
+ m_xBrowserController.set( xFactory->createInstanceWithContext( s_sControllerServiceName, xInspectorContext ), UNO_QUERY );
+ if ( !m_xBrowserController.is() )
+ {
+ vcl::Window* pWin = GetParent();
+ ShowServiceNotAvailableError(pWin ? pWin->GetFrameWeld() : nullptr, s_sControllerServiceName, true);
+ }
+ else
+ {
+ Reference< XController > xAsXController( m_xBrowserController, UNO_QUERY );
+ DBG_ASSERT(xAsXController.is(), "PropBrw::PropBrw: invalid controller object!");
+ if (!xAsXController.is())
+ {
+ ::comphelper::disposeComponent(m_xBrowserController);
+ m_xBrowserController.clear();
+ }
+ else
+ {
+ xAsXController->attachFrame( Reference<XFrame>(m_xMeAsFrame,UNO_QUERY_THROW) );
+ }
+ }
+
+ Point aPropWinPos( WIN_BORDER, WIN_BORDER );
+ Size aPropWinSize(STD_WIN_SIZE_X,STD_WIN_SIZE_Y);
+ aPropWinSize.AdjustWidth( -(2*WIN_BORDER) );
+ aPropWinSize.AdjustHeight( -(2*WIN_BORDER) );
+
+ VclContainer::setLayoutAllocation(*m_xContentArea, aPropWinPos, aPropWinSize);
+ m_xContentArea->Show();
+ }
+ catch (const Exception&)
+ {
+ OSL_FAIL("PropBrw::PropBrw: could not create/initialize the browser controller!");
+ try
+ {
+ ::comphelper::disposeComponent(m_xBrowserController);
+ }
+ catch(const Exception&)
+ {
+ }
+
+ m_xBrowserController.clear();
+ }
+ Resize();
+}
+
+PropBrw::~PropBrw()
+{
+ disposeOnce();
+}
+
+void PropBrw::dispose()
+{
+ if ( m_xBrowserController.is() )
+ ImplDestroyController();
+ m_xContentArea.disposeAndClear();
+ DockingWindow::dispose();
+}
+
+
+void PropBrw::ImplDestroyController()
+{
+ implSetNewObject( Reference< XPropertySet >() );
+
+ if ( m_xMeAsFrame.is() )
+ m_xMeAsFrame->setComponent( nullptr, nullptr );
+
+ Reference< XController > xAsXController( m_xBrowserController, UNO_QUERY );
+ if ( xAsXController.is() )
+ xAsXController->attachFrame( nullptr );
+
+ try
+ {
+ ::comphelper::disposeComponent( m_xBrowserController );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl");
+ }
+
+ m_xBrowserController.clear();
+}
+
+bool PropBrw::Close()
+{
+ ImplDestroyController();
+
+ return DockingWindow::Close();
+}
+
+Sequence< Reference< XInterface > >
+ PropBrw::CreateMultiSelectionSequence( const SdrMarkList& _rMarkList )
+{
+ Sequence< Reference< XInterface > > aSeq;
+ InterfaceArray aInterfaces;
+
+ const size_t nMarkCount = _rMarkList.GetMarkCount();
+ for( size_t i = 0 ; i < nMarkCount ; ++i )
+ {
+ SdrObject* pCurrent = _rMarkList.GetMark(i)->GetMarkedSdrObj();
+
+ std::optional<SdrObjListIter> oGroupIterator;
+ if (pCurrent->IsGroupObject())
+ {
+ oGroupIterator.emplace(pCurrent->GetSubList());
+ pCurrent = oGroupIterator->IsMore() ? oGroupIterator->Next() : nullptr;
+ }
+
+ while (pCurrent)
+ {
+ if (DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pCurrent))
+ {
+ Reference< XInterface > xControlInterface(pDlgEdObj->GetUnoControlModel(), UNO_QUERY);
+ if (xControlInterface.is())
+ aInterfaces.push_back(xControlInterface);
+ }
+
+ // next element
+ pCurrent = oGroupIterator && oGroupIterator->IsMore() ? oGroupIterator->Next() : nullptr;
+ }
+ }
+
+ sal_Int32 nCount = aInterfaces.size();
+ aSeq.realloc( nCount );
+ Reference< XInterface >* pInterfaces = aSeq.getArray();
+ for( sal_Int32 i = 0 ; i < nCount ; i++ )
+ pInterfaces[i] = aInterfaces[i];
+
+ return aSeq;
+}
+
+
+void PropBrw::implSetNewObjectSequence
+ ( const Sequence< Reference< XInterface > >& _rObjectSeq )
+{
+ Reference< inspection::XObjectInspector > xObjectInspector(m_xBrowserController, UNO_QUERY);
+ if ( xObjectInspector.is() )
+ {
+ xObjectInspector->inspect( _rObjectSeq );
+
+ OUString aText = IDEResId(RID_STR_BRWTITLE_PROPERTIES)
+ + IDEResId(RID_STR_BRWTITLE_MULTISELECT);
+ SetText( aText );
+ }
+}
+
+
+void PropBrw::implSetNewObject( const Reference< XPropertySet >& _rxObject )
+{
+ if ( m_xBrowserController.is() )
+ {
+ m_xBrowserController->setPropertyValue( "IntrospectedObject",
+ Any( _rxObject )
+ );
+
+ // set the new title according to the selected object
+ SetText( GetHeadlineName( _rxObject ) );
+ }
+}
+
+
+OUString PropBrw::GetHeadlineName( const Reference< XPropertySet >& _rxObject )
+{
+ OUString aName;
+ Reference< lang::XServiceInfo > xServiceInfo( _rxObject, UNO_QUERY );
+
+ if (xServiceInfo.is()) // single selection
+ {
+ OUString sResId;
+ aName = IDEResId(RID_STR_BRWTITLE_PROPERTIES);
+
+ if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlDialogModel" ) )
+ {
+ sResId = RID_STR_CLASS_DIALOG;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlButtonModel" ) )
+ {
+ sResId = RID_STR_CLASS_BUTTON;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlRadioButtonModel" ) )
+ {
+ sResId = RID_STR_CLASS_RADIOBUTTON;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlCheckBoxModel" ) )
+ {
+ sResId = RID_STR_CLASS_CHECKBOX;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlListBoxModel" ) )
+ {
+ sResId = RID_STR_CLASS_LISTBOX;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlComboBoxModel" ) )
+ {
+ sResId = RID_STR_CLASS_COMBOBOX;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlGroupBoxModel" ) )
+ {
+ sResId = RID_STR_CLASS_GROUPBOX;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlEditModel" ) )
+ {
+ sResId = RID_STR_CLASS_EDIT;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlFixedTextModel" ) )
+ {
+ sResId = RID_STR_CLASS_FIXEDTEXT;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlImageControlModel" ) )
+ {
+ sResId = RID_STR_CLASS_IMAGECONTROL;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlProgressBarModel" ) )
+ {
+ sResId = RID_STR_CLASS_PROGRESSBAR;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlScrollBarModel" ) )
+ {
+ sResId = RID_STR_CLASS_SCROLLBAR;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlFixedLineModel" ) )
+ {
+ sResId = RID_STR_CLASS_FIXEDLINE;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlDateFieldModel" ) )
+ {
+ sResId = RID_STR_CLASS_DATEFIELD;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlTimeFieldModel" ) )
+ {
+ sResId = RID_STR_CLASS_TIMEFIELD;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlNumericFieldModel" ) )
+ {
+ sResId = RID_STR_CLASS_NUMERICFIELD;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlCurrencyFieldModel" ) )
+ {
+ sResId = RID_STR_CLASS_CURRENCYFIELD;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlFormattedFieldModel" ) )
+ {
+ sResId = RID_STR_CLASS_FORMATTEDFIELD;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlPatternFieldModel" ) )
+ {
+ sResId = RID_STR_CLASS_PATTERNFIELD;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlFileControlModel" ) )
+ {
+ sResId = RID_STR_CLASS_FILECONTROL;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.tree.TreeControlModel" ) )
+ {
+ sResId = RID_STR_CLASS_TREECONTROL;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.grid.UnoControlGridModel" ) )
+ {
+ sResId = RID_STR_CLASS_GRIDCONTROL;
+ }
+ else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlFixedHyperlinkModel" ) )
+ {
+ sResId = RID_STR_CLASS_HYPERLINKCONTROL;
+ }
+ else
+ {
+ sResId = RID_STR_CLASS_CONTROL;
+ }
+
+ if (!sResId.isEmpty())
+ {
+ aName += sResId;
+ }
+ }
+ else if (!_rxObject.is()) // no properties
+ {
+ aName = IDEResId(RID_STR_BRWTITLE_NO_PROPERTIES);
+ }
+
+ return aName;
+}
+
+void PropBrw::ImplUpdate( const Reference< XModel >& _rxContextDocument, SdrView* pNewView )
+{
+ Reference< XModel > xContextDocument( _rxContextDocument );
+
+ // if we should simply "empty" ourself, assume the context document didn't change
+ if ( !pNewView )
+ {
+ OSL_ENSURE( !_rxContextDocument.is(), "PropBrw::ImplUpdate: no view, but a document?!" );
+ xContextDocument = m_xContextDocument;
+ }
+
+ if ( xContextDocument != m_xContextDocument )
+ {
+ m_xContextDocument = xContextDocument;
+ ImplReCreateController();
+ }
+
+ try
+ {
+ if ( pView )
+ {
+ EndListening(pView->GetModel());
+ pView = nullptr;
+ }
+
+ if ( !pNewView )
+ return;
+
+ pView = pNewView;
+
+ // set focus on initialization
+ if ( m_bInitialStateChange )
+ {
+ m_xContentArea->GrabFocus();
+ m_bInitialStateChange = false;
+ }
+
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+
+ if ( nMarkCount == 0 )
+ {
+ EndListening(pView->GetModel());
+ pView = nullptr;
+ implSetNewObject( nullptr );
+ return;
+ }
+
+ Reference< XPropertySet > xNewObject;
+ Sequence< Reference< XInterface > > aNewObjects;
+ if ( nMarkCount == 1 )
+ {
+ if (DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(rMarkList.GetMark(0)->GetMarkedSdrObj()))
+ {
+ if ( pDlgEdObj->IsGroupObject() ) // group object
+ aNewObjects = CreateMultiSelectionSequence( rMarkList );
+ else // single selection
+ xNewObject.set(pDlgEdObj->GetUnoControlModel(), css::uno::UNO_QUERY);
+ }
+ }
+ else if ( nMarkCount > 1 ) // multiple selection
+ {
+ aNewObjects = CreateMultiSelectionSequence( rMarkList );
+ }
+
+ if ( aNewObjects.hasElements() )
+ implSetNewObjectSequence( aNewObjects );
+ else
+ implSetNewObject( xNewObject );
+
+ StartListening(pView->GetModel());
+ }
+ catch ( const PropertyVetoException& ) { /* silence */ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basctl");
+ }
+}
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/IDEComboBox.hxx b/basctl/source/inc/IDEComboBox.hxx
new file mode 100644
index 0000000000..a5e7008a42
--- /dev/null
+++ b/basctl/source/inc/IDEComboBox.hxx
@@ -0,0 +1,271 @@
+/* -*- 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 <svl/stritem.hxx>
+#include <sfx2/tbxctrl.hxx>
+#include <vcl/InterimItemWindow.hxx>
+
+#include "doceventnotifier.hxx"
+#include "scriptdocument.hxx"
+
+namespace basctl
+{
+/*!
+ * @brief Manage states of macro and dialog Library ComboBox
+ *
+ * @see LibBox Class
+ */
+class LibBoxControl : public SfxToolBoxControl
+{
+public:
+ /*!
+ * Macro for registering two methods
+ *
+ * @code
+ * static SfxToolBoxControl* CreateImpl(sal_uInt16 nSlotId, sal_uInt16 nId, ToolBox& rTbx)
+ * static void RegisterControl(sal_uInt16 nSlotId = 0, SfxModule* pMod=nullptr)
+ * @endcode
+ * @see Macro SFX_IMPL_TOOLBOX_CONTROL
+ */
+ SFX_DECL_TOOLBOX_CONTROL();
+
+ /*!
+ * @param nSlotId -- the slot as internal operation number
+ * @param nId -- this item's unique id in ToolBox
+ * @param rTbx -- the ToolBox which contains this ComboBox
+ */
+ LibBoxControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx);
+
+ /*!
+ * Triggered if state was changed
+ *
+ * @param nSlotID -- the slot as internal operation number (not used in this place)
+ * @param eState -- enum value which contains ComboBox state
+ * @param pState --
+ */
+ virtual void StateChangedAtToolBoxControl(sal_uInt16 nSlotID, SfxItemState eState,
+ const SfxPoolItem* pState) override;
+ /*!
+ * Create combobox of Macro and Dialog Library
+ *
+ * @param pParent -- parent window
+ * @return ComboBox of macro and dialog Library
+ */
+ virtual VclPtr<InterimItemWindow> CreateItemWindow(vcl::Window* pParent) override;
+};
+
+/*!
+ * @brief Base class for all ComboBox elements.
+ *
+ * Base class for ComboBoxes which need to update their content according
+ * to the list of open documents.
+ */
+class DocListenerBox : public InterimItemWindow, public DocumentEventListener
+{
+private:
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+
+protected:
+ std::unique_ptr<weld::ComboBox> m_xWidget;
+
+ /// @param pParent -- parent window
+ DocListenerBox(vcl::Window* pParent);
+ virtual ~DocListenerBox() override;
+ virtual void dispose() override;
+
+ virtual void Select() = 0;
+ virtual void FillBox() = 0;
+
+ /// key strokes the ComboBox receives
+ virtual bool HandleKeyInput(const KeyEvent& rKEvt);
+
+private:
+ // DocumentEventListener
+ virtual void onDocumentCreated(const ScriptDocument& _rDoc) override;
+ virtual void onDocumentOpened(const ScriptDocument& _rDoc) override;
+ virtual void onDocumentSave(const ScriptDocument& _rDoc) override;
+ virtual void onDocumentSaveDone(const ScriptDocument& _rDoc) override;
+ virtual void onDocumentSaveAs(const ScriptDocument& _rDoc) override;
+ virtual void onDocumentSaveAsDone(const ScriptDocument& _rDoc) override;
+ virtual void onDocumentClosed(const ScriptDocument& _rDoc) override;
+ virtual void onDocumentTitleChanged(const ScriptDocument& _rDoc) override;
+ virtual void onDocumentModeChanged(const ScriptDocument& _rDoc) override;
+
+ DocumentEventNotifier maNotifier;
+
+public:
+ void set_sensitive(bool bSensitive);
+};
+
+/*!
+ * @brief Macros and Dialogs Library ComboBox
+ *
+ * @see LibBoxControl Class
+ */
+class LibBox : public DocListenerBox
+{
+public:
+ /// @param pParent
+ LibBox(vcl::Window* pParent);
+ virtual ~LibBox() override;
+ virtual void dispose() override;
+
+ /*!
+ * Update selection in ComboBox of macro and dialog Library
+ *
+ * @param pItem -- string that was selected
+ */
+ void Update(const SfxStringItem* pItem);
+
+protected:
+ /// Called for setting language when user selects a language in ComboBox
+ virtual void Select() override;
+
+private:
+ static void ReleaseFocus();
+
+ /*!
+ * Insert name library in specified position
+ *
+ * @param rDocument -- macro or dialog
+ * @param eLocation -- enum value of Locations
+ */
+ void InsertEntries(const ScriptDocument& rDocument, LibraryLocation eLocation);
+
+ void ClearBox();
+ void NotifyIDE();
+
+ /// Fill up the combobox
+ virtual void FillBox() override;
+
+ /*!
+ * Handle keystrokes
+ *
+ * @param rKEvt represents key event
+ * @return a bool value: true if was handled, and false if there was nothing handled
+ */
+ virtual bool HandleKeyInput(const KeyEvent& rKEvt) override;
+
+ DECL_LINK(FocusInHdl, weld::Widget&, void);
+ DECL_LINK(FocusOutHdl, weld::Widget&, void);
+
+ OUString maCurrentText;
+ bool mbIgnoreSelect;
+ bool mbFillBox; ///< If true, when FillBox() is called
+};
+
+/*!
+ * @brief Manage stats of Language ComboBox
+ *
+ * @see LanguageBox Class
+ */
+class LanguageBoxControl : public SfxToolBoxControl
+{
+public:
+ /*! Macro for registering two methods
+ *
+ * @code
+ * static SfxToolBoxControl* CreateImpl(sal_uInt16 nSlotId, sal_uInt16 nId, ToolBox& rTbx)
+ * static void RegisterControl(sal_uInt16 nSlotId = 0, SfxModule* pMod=nullptr)
+ * @endcode
+ * @see Macro SFX_IMPL_TOOLBOX_CONTROL
+ */
+ SFX_DECL_TOOLBOX_CONTROL();
+
+ /*!
+ * @param nSlotId -- the slot as internal operation number
+ * @param nId -- this item's unique id in ToolBox
+ * @param rTbx -- the ToolBox which contains this ComboBox
+ */
+ LanguageBoxControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx);
+
+ /*!
+ * Triggered if state was changed
+ *
+ * @param nSlotID -- the slot as internal operation number (not used in this place)
+ * @param eState -- enum value which contains ComboBox state
+ * @param pState --
+ */
+ virtual void StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState) override;
+ /*!
+ * Create ComboBox of Language
+ *
+ * @param pParent
+ * @return LanguageBox ComboBox
+ */
+ virtual VclPtr<InterimItemWindow> CreateItemWindow(vcl::Window* pParent) override;
+};
+
+/*!
+ * @brief Class language ComboBox
+ *
+ * @see LanguageBoxControl Class
+ */
+class LanguageBox : public DocListenerBox
+{
+public:
+ /*!
+ * @param pParent
+ */
+ LanguageBox(vcl::Window* pParent);
+ virtual ~LanguageBox() override;
+ virtual void dispose() override;
+
+ /*!
+ * Update selection in ComboBox of macro and dialog Library
+ *
+ * @param pItem -- string that was selected
+ */
+ void Update(const SfxStringItem* pItem);
+
+protected:
+ /// Called for setting language when user selects a language in ComboBox
+ virtual void Select() override;
+
+ /*!
+ * Handle keystrokes
+ *
+ * @param rKEvt represents key event
+ * @return a bool value: true if was handled, and false if there was nothing handled
+ */
+ virtual bool HandleKeyInput(const KeyEvent& rKEvt) override;
+
+private:
+ /// Delete all languages from ComboBox
+ void ClearBox();
+ /// Switch interface of dialog to selected language
+ void SetLanguage();
+
+ /// Fill up the language combobox
+ virtual void FillBox() override;
+
+ OUString msNotLocalizedStr;
+ OUString msDefaultLanguageStr;
+ OUString msCurrentText;
+
+ bool mbIgnoreSelect; ///< do not use in this class
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/ObjectCatalog.hxx b/basctl/source/inc/ObjectCatalog.hxx
new file mode 100644
index 0000000000..a5b63eef42
--- /dev/null
+++ b/basctl/source/inc/ObjectCatalog.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 "bastype2.hxx"
+#include "bastypes.hxx"
+
+#include <vcl/weld.hxx>
+
+namespace basctl
+{
+/*!
+ * @brief A docking window that contains a tree of the currently loaded macros
+ *
+ * The class creates Object Catalog window with the currently loaded macros
+ * in a tree structure which allows user to quickly select the necessary
+ * macro in BasicIDE.
+ */
+class ObjectCatalog : public DockingWindow
+{
+public:
+ explicit ObjectCatalog(vcl::Window* pParent);
+ virtual ~ObjectCatalog() override;
+ virtual void dispose() override;
+
+ /// Update the entries of Object Catalog Treelist
+ void UpdateEntries() { m_xTree->UpdateEntries(); }
+ void SetCurrentEntry(BaseWindow* pCurWin);
+
+private:
+ std::unique_ptr<weld::Label> m_xTitle; ///< Title of the Object Catalog window
+ std::unique_ptr<SbTreeListBox> m_xTree; ///< The Treelist of the objects in window
+
+ /*!
+ * Function for resize by DockingWindow.
+ * It is called by DockingWindow when IsFloatingMode() changes.
+ */
+ virtual void ToggleFloatingMode() override;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/accessibledialogcontrolshape.hxx b/basctl/source/inc/accessibledialogcontrolshape.hxx
new file mode 100644
index 0000000000..3af6e3da90
--- /dev/null
+++ b/basctl/source/inc/accessibledialogcontrolshape.hxx
@@ -0,0 +1,120 @@
+/* -*- 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/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <comphelper/accessiblecomponenthelper.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <vcl/vclptr.hxx>
+
+namespace vcl { class Window; }
+
+namespace basctl
+{
+
+class DlgEdObj;
+class DialogWindow;
+
+
+
+class AccessibleDialogControlShape final : public cppu::ImplInheritanceHelper<
+ comphelper::OAccessibleExtendedComponentHelper,
+ css::accessibility::XAccessible,
+ css::lang::XServiceInfo,
+ css::beans::XPropertyChangeListener>
+{
+ friend class AccessibleDialogWindow;
+
+private:
+ VclPtr<DialogWindow> m_pDialogWindow;
+ DlgEdObj* m_pDlgEdObj;
+ bool m_bFocused;
+ bool m_bSelected;
+
+ css::awt::Rectangle m_aBounds;
+ css::uno::Reference< css::beans::XPropertySet > m_xControlModel;
+
+ bool IsFocused() const;
+ bool IsSelected() const;
+
+ void SetFocused (bool bFocused);
+ void SetSelected (bool bSelected);
+
+ css::awt::Rectangle GetBounds() const;
+ void SetBounds( const css::awt::Rectangle& aBounds );
+
+ vcl::Window* GetWindow() const;
+
+ OUString GetModelStringProperty( OUString const & pPropertyName );
+
+ void FillAccessibleStateSet( sal_Int64& rStateSet );
+
+ // OCommonAccessibleComponent
+ virtual css::awt::Rectangle implGetBounds() override;
+
+ // XComponent
+ virtual void SAL_CALL disposing() override;
+
+public:
+ AccessibleDialogControlShape (DialogWindow*, DlgEdObj*);
+ virtual ~AccessibleDialogControlShape() override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& rSource ) override;
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& rEvent ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XAccessible
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override;
+
+ // XAccessibleContext
+ virtual sal_Int64 SAL_CALL getAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int64 i ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
+ virtual sal_Int64 SAL_CALL getAccessibleIndexInParent( ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
+ virtual OUString SAL_CALL getAccessibleDescription( ) override;
+ virtual OUString SAL_CALL getAccessibleName( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
+ virtual sal_Int64 SAL_CALL getAccessibleStateSet( ) override;
+ virtual css::lang::Locale SAL_CALL getLocale( ) override;
+
+ // XAccessibleComponent
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+ virtual void SAL_CALL grabFocus( ) override;
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ // XAccessibleExtendedComponent
+ virtual css::uno::Reference< css::awt::XFont > SAL_CALL getFont( ) override;
+ virtual OUString SAL_CALL getTitledBorderText( ) override;
+ virtual OUString SAL_CALL getToolTipText( ) override;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/accessibledialogwindow.hxx b/basctl/source/inc/accessibledialogwindow.hxx
new file mode 100644
index 0000000000..0332b98a41
--- /dev/null
+++ b/basctl/source/inc/accessibledialogwindow.hxx
@@ -0,0 +1,143 @@
+/* -*- 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/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <comphelper/accessiblecomponenthelper.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <svl/lstner.hxx>
+#include <tools/link.hxx>
+#include <vcl/vclptr.hxx>
+
+class VclSimpleEvent;
+class VclWindowEvent;
+
+namespace basctl
+{
+
+class DialogWindow;
+class DlgEditor;
+class DlgEdModel;
+class DlgEdObj;
+class AccessibleDialogControlShape;
+
+
+class AccessibleDialogWindow final : public cppu::ImplInheritanceHelper<
+ comphelper::OAccessibleExtendedComponentHelper,
+ css::accessibility::XAccessible,
+ css::accessibility::XAccessibleSelection,
+ css::lang::XServiceInfo>,
+ public SfxListener
+{
+private:
+
+ class ChildDescriptor
+ {
+ public:
+ DlgEdObj* pDlgEdObj;
+ rtl::Reference< AccessibleDialogControlShape > mxAccessible;
+
+ ChildDescriptor( DlgEdObj* _pDlgEdObj );
+
+ bool operator==( const ChildDescriptor& rDesc );
+ bool operator<( const ChildDescriptor& rDesc ) const;
+ };
+
+ typedef std::vector< ChildDescriptor > AccessibleChildren;
+
+ AccessibleChildren m_aAccessibleChildren;
+ VclPtr<basctl::DialogWindow> m_pDialogWindow;
+ DlgEdModel* m_pDlgEdModel;
+
+ void UpdateFocused();
+ void UpdateSelected();
+ void UpdateBounds();
+
+ bool IsChildVisible( const ChildDescriptor& rDesc );
+
+ void InsertChild( const ChildDescriptor& rDesc );
+ void RemoveChild( const ChildDescriptor& rDesc );
+ void UpdateChild( const ChildDescriptor& rDesc );
+ void UpdateChildren();
+ void SortChildren();
+
+ DECL_LINK( WindowEventListener, VclWindowEvent&, void );
+
+ void ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent );
+ void FillAccessibleStateSet( sal_Int64& rStateSet );
+
+ // OCommonAccessibleComponent
+ virtual css::awt::Rectangle implGetBounds( ) override;
+
+ // XComponent
+ virtual void SAL_CALL disposing() override;
+
+public:
+ AccessibleDialogWindow (basctl::DialogWindow*);
+ virtual ~AccessibleDialogWindow() override;
+
+ // SfxListener
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XAccessible
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override;
+
+ // XAccessibleContext
+ virtual sal_Int64 SAL_CALL getAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int64 i ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
+ virtual sal_Int64 SAL_CALL getAccessibleIndexInParent( ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
+ virtual OUString SAL_CALL getAccessibleDescription( ) override;
+ virtual OUString SAL_CALL getAccessibleName( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
+ virtual sal_Int64 SAL_CALL getAccessibleStateSet( ) override;
+ virtual css::lang::Locale SAL_CALL getLocale( ) override;
+
+ // XAccessibleComponent
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+ virtual void SAL_CALL grabFocus( ) override;
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ // XAccessibleExtendedComponent
+ virtual css::uno::Reference< css::awt::XFont > SAL_CALL getFont( ) override;
+ virtual OUString SAL_CALL getTitledBorderText( ) override;
+ virtual OUString SAL_CALL getToolTipText( ) override;
+
+ // XAccessibleSelection
+ virtual void SAL_CALL selectAccessibleChild( sal_Int64 nChildIndex ) override;
+ virtual sal_Bool SAL_CALL isAccessibleChildSelected( sal_Int64 nChildIndex ) override;
+ virtual void SAL_CALL clearAccessibleSelection() override;
+ virtual void SAL_CALL selectAllAccessibleChildren( ) override;
+ virtual sal_Int64 SAL_CALL getSelectedAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex ) override;
+ virtual void SAL_CALL deselectAccessibleChild( sal_Int64 nChildIndex ) override;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/baside3.hxx b/basctl/source/inc/baside3.hxx
new file mode 100644
index 0000000000..14fc68f079
--- /dev/null
+++ b/basctl/source/inc/baside3.hxx
@@ -0,0 +1,154 @@
+/* -*- 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 "dlged.hxx"
+#include "layout.hxx"
+#include "bastypes.hxx"
+#include "propbrw.hxx"
+#include <svl/undo.hxx>
+#include <memory>
+
+class Printer;
+class StarBASIC;
+class SfxItemSet;
+class SfxUndoManager;
+class SdrUndoAction;
+
+namespace basctl
+{
+
+class DlgEditor;
+class DlgEdModel;
+class DlgEdPage;
+class DlgEdView;
+
+class DialogWindowLayout;
+class ObjectCatalog;
+
+bool implImportDialog(weld::Window* pWin, const ScriptDocument& rDocument, const OUString& rLibName);
+
+class DialogWindow: public BaseWindow
+{
+private:
+ DialogWindowLayout& m_rLayout;
+ std::unique_ptr<DlgEditor> m_pEditor;
+ std::unique_ptr<SfxUndoManager> m_pUndoMgr; // never nullptr
+ sal_uInt16 m_nControlSlotId;
+
+protected:
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+ virtual void Resize() override;
+ virtual void dispose() override;
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+ virtual void KeyInput( const KeyEvent& rKEvt ) override;
+ virtual void Command( const CommandEvent& rCEvt ) override;
+ virtual void LoseFocus() override;
+
+ static void NotifyUndoActionHdl( std::unique_ptr<SdrUndoAction> );
+ virtual void DoInit() override;
+ virtual void DoScroll( Scrollable* pCurScrollBar ) override;
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+ void InitSettings();
+
+public:
+ DialogWindow (DialogWindowLayout* pParent, ScriptDocument const& rDocument, const OUString& aLibName, const OUString& aName, css::uno::Reference<css::container::XNameContainer> const& xDialogModel);
+
+ virtual void ExecuteCommand( SfxRequest& rReq ) override;
+ virtual void GetState( SfxItemSet& ) override;
+ DlgEditor& GetEditor() const { return *m_pEditor; }
+ css::uno::Reference< css::container::XNameContainer > const & GetDialog() const;
+ DlgEdModel& GetModel() const;
+ DlgEdPage& GetPage() const;
+ DlgEdView& GetView() const;
+ bool RenameDialog( const OUString& rNewName );
+ void DisableBrowser();
+ void UpdateBrowser();
+ void SaveDialog();
+ void ImportDialog();
+
+ virtual OUString GetTitle() override;
+ virtual EntryDescriptor CreateEntryDescriptor() override;
+ virtual void SetReadOnly (bool bReadOnly) override;
+ virtual bool IsReadOnly() override;
+
+ virtual void StoreData() override;
+ virtual bool IsModified() override;
+ bool IsPasteAllowed();
+
+ virtual SfxUndoManager* GetUndoManager() override;
+ // return number of pages to be printed
+ virtual sal_Int32 countPages( Printer* pPrinter ) override;
+ // print page
+ virtual void printPage (sal_Int32 nPage, Printer*) override;
+
+ virtual void Activating () override;
+ virtual void Deactivating () override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override;
+
+ virtual OUString GetHid () const override;
+ virtual ItemType GetType () const override;
+};
+
+
+// DialogWindowLayout
+
+class DialogWindowLayout : public Layout
+{
+public:
+ DialogWindowLayout (vcl::Window* pParent, ObjectCatalog&);
+ virtual ~DialogWindowLayout() override;
+ virtual void dispose() override;
+public:
+ void ShowPropertyBrowser ();
+ void UpdatePropertyBrowser ();
+ void DisablePropertyBrowser ();
+public:
+ // Layout:
+ virtual void Activating (BaseWindow&) override;
+ virtual void Deactivating () override;
+ virtual void ExecuteGlobal (SfxRequest&) override;
+ virtual void GetState (SfxItemSet&, unsigned nWhich) override;
+ virtual void UpdateDebug (bool) override {};
+protected:
+ // Layout:
+ virtual void OnFirstSize (tools::Long nWidth, tools::Long nHeight) override;
+
+private:
+ // dockable windows:
+ // object catalog (owned by Shell)
+ ObjectCatalog& rObjectCatalog;
+ // property browser (created by this, deleted by toolkit)
+ VclPtr<PropBrw> pPropertyBrowser;
+
+private:
+ void AddPropertyBrowser ();
+private:
+ friend class DialogWindow;
+};
+
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/basidectrlr.hxx b/basctl/source/inc/basidectrlr.hxx
new file mode 100644
index 0000000000..a32e1ffd94
--- /dev/null
+++ b/basctl/source/inc/basidectrlr.hxx
@@ -0,0 +1,68 @@
+/* -*- 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 <comphelper/broadcasthelper.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <sfx2/sfxbasecontroller.hxx>
+
+namespace basctl
+{
+
+class Shell;
+
+class Controller :
+ public comphelper::OMutexAndBroadcastHelper,
+ public comphelper::OPropertyContainer,
+ public comphelper::OPropertyArrayUsageHelper<Controller>,
+ public SfxBaseController
+{
+private:
+ // properties
+ sal_Int32 m_nIconId;
+
+public:
+ Controller (Shell* pViewShell);
+ virtual ~Controller() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider ( ::SfxBaseController )
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/basidesh.hxx b/basctl/source/inc/basidesh.hxx
new file mode 100644
index 0000000000..f907abe6f2
--- /dev/null
+++ b/basctl/source/inc/basidesh.hxx
@@ -0,0 +1,231 @@
+/* -*- 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 "doceventnotifier.hxx"
+#include "sbxitem.hxx"
+#include "ObjectCatalog.hxx"
+
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <sfx2/viewsh.hxx>
+#include <svx/ifaceids.hxx>
+#include <svl/srchitem.hxx>
+#include <svtools/scrolladaptor.hxx>
+#include <map>
+#include <memory>
+#include <string_view>
+
+class SfxViewFactory;
+class SdrView;
+class TabBar;
+class SbxObject;
+class SbModule;
+class StarBASIC;
+
+namespace basctl
+{
+
+// Used to control zoom level
+constexpr sal_uInt16 MIN_ZOOM_LEVEL = 50;
+constexpr sal_uInt16 DEFAULT_ZOOM_LEVEL = 100;
+constexpr sal_uInt16 MAX_ZOOM_LEVEL = 400;
+
+class Layout;
+class ModulWindow;
+class ModulWindowLayout;
+class DialogWindow;
+class DialogWindowLayout;
+class TabBar;
+class BaseWindow;
+class LocalizationMgr;
+
+class Shell :
+ public SfxViewShell,
+ public DocumentEventListener
+{
+public:
+ typedef std::map<sal_uInt16, VclPtr<BaseWindow> > WindowTable;
+
+private:
+ friend class JavaDebuggingListenerImpl;
+ friend class LocalizationMgr;
+ friend bool implImportDialog(weld::Window* pWin, const ScriptDocument& rDocument, const OUString& rLibName); // defined in baside3.cxx
+
+ WindowTable aWindowTable;
+ sal_uInt16 nCurKey;
+ VclPtr<BaseWindow> pCurWin;
+ ScriptDocument m_aCurDocument;
+ OUString m_aCurLibName;
+ std::shared_ptr<LocalizationMgr> m_pCurLocalizationMgr;
+
+ // Current value of the zoom slider
+ sal_uInt16 m_nCurrentZoomSliderValue;
+ VclPtr<ScrollAdaptor> aHScrollBar;
+ VclPtr<ScrollAdaptor> aVScrollBar;
+ VclPtr<TabBar> pTabBar; // basctl::TabBar
+ bool bCreatingWindow;
+
+ // layout windows
+ VclPtr<ModulWindowLayout> pModulLayout;
+ VclPtr<DialogWindowLayout> pDialogLayout;
+ VclPtr<Layout> pLayout; // the active layout window
+ // common object catalog window
+ VclPtr<ObjectCatalog> aObjectCatalog;
+
+ bool m_bAppBasicModified;
+ bool mbJustOpened = false;
+
+ DocumentEventNotifier m_aNotifier;
+
+ friend class ContainerListenerImpl;
+ css::uno::Reference< css::container::XContainerListener > m_xLibListener;
+ std::unique_ptr<SvxSearchItem> mpSearchItem;
+
+ void Init();
+ void InitTabBar();
+ void InitScrollBars();
+ void InitZoomLevel();
+ void CheckWindows();
+ void RemoveWindows( const ScriptDocument& rDocument, std::u16string_view rLibName );
+ void UpdateWindows();
+ static void InvalidateBasicIDESlots();
+ void StoreAllWindowData( bool bPersistent = true );
+ void SetMDITitle();
+ void SetCurLib( const ScriptDocument& rDocument, const OUString& aLibName, bool bUpdateWindows = true , bool bCheck = true );
+ void SetCurLibForLocalization( const ScriptDocument& rDocument, const OUString& aLibName );
+
+ DECL_LINK( TabBarHdl, ::TabBar*, void );
+
+ static unsigned nShellCount;
+
+private:
+ void AdjustPosSizePixel( const Point &rPos, const Size &rSize );
+ virtual void OuterResizePixel( const Point &rPos, const Size &rSize ) override;
+ sal_uInt16 InsertWindowInTable (BaseWindow* pNewWin);
+ virtual bool PrepareClose( bool bUI = true ) override;
+
+ void SetCurWindow (BaseWindow* pNewWin, bool bUpdateTabBar = false, bool bRememberAsCurrent = true);
+ void ManageToolbars();
+
+ VclPtr<ModulWindow> CreateBasWin( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName );
+ VclPtr<DialogWindow> CreateDlgWin( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rDlgName );
+
+ VclPtr<ModulWindow> ShowActiveModuleWindow( StarBASIC const * pBasic );
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ virtual void Activate(bool bMDI) override;
+ virtual void Deactivate(bool bMDI) override;
+
+ virtual void Move() override;
+ virtual void ShowCursor( bool bOn = true ) override;
+
+ // 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;
+
+public:
+ SFX_DECL_INTERFACE( SVX_INTERFACE_BASIDE_VIEWSH )
+ SFX_DECL_VIEWFACTORY(Shell);
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ Shell(SfxViewFrame& rFrame, SfxViewShell *pOldSh);
+ virtual ~Shell() override;
+
+ BaseWindow* GetCurWindow() const { return pCurWin; }
+ OUString const& GetCurLibName() const { return m_aCurLibName; }
+ const std::shared_ptr<LocalizationMgr>& GetCurLocalizationMgr() const { return m_pCurLocalizationMgr; }
+
+ TabBar& GetTabBar() { return *pTabBar; }
+ WindowTable& GetWindowTable() { return aWindowTable; }
+ sal_uInt16 GetWindowId (BaseWindow const* pWin) const;
+
+ SdrView* GetCurDlgView() const;
+
+ SfxUndoManager* GetUndoManager() override;
+
+ void SetGlobalEditorZoomLevel(sal_uInt16 nNewZoomLevel);
+ sal_uInt16 GetCurrentZoomSliderValue() { return m_nCurrentZoomSliderValue; }
+ static sal_uInt16 GetMinZoom() { return MIN_ZOOM_LEVEL; }
+ static sal_uInt16 GetMaxZoom() { return MAX_ZOOM_LEVEL; }
+
+ virtual css::uno::Reference< css::view::XRenderable > GetRenderable() override;
+
+ // virtual sal_uInt16 Print( SfxProgress &rProgress, sal_Bool bIsAPI, PrintDialog *pPrintDialog = 0 );
+ virtual SfxPrinter* GetPrinter( bool bCreate = false ) override;
+ virtual sal_uInt16 SetPrinter( SfxPrinter *pNewPrinter, SfxPrinterChangeFlags nDiffFlags = SFX_PRINTER_ALL ) override;
+ virtual OUString GetSelectionText( bool bCompleteWords = false, bool bOnlyASample = false ) override;
+ virtual bool HasSelection( bool bText = true ) const override;
+
+ void GetState( SfxItemSet& );
+ void ExecuteGlobal( SfxRequest& rReq );
+ void ExecuteSearch( SfxRequest& rReq );
+ void ExecuteCurrent( SfxRequest& rReq );
+ void ExecuteBasic( SfxRequest& rReq );
+ void ExecuteDialog( SfxRequest& rReq );
+
+ virtual bool HasUIFeature(SfxShellFeature nFeature) const override;
+
+ bool CallBasicErrorHdl( StarBASIC const * pBasic );
+ BasicDebugFlags CallBasicBreakHdl( StarBASIC const * pBasic );
+
+ VclPtr<BaseWindow> FindWindow( const ScriptDocument& rDocument, std::u16string_view rLibName, std::u16string_view rName, ItemType nType, bool bFindSuspended = false );
+ VclPtr<DialogWindow> FindDlgWin( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rName, bool bCreateIfNotExist = false, bool bFindSuspended = false );
+ VclPtr<ModulWindow> FindBasWin( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName, bool bCreateIfNotExist = false, bool bFindSuspended = false );
+ VclPtr<BaseWindow> FindApplicationWindow();
+ bool NextPage( bool bPrev );
+
+ bool IsAppBasicModified () const { return m_bAppBasicModified; }
+ void SetAppBasicModified (bool bModified) { m_bAppBasicModified = bModified; }
+
+ // For Dialog Drag&Drop in Dialog Organizer:
+ // (defined in moduldlg.cxx)
+ static void CopyDialogResources(
+ css::uno::Reference< css::io::XInputStreamProvider >& io_xISP,
+ const ScriptDocument& rSourceDoc, const OUString& rSourceLibName, const ScriptDocument& rDestDoc,
+ const OUString& rDestLibName, std::u16string_view rDlgName );
+
+ static void InvalidateControlSlots();
+
+ virtual css::uno::Reference< css::frame::XModel >
+ GetCurrentDocument() const override;
+
+ void UpdateObjectCatalog () { aObjectCatalog->UpdateEntries(); }
+
+ void RemoveWindow (BaseWindow* pWindow, bool bDestroy, bool bAllowChangeCurWindow = true);
+};
+
+} // namespace basctl
+
+// This typedef helps baside.sdi,
+// because I don't know how to use nested names in it.
+typedef basctl::Shell basctl_Shell;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/basobj.hxx b/basctl/source/inc/basobj.hxx
new file mode 100644
index 0000000000..70c603d454
--- /dev/null
+++ b/basctl/source/inc/basobj.hxx
@@ -0,0 +1,105 @@
+/* -*- 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 "scriptdocument.hxx"
+#include <tools/long.hxx>
+
+class SbMethod;
+class SbModule;
+class SbxVariable;
+class StarBASIC;
+class SfxUInt16Item;
+class SfxBindings;
+class SfxDispatcher;
+namespace weld { class Widget; class Window; }
+
+namespace basctl
+{
+ void Organize(weld::Window* pParent, const css::uno::Reference<css::frame::XFrame>& xDocFrame, sal_Int16 tabId);
+
+ // help methods for the general use:
+ SbMethod* CreateMacro( SbModule* pModule, const OUString& rMacroName );
+ void RunMethod( SbMethod const * pMethod );
+
+ StarBASIC* FindBasic( const SbxVariable* pVar );
+ void StopBasic();
+ tools::Long HandleBasicError( StarBASIC const * pBasic );
+ void BasicStopped( bool* pbAppWindowDisabled = nullptr, bool* pbDispatcherLocked = nullptr, sal_uInt16* pnWaitCount = nullptr,
+ SfxUInt16Item** ppSWActionCount = nullptr, SfxUInt16Item** ppSWLockViewCount = nullptr );
+
+ bool IsValidSbxName( std::u16string_view rName );
+
+ BasicManager* FindBasicManager( StarBASIC const * pLib );
+
+ SfxBindings* GetBindingsPtr();
+
+ SfxDispatcher* GetDispatcher ();
+
+ void InvalidateDebuggerSlots();
+
+ // libraries
+
+ css::uno::Sequence< OUString > GetMergedLibraryNames(
+ const css::uno::Reference< css::script::XLibraryContainer >& xModLibContainer,
+ const css::uno::Reference< css::script::XLibraryContainer >& xDlgLibContainer );
+
+ /** renames a module
+
+ Will show an error message when renaming fails because the new name is already used.
+ */
+ bool RenameModule(
+ weld::Widget* pErrorParent, const ScriptDocument& rDocument,
+ const OUString& rLibName, const OUString& rOldName, const OUString& rNewName );
+
+ // new methods for macros
+
+ OUString ChooseMacro(weld::Window* pParent,
+ const css::uno::Reference< css::frame::XModel >& rxLimitToDocument, const css::uno::Reference< css::frame::XFrame >& xDocFrame,
+ bool bChooseOnly );
+ inline OUString ChooseMacro(weld::Window* pParent, const css::uno::Reference<css::frame::XModel>& rLimitToDocument)
+ { return ChooseMacro(pParent, rLimitToDocument, css::uno::Reference< css::frame::XFrame >(), false/*bChooseOnly*/); }
+
+ /// @throws css::container::NoSuchElementException
+ /// @throws css::uno::RuntimeException
+ css::uno::Sequence< OUString > GetMethodNames(
+ const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName );
+
+ bool HasMethod(
+ const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName, const OUString& rMethName );
+
+ // new methods for dialogs
+
+ /** renames a dialog
+
+ Will show an error message when renaming fails because the new name is already used.
+
+ @throws css::container::ElementExistException
+ @throws css::container::NoSuchElementException
+ @throws css::uno::RuntimeException
+ */
+ bool RenameDialog(weld::Widget* pErrorParent, const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rOldName, const OUString& rNewName);
+
+ bool RemoveDialog( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rDlgName );
+
+ void MarkDocumentModified( const ScriptDocument& rDocument );
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/bastype2.hxx b/basctl/source/inc/bastype2.hxx
new file mode 100644
index 0000000000..0161797f16
--- /dev/null
+++ b/basctl/source/inc/bastype2.hxx
@@ -0,0 +1,278 @@
+/* -*- 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 <memory>
+
+#include "doceventnotifier.hxx"
+
+#include <vcl/weld.hxx>
+#include "sbxitem.hxx"
+#include <o3tl/typed_flags_set.hxx>
+
+class SbModule;
+class SbxVariable;
+
+enum class BrowseMode
+{
+ Modules = 0x01,
+ Subs = 0x02,
+ Dialogs = 0x04,
+ All = Modules | Subs | Dialogs,
+};
+namespace o3tl {
+ template<> struct typed_flags<BrowseMode> : is_typed_flags<BrowseMode, 0x7> {};
+}
+
+namespace basctl
+{
+using namespace ::com::sun::star::uno;
+
+enum EntryType
+{
+ OBJ_TYPE_UNKNOWN,
+ OBJ_TYPE_DOCUMENT,
+ OBJ_TYPE_LIBRARY,
+ OBJ_TYPE_MODULE,
+ OBJ_TYPE_DIALOG,
+ OBJ_TYPE_METHOD,
+ OBJ_TYPE_DOCUMENT_OBJECTS,
+ OBJ_TYPE_USERFORMS,
+ OBJ_TYPE_NORMAL_MODULES,
+ OBJ_TYPE_CLASS_MODULES
+};
+
+class Entry
+{
+private:
+ EntryType m_eType;
+
+public:
+ explicit Entry(EntryType eType)
+ : m_eType(eType)
+ {
+ }
+
+ virtual ~Entry();
+
+ Entry(Entry const &) = default;
+ Entry(Entry &&) = default;
+ Entry & operator =(Entry const &) = default;
+ Entry & operator =(Entry &&) = default;
+
+ EntryType GetType () const { return m_eType; }
+};
+
+class DocumentEntry : public Entry
+{
+private:
+ ScriptDocument m_aDocument;
+ LibraryLocation m_eLocation;
+
+public:
+ DocumentEntry (
+ ScriptDocument aDocument,
+ LibraryLocation eLocation,
+ EntryType eType = OBJ_TYPE_DOCUMENT
+ );
+ virtual ~DocumentEntry () override;
+
+ ScriptDocument const& GetDocument() const { return m_aDocument; }
+ LibraryLocation GetLocation() const { return m_eLocation; }
+};
+
+class LibEntry : public DocumentEntry
+{
+private:
+ OUString m_aLibName;
+
+public:
+ LibEntry (
+ ScriptDocument const& rDocument,
+ LibraryLocation eLocation,
+ OUString aLibName
+ );
+ virtual ~LibEntry () override;
+
+ OUString const& GetLibName () const { return m_aLibName; }
+};
+
+class EntryDescriptor
+{
+ ScriptDocument m_aDocument;
+ LibraryLocation m_eLocation;
+ OUString m_aLibName;
+ OUString m_aLibSubName; // for vba entry: Document Objects, Class Modules, Forms and Normal Modules
+ OUString m_aName;
+ OUString m_aMethodName;
+ EntryType m_eType;
+
+public:
+ EntryDescriptor ();
+ EntryDescriptor (
+ ScriptDocument aDocument,
+ LibraryLocation eLocation,
+ OUString aLibName,
+ OUString aLibSubName,
+ OUString aName,
+ EntryType eType
+ );
+ EntryDescriptor (
+ ScriptDocument aDocument,
+ LibraryLocation eLocation,
+ OUString aLibName,
+ OUString aLibSubName,
+ OUString aName,
+ OUString aMethodName,
+ EntryType eType
+ );
+
+ ScriptDocument const& GetDocument() const { return m_aDocument; }
+ LibraryLocation GetLocation() const { return m_eLocation; }
+
+ const OUString& GetLibName() const { return m_aLibName; }
+ const OUString& GetLibSubName() const { return m_aLibSubName; }
+ const OUString& GetName() const { return m_aName; }
+ const OUString& GetMethodName() const { return m_aMethodName; }
+ void SetMethodName( const OUString& aMethodName ) { m_aMethodName = aMethodName; }
+
+ EntryType GetType() const { return m_eType; }
+ void SetType( EntryType eType ) { m_eType = eType; }
+};
+
+
+/*
+ Classification of types and pointers in the Entries:
+
+ OBJ_TYPE_DOCUMENT DocumentEntry
+ OBJ_TYPE_LIBRARY Entry
+ OBJ_TYPE_MODULE Entry
+ OBJ_TYPE_DIALOG Entry
+ OBJ_TYPE_METHOD Entry
+
+*/
+
+class SbTreeListBox : public DocumentEventListener
+{
+private:
+ std::unique_ptr<weld::TreeView> m_xControl;
+ std::unique_ptr<weld::TreeIter> m_xScratchIter;
+ weld::Window* m_pTopLevel;
+ bool m_bFreezeOnFirstAddRemove;
+ BrowseMode nMode;
+ DocumentEventNotifier m_aNotifier;
+ void SetEntryBitmaps(const weld::TreeIter& rIter, const OUString& rImage);
+
+protected:
+ DECL_LINK(RequestingChildrenHdl, const weld::TreeIter&, bool);
+ DECL_LINK(OpenCurrentHdl, weld::TreeView&, bool);
+ void ImpCreateLibEntries(const weld::TreeIter& rShellRootEntry, const ScriptDocument& rDocument, LibraryLocation eLocation);
+ void ImpCreateLibSubEntries(const weld::TreeIter& rLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName);
+ void ImpCreateLibSubEntriesInVBAMode(const weld::TreeIter& rLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName );
+ void ImpCreateLibSubSubEntriesInVBAMode(const weld::TreeIter& rLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName);
+ bool ImpFindEntry(weld::TreeIter& rIter, std::u16string_view rText);
+
+ // 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;
+
+public:
+ SbTreeListBox(std::unique_ptr<weld::TreeView> xControl, weld::Window* pTopLevel);
+ virtual ~SbTreeListBox() override;
+
+ void ScanEntry( const ScriptDocument& rDocument, LibraryLocation eLocation );
+ void ScanAllEntries();
+ void UpdateEntries();
+
+ bool IsEntryProtected(const weld::TreeIter* pEntry);
+
+ void SetMode( BrowseMode nM ) { nMode = nM; }
+ BrowseMode GetMode() const { return nMode; }
+
+ SbModule* FindModule(const weld::TreeIter* pEntry);
+ SbxVariable* FindVariable(const weld::TreeIter* pEntry);
+ bool FindRootEntry(const ScriptDocument& rDocument, LibraryLocation eLocation, weld::TreeIter& rIter);
+ bool FindEntry(std::u16string_view rText, EntryType eType, weld::TreeIter& rIter);
+ EntryDescriptor GetEntryDescriptor(const weld::TreeIter* pEntry);
+
+ static ItemType ConvertType (EntryType eType);
+ bool IsValidEntry(const weld::TreeIter& rEntry);
+ void AddEntry(const OUString& rText, const OUString& rImage,
+ const weld::TreeIter* pParent, bool bChildrenOnDemand,
+ std::unique_ptr<Entry>&& rUserData,
+ weld::TreeIter* pRet = nullptr);
+
+ void connect_changed(const Link<weld::TreeView&, void>& rLink) { m_xControl->connect_changed(rLink); }
+ std::unique_ptr<weld::TreeIter> make_iterator(const weld::TreeIter* pIter = nullptr) const { return m_xControl->make_iterator(pIter); }
+ void copy_iterator(const weld::TreeIter& rSource, weld::TreeIter& rDest) const { m_xControl->copy_iterator(rSource, rDest); }
+ bool get_selected(weld::TreeIter* pIter) const { return m_xControl->get_selected(pIter); }
+ void select(const weld::TreeIter& rIter) { m_xControl->select(rIter); }
+ void unselect(const weld::TreeIter& rIter) { m_xControl->unselect(rIter); }
+ void remove(const weld::TreeIter& rIter) { m_xControl->remove(rIter); }
+ bool get_cursor(weld::TreeIter* pIter) const { return m_xControl->get_cursor(pIter); }
+ void set_cursor(const weld::TreeIter& rIter) { m_xControl->set_cursor(rIter); }
+ OUString get_text(const weld::TreeIter& rIter) const { return m_xControl->get_text(rIter); }
+ void set_text(const weld::TreeIter& rIter, const OUString& rText) { m_xControl->set_text(rIter, rText); }
+ OUString get_id(const weld::TreeIter& rIter) const { return m_xControl->get_id(rIter); }
+ bool get_iter_first(weld::TreeIter& rIter) const { return m_xControl->get_iter_first(rIter); }
+ bool iter_next_sibling(weld::TreeIter& rIter) const { return m_xControl->iter_next_sibling(rIter); }
+ bool iter_children(weld::TreeIter& rIter) const { return m_xControl->iter_children(rIter); }
+ bool iter_parent(weld::TreeIter& rIter) const { return m_xControl->iter_parent(rIter); }
+ int get_iter_depth(const weld::TreeIter& rIter) const { return m_xControl->get_iter_depth(rIter); }
+ bool get_row_expanded(const weld::TreeIter& rIter) const { return m_xControl->get_row_expanded(rIter); }
+ void expand_row(const weld::TreeIter& rIter) { m_xControl->expand_row(rIter); }
+ void set_size_request(int nWidth, int nHeight) { m_xControl->set_size_request(nWidth, nHeight); }
+ float get_approximate_digit_width() const { return m_xControl->get_approximate_digit_width(); }
+ int get_height_rows(int nRows) const { return m_xControl->get_height_rows(nRows); }
+ int get_iter_index_in_parent(const weld::TreeIter& rIter) const { return m_xControl->get_iter_index_in_parent(rIter); }
+ void connect_editing(const Link<const weld::TreeIter&, bool>& rStartLink,
+ const Link<const std::pair<const weld::TreeIter&, OUString>&, bool>& rEndLink)
+ {
+ m_xControl->connect_editing(rStartLink, rEndLink);
+ }
+
+ void make_sorted() { m_xControl->make_sorted(); };
+
+ void RemoveEntry(const weld::TreeIter& rIter);
+ void RemoveEntry(const ScriptDocument&);
+
+ OUString GetRootEntryName(const ScriptDocument& rDocument, LibraryLocation eLocation) const;
+ static OUString GetRootEntryBitmaps(const ScriptDocument& rDocument);
+
+ void SetCurrentEntry (EntryDescriptor const &);
+
+ weld::TreeView& get_widget() { return *m_xControl; }
+
+private:
+ LibraryType GetLibraryType() const;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/bastypes.hxx b/basctl/source/inc/bastypes.hxx
new file mode 100644
index 0000000000..513fbce3a4
--- /dev/null
+++ b/basctl/source/inc/bastypes.hxx
@@ -0,0 +1,316 @@
+/* -*- 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 "scriptdocument.hxx"
+
+#include "sbxitem.hxx"
+#include <svtools/scrolladaptor.hxx>
+#include <svtools/tabbar.hxx>
+#include <basic/sbdef.hxx>
+#include <vcl/dockwin.hxx>
+#include <vcl/weld.hxx>
+
+#include <string_view>
+#include <unordered_map>
+
+class SbModule;
+class SfxItemSet;
+class SfxRequest;
+class SvxSearchItem;
+class Printer;
+enum class SearchOptionFlags;
+class SfxUndoManager;
+
+namespace weld
+{
+ class Widget;
+}
+
+namespace basctl
+{
+
+class Layout;
+class ModulWindow;
+class DialogWindow;
+
+constexpr auto LINE_SEP_CR = 0x0D;
+constexpr auto LINE_SEP = 0x0A;
+
+// Implementation: baside2b.cxx
+sal_Int32 searchEOL( std::u16string_view rStr, sal_Int32 fromIndex );
+
+// Meaning of bToBeKilled:
+// While being in a reschedule-loop, I may not destroy the window.
+// It must first break from the reschedule-loop to self-destroy then.
+// Does unfortunately not work that way: Destroying Window with living Child!
+
+struct BasicStatus
+{
+ bool bIsRunning : 1;
+ bool bError : 1;
+ bool bIsInReschedule : 1;
+ BasicDebugFlags nBasicFlags;
+
+ BasicStatus():
+ bIsRunning(false),
+ bError(false),
+ bIsInReschedule(false),
+ nBasicFlags(BasicDebugFlags::NONE) { }
+};
+
+
+// basctl::DockingWindow -- special docking window for the Basic IDE
+// Not to be confused with ::DockingWindow from vcl.
+
+class DockingWindow : public ResizableDockingWindow
+{
+public:
+ DockingWindow(vcl::Window* pParent, const OUString& rUIXMLDescription, const OUString& rID);
+ DockingWindow(Layout* pParent);
+ virtual ~DockingWindow() override;
+ virtual void dispose() override;
+ void ResizeIfDocking (Point const&, Size const&);
+ void ResizeIfDocking (Size const&);
+ Size GetDockingSize () const { return aDockingRect.GetSize(); }
+ void SetLayoutWindow (Layout*);
+public:
+ void Show (bool = true);
+ void Hide ();
+
+protected:
+ virtual bool Docking( const Point& rPos, tools::Rectangle& rRect ) override;
+ virtual void EndDocking( const tools::Rectangle& rRect, bool bFloatMode ) override;
+ virtual void ToggleFloatingMode() override;
+ virtual bool PrepareToggleFloatingMode() override;
+ virtual void StartDocking() override;
+
+protected:
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+
+private:
+ // the position and the size of the floating window
+ tools::Rectangle aFloatingRect;
+ // the position and the size of the docking window
+ tools::Rectangle aDockingRect;
+ // the parent layout window (only when docking)
+ VclPtr<Layout> pLayout;
+ // > 0: shown, <= 0: hidden, ++ by Show() and -- by Hide()
+ int nShowCount;
+
+ static WinBits const StyleBits;
+
+private:
+ void DockThis ();
+};
+
+
+// basctl::TabBar
+// Not to be confused with ::TabBar from svtools.
+
+class TabBar : public ::TabBar
+{
+protected:
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void Command( const CommandEvent& rCEvt ) override;
+
+ virtual TabBarAllowRenamingReturnCode AllowRenaming() override;
+ virtual void EndRenaming() override;
+
+public:
+ TabBar (vcl::Window* pParent);
+
+ void Sort();
+};
+
+enum BasicWindowStatus
+{
+ BASWIN_RUNNINGBASIC = 0x01,
+ BASWIN_TOBEKILLED = 0x02,
+ BASWIN_SUSPENDED = 0x04,
+ BASWIN_INRESCHEDULE = 0x08
+};
+
+class EntryDescriptor;
+
+
+// BaseWindow -- the base of both ModulWindow and DialogWindow.
+
+class BaseWindow : public vcl::Window
+{
+private:
+ VclPtr<ScrollAdaptor> pShellHScrollBar;
+ VclPtr<ScrollAdaptor> pShellVScrollBar;
+
+ DECL_LINK( VertScrollHdl, weld::Scrollbar&, void );
+ DECL_LINK( HorzScrollHdl, weld::Scrollbar&, void );
+ int nStatus;
+
+ ScriptDocument m_aDocument;
+ OUString m_aLibName;
+ OUString m_aName;
+
+ friend class ModulWindow;
+ friend class DialogWindow;
+
+protected:
+ virtual void DoScroll(Scrollable* pCurScrollBar);
+
+public:
+ BaseWindow( vcl::Window* pParent, ScriptDocument aDocument, OUString aLibName, OUString aName );
+ virtual ~BaseWindow() override;
+ virtual void dispose() override;
+
+ void Init();
+ virtual void DoInit();
+ virtual void Activating () = 0;
+ virtual void Deactivating () = 0;
+ void GrabScrollBars(ScrollAdaptor* pHScroll, ScrollAdaptor* pVScroll);
+
+ ScrollAdaptor* GetHScrollBar() const { return pShellHScrollBar.get(); }
+ ScrollAdaptor* GetVScrollBar() const { return pShellVScrollBar.get(); }
+ void ShowShellScrollBars(bool bVisible = true);
+
+ virtual void ExecuteCommand (SfxRequest&);
+ virtual void ExecuteGlobal (SfxRequest&);
+ virtual void GetState (SfxItemSet&) = 0;
+ virtual bool EventNotify( NotifyEvent& rNEvt ) override;
+
+ virtual void StoreData();
+ virtual void UpdateData();
+
+ // return number of pages to be printed
+ virtual sal_Int32 countPages( Printer* pPrinter ) = 0;
+ // print page
+ virtual void printPage( sal_Int32 nPage, Printer* pPrinter ) = 0;
+
+ virtual OUString GetTitle();
+ OUString CreateQualifiedName();
+ virtual EntryDescriptor CreateEntryDescriptor() = 0;
+
+ virtual bool IsModified();
+
+ virtual bool AllowUndo();
+
+ virtual void SetReadOnly (bool bReadOnly);
+ virtual bool IsReadOnly();
+ void ShowReadOnlyInfoBar();
+
+ int GetStatus() const { return nStatus; }
+ void SetStatus(int n) { nStatus = n; }
+ void AddStatus(int n) { nStatus |= n; }
+ void ClearStatus(int n) { nStatus &= ~n; }
+
+ virtual SfxUndoManager* GetUndoManager ();
+
+ virtual SearchOptionFlags GetSearchOptions();
+ virtual sal_uInt16 StartSearchAndReplace (SvxSearchItem const&, bool bFromStart = false);
+
+ virtual void BasicStarted();
+ virtual void BasicStopped();
+
+ bool IsSuspended() const { return nStatus & BASWIN_SUSPENDED; }
+
+ const ScriptDocument&
+ GetDocument() const { return m_aDocument; }
+ bool IsDocument( const ScriptDocument& rDocument ) const { return rDocument == m_aDocument; }
+ const OUString& GetLibName() const { return m_aLibName; }
+
+ const OUString& GetName() const { return m_aName; }
+ void SetName( const OUString& aName ) { m_aName = aName; }
+
+ virtual void OnNewDocument ();
+ virtual OUString GetHid () const = 0;
+ virtual ItemType GetType () const = 0;
+ void InsertLibInfo () const;
+ bool Is (ScriptDocument const&, std::u16string_view, std::u16string_view, ItemType, bool bFindSuspended);
+ virtual bool HasActiveEditor () const;
+};
+
+class LibInfo
+{
+public:
+ class Item;
+public:
+ LibInfo ();
+ ~LibInfo ();
+public:
+ void InsertInfo (ScriptDocument const&, OUString const& rLibName, OUString const& rCurrentName, ItemType eCurrentType);
+ void RemoveInfoFor (ScriptDocument const&);
+ Item const* GetInfo (ScriptDocument const&, OUString const& rLibName);
+
+private:
+ class Key
+ {
+ private:
+ ScriptDocument m_aDocument;
+ OUString m_aLibName;
+
+ public:
+ Key (ScriptDocument , OUString aLibName);
+ public:
+ bool operator == (Key const&) const;
+ struct Hash
+ {
+ size_t operator () (Key const&) const;
+ };
+ public:
+ const ScriptDocument& GetDocument() const { return m_aDocument; }
+ };
+public:
+ class Item
+ {
+ private:
+ OUString m_aCurrentName;
+ ItemType m_eCurrentType;
+
+ public:
+ Item (OUString aCurrentName, ItemType eCurrentType);
+ const OUString& GetCurrentName() const { return m_aCurrentName; }
+ ItemType GetCurrentType() const { return m_eCurrentType; }
+ };
+private:
+ typedef std::unordered_map<Key, Item, Key::Hash> Map;
+ Map m_aMap;
+};
+
+void CutLines( OUString& rStr, sal_Int32 nStartLine, sal_Int32 nLines );
+OUString CreateMgrAndLibStr( std::u16string_view rMgrName, std::u16string_view rLibName );
+sal_uInt32 CalcLineCount( SvStream& rStream );
+
+bool QueryReplaceMacro( std::u16string_view rName, weld::Widget* pParent );
+bool QueryDelMacro( std::u16string_view rName, weld::Widget* pParent );
+bool QueryDelDialog( std::u16string_view rName, weld::Widget* pParent );
+bool QueryDelModule( std::u16string_view rName, weld::Widget* pParent );
+bool QueryDelLib( std::u16string_view rName, bool bRef, weld::Widget* pParent );
+bool QueryPassword(weld::Widget* pDialogParent, const css::uno::Reference< css::script::XLibraryContainer >& xLibContainer, const OUString& rLibName, OUString& rPassword, bool bRepeat = false, bool bNewTitle = false);
+
+class ModuleInfoHelper
+{
+ ModuleInfoHelper (const ModuleInfoHelper&) = delete;
+ ModuleInfoHelper& operator = (const ModuleInfoHelper&) = delete;
+public:
+ static void getObjectName( const css::uno::Reference< css::container::XNameContainer >& rLib, const OUString& rModName, OUString& rObjName );
+ static sal_Int32 getModuleType( const css::uno::Reference< css::container::XNameContainer >& rLib, const OUString& rModName );
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/dlged.hxx b/basctl/source/inc/dlged.hxx
new file mode 100644
index 0000000000..c50faf51b3
--- /dev/null
+++ b/basctl/source/inc/dlged.hxx
@@ -0,0 +1,210 @@
+/* -*- 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/awt/XControlContainer.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <o3tl/deleter.hxx>
+#include <svl/SfxBroadcaster.hxx>
+#include <svl/hint.hxx>
+#include <svx/svdobjkind.hxx>
+#include <tools/gen.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/idle.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/window.hxx>
+
+#include <memory>
+
+class ScrollAdaptor;
+class Printer;
+class KeyEvent;
+class MouseEvent;
+class Timer;
+namespace vcl { class Window; }
+
+namespace basctl
+{
+
+class DialogWindowLayout;
+
+constexpr auto DLGED_PAGE_WIDTH_MIN = 1280;
+constexpr auto DLGED_PAGE_HEIGHT_MIN = 1024;
+
+// DlgEdHint
+
+
+class DlgEdObj;
+
+class DlgEdHint: public SfxHint
+{
+public:
+ enum Kind {
+ UNKNOWN,
+ WINDOWSCROLLED,
+ LAYERCHANGED,
+ OBJORDERCHANGED,
+ SELECTIONCHANGED,
+ };
+
+private:
+ Kind eKind;
+ DlgEdObj* pDlgEdObj;
+
+public:
+ DlgEdHint (Kind);
+ DlgEdHint (Kind, DlgEdObj* pObj);
+ virtual ~DlgEdHint() override;
+
+ Kind GetKind() const { return eKind; }
+ DlgEdObj* GetObject() const { return pDlgEdObj; }
+};
+
+
+// DlgEditor
+
+
+class DlgEdModel;
+class DlgEdPage;
+class DlgEdView;
+class DlgEdForm;
+class DlgEdFactory;
+class DlgEdFunc;
+
+class DlgEditor: public SfxBroadcaster
+{
+public:
+ enum Mode {
+ INSERT,
+ SELECT,
+ TEST,
+ READONLY,
+ };
+
+private:
+ DECL_LINK(MarkTimeout, Timer *, void);
+
+ static void Print( Printer* pPrinter, const OUString& rTitle );
+
+private:
+ VclPtr<ScrollAdaptor> pHScroll;
+ VclPtr<ScrollAdaptor> pVScroll;
+ std::unique_ptr<DlgEdModel> pDlgEdModel; // never nullptr
+ DlgEdPage* pDlgEdPage; // never nullptr
+ std::unique_ptr<DlgEdView> pDlgEdView; // never nullptr
+ rtl::Reference<DlgEdForm> pDlgEdForm; // never nullptr
+ css::uno::Reference< css::container::XNameContainer > m_xUnoControlDialogModel;
+ css::uno::Reference< css::awt::XControlContainer > m_xControlContainer;
+ css::uno::Sequence< css::datatransfer::DataFlavor > m_ClipboardDataFlavors;
+ css::uno::Sequence< css::datatransfer::DataFlavor > m_ClipboardDataFlavorsResource;
+ css::uno::Reference< css::util::XNumberFormatsSupplier > m_xSupplier;
+ std::unique_ptr<DlgEdFactory, o3tl::default_delete<DlgEdFactory>> pObjFac; // never nullptr
+ vcl::Window& rWindow; // DialogWindow
+ std::unique_ptr<DlgEdFunc> pFunc;
+ DialogWindowLayout& rLayout;
+ Mode eMode;
+ SdrObjKind eActObj;
+ bool bFirstDraw;
+ bool bCreateOK;
+ tools::Rectangle aPaintRect;
+ bool bDialogModelChanged;
+ Idle aMarkIdle;
+ tools::Long mnPaintGuard;
+ css::uno::Reference< css::frame::XModel > m_xDocument;
+
+public:
+ DlgEditor (
+ vcl::Window&, DialogWindowLayout&,
+ css::uno::Reference<css::frame::XModel> const& xModel,
+ css::uno::Reference<css::container::XNameContainer> const & xDialogModel
+ );
+ virtual ~DlgEditor() override;
+
+ vcl::Window& GetWindow() const { return rWindow; }
+
+ /** returns the control container associated with our window
+ @see GetWindow
+ @see SetWindow
+ */
+ css::uno::Reference< css::awt::XControlContainer > const &
+ GetWindowControlContainer();
+
+ void SetScrollBars(ScrollAdaptor* pHScroll, ScrollAdaptor* pVScroll);
+ void InitScrollBars();
+ ScrollAdaptor* GetHScroll() const { return pHScroll; }
+ ScrollAdaptor* GetVScroll() const { return pVScroll; }
+ void DoScroll();
+ void UpdateScrollBars();
+
+ void SetDialog (const css::uno::Reference<css::container::XNameContainer>& xUnoControlDialogModel);
+ void ResetDialog ();
+ const css::uno::Reference< css::container::XNameContainer >& GetDialog() const
+ {return m_xUnoControlDialogModel;}
+
+ css::uno::Reference< css::util::XNumberFormatsSupplier > const & GetNumberFormatsSupplier();
+
+ DlgEdModel& GetModel() const { return *pDlgEdModel; }
+ DlgEdView& GetView() const { return *pDlgEdView; }
+ DlgEdPage& GetPage() const { return *pDlgEdPage; }
+
+ void ShowDialog();
+
+ bool UnmarkDialog();
+ bool RemarkDialog();
+
+ void SetDialogModelChanged() { bDialogModelChanged = true; }
+
+ bool IsModified () const;
+ void ClearModifyFlag();
+
+ void MouseButtonDown( const MouseEvent& rMEvt );
+ void MouseButtonUp( const MouseEvent& rMEvt );
+ void MouseMove( const MouseEvent& rMEvt );
+ void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect);
+ bool KeyInput( const KeyEvent& rKEvt );
+
+ void SetMode (Mode eMode);
+ void SetInsertObj(SdrObjKind eObj);
+ void CreateDefaultObject();
+ Mode GetMode() const { return eMode; }
+ bool IsCreateOK() const { return bCreateOK; }
+
+ void Cut();
+ void Copy();
+ void Paste();
+ void Delete();
+ bool IsPasteAllowed();
+
+ void ShowProperties();
+ void UpdatePropertyBrowserDelayed();
+
+ static void printPage( sal_Int32 nPage, Printer* pPrinter, const OUString& );
+
+ bool AdjustPageSize();
+
+ bool isInPaint() const { return mnPaintGuard > 0; }
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/dlgedclip.hxx b/basctl/source/inc/dlgedclip.hxx
new file mode 100644
index 0000000000..0bb7a74161
--- /dev/null
+++ b/basctl/source/inc/dlgedclip.hxx
@@ -0,0 +1,53 @@
+/* -*- 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/datatransfer/clipboard/XClipboardOwner.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace basctl
+{
+
+
+class DlgEdTransferableImpl final : public ::cppu::WeakImplHelper< css::datatransfer::XTransferable,
+ css::datatransfer::clipboard::XClipboardOwner >
+{
+private:
+ css::uno::Sequence< css::datatransfer::DataFlavor > m_SeqFlavors;
+ css::uno::Sequence< css::uno::Any > m_SeqData;
+
+ static bool compareDataFlavors( const css::datatransfer::DataFlavor& lFlavor, const css::datatransfer::DataFlavor& rFlavor );
+
+public:
+ DlgEdTransferableImpl( const css::uno::Sequence< css::datatransfer::DataFlavor >& aSeqFlavors, const css::uno::Sequence< css::uno::Any >& aSeqData );
+ virtual ~DlgEdTransferableImpl() override;
+
+ // XTransferable
+ virtual css::uno::Any SAL_CALL getTransferData( const css::datatransfer::DataFlavor& rFlavor ) override;
+ virtual css::uno::Sequence< css::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors() override;
+ virtual sal_Bool SAL_CALL isDataFlavorSupported( const css::datatransfer::DataFlavor& rFlavor ) override;
+
+ // XClipboardOwner
+ virtual void SAL_CALL lostOwnership( const css::uno::Reference< css::datatransfer::clipboard::XClipboard >& xClipboard, const css::uno::Reference< css::datatransfer::XTransferable >& xTrans ) override;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/dlgeddef.hxx b/basctl/source/inc/dlgeddef.hxx
new file mode 100644
index 0000000000..c10ef16cd8
--- /dev/null
+++ b/basctl/source/inc/dlgeddef.hxx
@@ -0,0 +1,47 @@
+/* -*- 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 <rtl/ustring.hxx>
+
+namespace basctl
+{
+
+// control properties
+#define DLGED_PROP_BACKGROUNDCOLOR "BackgroundColor"
+inline constexpr OUString DLGED_PROP_DROPDOWN = u"Dropdown"_ustr;
+inline constexpr OUString DLGED_PROP_FORMATSSUPPLIER = u"FormatsSupplier"_ustr;
+inline constexpr OUString DLGED_PROP_HEIGHT = u"Height"_ustr;
+inline constexpr OUString DLGED_PROP_LABEL = u"Label"_ustr;
+inline constexpr OUString DLGED_PROP_NAME = u"Name"_ustr;
+inline constexpr OUString DLGED_PROP_ORIENTATION = u"Orientation"_ustr;
+inline constexpr OUString DLGED_PROP_POSITIONX = u"PositionX"_ustr;
+inline constexpr OUString DLGED_PROP_POSITIONY = u"PositionY"_ustr;
+inline constexpr OUString DLGED_PROP_STEP = u"Step"_ustr;
+inline constexpr OUString DLGED_PROP_TABINDEX = u"TabIndex"_ustr;
+#define DLGED_PROP_TEXTCOLOR "TextColor"
+#define DLGED_PROP_TEXTLINECOLOR "TextLineColor"
+inline constexpr OUString DLGED_PROP_WIDTH = u"Width"_ustr;
+inline constexpr OUString DLGED_PROP_DECORATION = u"Decoration"_ustr;
+
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/dlgedfac.hxx b/basctl/source/inc/dlgedfac.hxx
new file mode 100644
index 0000000000..5e583ada17
--- /dev/null
+++ b/basctl/source/inc/dlgedfac.hxx
@@ -0,0 +1,43 @@
+/* -*- 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 <svx/svdobj.hxx>
+#include <tools/link.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+
+namespace basctl
+{
+// DlgEdFactory
+
+class DlgEdFactory
+{
+ const css::uno::Reference<css::frame::XModel> mxModel;
+
+public:
+ DlgEdFactory(css::uno::Reference<css::frame::XModel> xModel);
+ ~DlgEdFactory() COVERITY_NOEXCEPT_FALSE;
+
+ DECL_LINK(MakeObject, SdrObjCreatorParams, rtl::Reference<SdrObject>);
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/dlgedfunc.hxx b/basctl/source/inc/dlgedfunc.hxx
new file mode 100644
index 0000000000..9e20f39015
--- /dev/null
+++ b/basctl/source/inc/dlgedfunc.hxx
@@ -0,0 +1,80 @@
+/* -*- 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/event.hxx>
+#include <vcl/timer.hxx>
+#include <tools/link.hxx>
+#include <tools/gen.hxx>
+
+namespace basctl
+{
+class DlgEditor;
+
+// DlgEdFunc
+
+class DlgEdFunc /* : public LinkHdl */
+{
+protected:
+ DlgEditor& rParent;
+ Timer aScrollTimer;
+
+ DECL_LINK(ScrollTimeout, Timer*, void);
+ void ForceScroll(const Point& rPos);
+
+public:
+ explicit DlgEdFunc(DlgEditor& rParent);
+ virtual ~DlgEdFunc();
+
+ virtual void MouseButtonDown(const MouseEvent& rMEvt);
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt);
+ virtual void MouseMove(const MouseEvent& rMEvt);
+ bool KeyInput(const KeyEvent& rKEvt);
+};
+
+// DlgEdFuncInsert
+
+class DlgEdFuncInsert : public DlgEdFunc
+{
+public:
+ explicit DlgEdFuncInsert(DlgEditor& rParent);
+ virtual ~DlgEdFuncInsert() override;
+
+ virtual void MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual void MouseMove(const MouseEvent& rMEvt) override;
+};
+
+// DlgEdFuncSelect
+
+class DlgEdFuncSelect : public DlgEdFunc
+{
+public:
+ explicit DlgEdFuncSelect(DlgEditor& rParent);
+ virtual ~DlgEdFuncSelect() override;
+
+ virtual void MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual void MouseMove(const MouseEvent& rMEvt) override;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/dlgedlist.hxx b/basctl/source/inc/dlgedlist.hxx
new file mode 100644
index 0000000000..373f38b146
--- /dev/null
+++ b/basctl/source/inc/dlgedlist.hxx
@@ -0,0 +1,74 @@
+/* -*- 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 <cppuhelper/implbase.hxx>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+
+namespace basctl
+{
+class DlgEdObj;
+
+// DlgEdPropListenerImpl
+
+typedef ::cppu::WeakImplHelper<css::beans::XPropertyChangeListener> PropertyChangeListenerHelper;
+
+class DlgEdPropListenerImpl : public PropertyChangeListenerHelper
+{
+private:
+ DlgEdObj& rDlgEdObj;
+
+public:
+ explicit DlgEdPropListenerImpl(DlgEdObj&);
+ virtual ~DlgEdPropListenerImpl() override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& evt) override;
+};
+
+// DlgEdEvtContListenerImpl
+
+typedef ::cppu::WeakImplHelper<css::container::XContainerListener> ContainerListenerHelper;
+
+class DlgEdEvtContListenerImpl : public ContainerListenerHelper
+{
+private:
+ DlgEdObj& rDlgEdObj;
+
+public:
+ explicit DlgEdEvtContListenerImpl(DlgEdObj&);
+ virtual ~DlgEdEvtContListenerImpl() override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ // XContainerListener
+ virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& Event) override;
+ virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& Event) override;
+ virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& Event) override;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/dlgedmod.hxx b/basctl/source/inc/dlgedmod.hxx
new file mode 100644
index 0000000000..24a97905b1
--- /dev/null
+++ b/basctl/source/inc/dlgedmod.hxx
@@ -0,0 +1,45 @@
+/* -*- 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 <svx/svdmodel.hxx>
+
+namespace basctl
+{
+// DlgEdModel
+
+class DlgEdModel : public SdrModel
+{
+ friend class DlgEdPage;
+
+private:
+ DlgEdModel(const DlgEdModel&) = delete;
+ void operator=(const DlgEdModel& rSrcModel) = delete;
+
+public:
+ DlgEdModel();
+ virtual ~DlgEdModel() override;
+
+ virtual rtl::Reference<SdrPage> AllocPage(bool bMasterPage) override;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/dlgedobj.hxx b/basctl/source/inc/dlgedobj.hxx
new file mode 100644
index 0000000000..a8c249adec
--- /dev/null
+++ b/basctl/source/inc/dlgedobj.hxx
@@ -0,0 +1,195 @@
+/* -*- 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/XModel.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <svx/svdouno.hxx>
+
+#include <optional>
+
+#include <map>
+
+namespace basctl
+{
+
+typedef std::multimap< sal_Int16, OUString > IndexToNameMap;
+
+
+class DlgEdForm;
+class DlgEditor;
+
+
+// DlgEdObj
+
+
+class DlgEdObj: public SdrUnoObj
+{
+ friend class DlgEditor;
+ friend class DlgEdFactory;
+ friend class DlgEdPropListenerImpl;
+ friend class DlgEdForm;
+
+private:
+ bool bIsListening;
+ rtl::Reference<DlgEdForm> pDlgEdForm;
+ css::uno::Reference< css::beans::XPropertyChangeListener> m_xPropertyChangeListener;
+ css::uno::Reference< css::container::XContainerListener> m_xContainerListener;
+
+private:
+ DlgEditor& GetDialogEditor ();
+
+protected:
+ DlgEdObj(SdrModel& rSdrModel);
+ // copy constructor
+ DlgEdObj(SdrModel& rSdrModel, DlgEdObj const & rSource);
+ DlgEdObj(
+ SdrModel& rSdrModel,
+ const OUString& rModelName,
+ const css::uno::Reference< css::lang::XMultiServiceFactory >& rxSFac);
+
+ // protected destructor
+ virtual ~DlgEdObj() override;
+
+ virtual void NbcMove( const Size& rSize ) override;
+ virtual void NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact) override;
+ virtual bool EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) override;
+
+ using SfxListener::StartListening;
+ void StartListening();
+ using SfxListener::EndListening;
+ void EndListening(bool bRemoveListener);
+ bool isListening() const { return bIsListening; }
+
+ bool TransformSdrToControlCoordinates(
+ sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn,
+ sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut );
+ bool TransformSdrToFormCoordinates(
+ sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn,
+ sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut );
+ bool TransformControlToSdrCoordinates(
+ sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn,
+ sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut );
+ bool TransformFormToSdrCoordinates(
+ sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn,
+ sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut );
+
+public:
+ void SetDlgEdForm( DlgEdForm* pForm ) { pDlgEdForm = pForm; }
+ DlgEdForm* GetDlgEdForm() const { return pDlgEdForm.get(); }
+
+ virtual SdrInventor GetObjInventor() const override;
+ virtual SdrObjKind GetObjIdentifier() const override;
+
+ virtual rtl::Reference<SdrObject> CloneSdrObject(SdrModel& rTargetModel) const override; // not working yet
+
+ // FullDrag support
+ virtual rtl::Reference<SdrObject> getFullDragClone() const override;
+
+ bool supportsService( OUString const & serviceName ) const;
+ OUString GetDefaultName() const;
+ OUString GetUniqueName() const;
+
+ sal_Int32 GetStep() const;
+ virtual void UpdateStep();
+
+ void SetDefaults();
+ virtual void SetRectFromProps();
+ virtual void SetPropsFromRect();
+
+ css::uno::Reference< css::awt::XControl > GetControl() const;
+
+ virtual void PositionAndSizeChange( const css::beans::PropertyChangeEvent& evt );
+ /// @throws css::container::NoSuchElementException
+ /// @throws css::uno::RuntimeException
+ void NameChange( const css::beans::PropertyChangeEvent& evt );
+ /// @throws css::uno::RuntimeException
+ void TabIndexChange( const css::beans::PropertyChangeEvent& evt );
+
+ // PropertyChangeListener
+ /// @throws css::uno::RuntimeException
+ void _propertyChange(const css::beans::PropertyChangeEvent& evt);
+
+ // ContainerListener
+ /// @throws css::uno::RuntimeException
+ void _elementInserted();
+ /// @throws css::uno::RuntimeException
+ void _elementReplaced();
+ /// @throws css::uno::RuntimeException
+ void _elementRemoved();
+
+ virtual void SetLayer(SdrLayerID nLayer) override;
+ void MakeDataAware( const css::uno::Reference< css::frame::XModel >& xModel );
+};
+
+
+// DlgEdForm
+
+
+class DlgEdForm: public DlgEdObj
+{
+ friend class DlgEditor;
+ friend class DlgEdFactory;
+
+private:
+ DlgEditor& rDlgEditor;
+ std::vector<DlgEdObj*> pChildren;
+
+ mutable ::std::optional< css::awt::DeviceInfo > mpDeviceInfo;
+
+private:
+ explicit DlgEdForm(
+ SdrModel& rSdrModel,
+ DlgEditor&);
+
+protected:
+ virtual void NbcMove( const Size& rSize ) override;
+ virtual void NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact) override;
+ virtual bool EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) override;
+
+ // protected destructor
+ virtual ~DlgEdForm() override;
+
+public:
+ DlgEditor& GetDlgEditor () const { return rDlgEditor; }
+
+ void AddChild( DlgEdObj* pDlgEdObj );
+ void RemoveChild( DlgEdObj* pDlgEdObj );
+ std::vector<DlgEdObj*> const& GetChildren() const { return pChildren; }
+
+ virtual void UpdateStep() override;
+
+ virtual void SetRectFromProps() override;
+ virtual void SetPropsFromRect() override;
+
+ virtual void PositionAndSizeChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ void UpdateTabIndices();
+ void UpdateTabOrder();
+ void UpdateGroups();
+ void UpdateTabOrderAndGroups();
+
+ css::awt::DeviceInfo getDeviceInfo() const;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/dlgedpage.hxx b/basctl/source/inc/dlgedpage.hxx
new file mode 100644
index 0000000000..91efc12edd
--- /dev/null
+++ b/basctl/source/inc/dlgedpage.hxx
@@ -0,0 +1,52 @@
+/* -*- 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 <svx/svdpage.hxx>
+
+namespace basctl
+{
+// DlgEdPage
+
+class DlgEdModel;
+class DlgEdForm;
+
+class DlgEdPage final : public SdrPage
+{
+ DlgEdPage& operator=(const DlgEdPage&) = delete;
+ DlgEdPage(const DlgEdPage&) = delete;
+
+ DlgEdForm* pDlgEdForm;
+
+public:
+ explicit DlgEdPage(DlgEdModel& rModel, bool bMasterPage = false);
+ virtual ~DlgEdPage() override;
+
+ virtual rtl::Reference<SdrPage> CloneSdrPage(SdrModel& rTargetModel) const override;
+
+ void SetDlgEdForm(DlgEdForm* pForm) { pDlgEdForm = pForm; }
+ DlgEdForm* GetDlgEdForm() const { return pDlgEdForm; }
+
+ virtual SdrObject* SetObjectOrdNum(size_t nOldObjNum, size_t nNewObjNum) override;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/dlgedview.hxx b/basctl/source/inc/dlgedview.hxx
new file mode 100644
index 0000000000..195dee8403
--- /dev/null
+++ b/basctl/source/inc/dlgedview.hxx
@@ -0,0 +1,59 @@
+/* -*- 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 <svx/svdview.hxx>
+
+namespace basctl
+{
+
+class DlgEditor;
+
+
+// DlgEdView
+
+
+class DlgEdView : public SdrView
+{
+private:
+ DlgEditor& rDlgEditor;
+
+public:
+
+ DlgEdView(
+ SdrModel& rSdrModel,
+ OutputDevice& rOut,
+ DlgEditor& rEditor);
+
+ virtual ~DlgEdView() override;
+
+ virtual void MarkListHasChanged() override;
+ virtual void MakeVisible( const tools::Rectangle& rRect, vcl::Window& rWin ) override;
+
+protected:
+ /// override to handle HitTest for some objects specially
+ using SdrView::CheckSingleSdrObjectHit;
+ virtual SdrObject* CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay) const override;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/doceventnotifier.hxx b/basctl/source/inc/doceventnotifier.hxx
new file mode 100644
index 0000000000..25fd2a7a84
--- /dev/null
+++ b/basctl/source/inc/doceventnotifier.hxx
@@ -0,0 +1,82 @@
+/* -*- 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/XModel.hpp>
+
+#include <rtl/ref.hxx>
+
+
+namespace basctl
+{
+
+
+ class ScriptDocument;
+
+
+ class SAL_NO_VTABLE DocumentEventListener
+ {
+ public:
+ DocumentEventListener(const DocumentEventListener&) = delete;
+ const DocumentEventListener& operator=(const DocumentEventListener&) = delete;
+ DocumentEventListener() = default;
+
+ virtual void onDocumentCreated( const ScriptDocument& _rDocument ) = 0;
+ virtual void onDocumentOpened( const ScriptDocument& _rDocument ) = 0;
+ virtual void onDocumentSave( const ScriptDocument& _rDocument ) = 0;
+ virtual void onDocumentSaveDone( const ScriptDocument& _rDocument ) = 0;
+ virtual void onDocumentSaveAs( const ScriptDocument& _rDocument ) = 0;
+ virtual void onDocumentSaveAsDone( const ScriptDocument& _rDocument ) = 0;
+ virtual void onDocumentClosed( const ScriptDocument& _rDocument ) = 0;
+ virtual void onDocumentTitleChanged( const ScriptDocument& _rDocument ) = 0;
+ virtual void onDocumentModeChanged( const ScriptDocument& _rDocument ) = 0;
+
+ virtual ~DocumentEventListener();
+ };
+
+
+ /** allows registering at theGlobalEventBroadcaster for global document events
+ */
+ class DocumentEventNotifier
+ {
+ public:
+ /** create a notifier instance which notifies about events of all documents in the whole application
+ */
+ DocumentEventNotifier (DocumentEventListener&);
+
+ /** creates a notifier instance which notifies about events at a single document
+ */
+ DocumentEventNotifier (DocumentEventListener&, css::uno::Reference<css::frame::XModel> const& rxDocument);
+
+ ~DocumentEventNotifier();
+
+ public:
+ void dispose();
+
+ private:
+ class Impl;
+ rtl::Reference<Impl> m_pImpl;
+ };
+
+
+} // namespace basctl
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/docsignature.hxx b/basctl/source/inc/docsignature.hxx
new file mode 100644
index 0000000000..1681807d39
--- /dev/null
+++ b/basctl/source/inc/docsignature.hxx
@@ -0,0 +1,74 @@
+/* -*- 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/signaturestate.hxx>
+#include <vcl/weld.hxx>
+
+class SfxObjectShell;
+
+namespace basctl
+{
+
+
+ class ScriptDocument;
+
+ /// encapsulates (actions on) the signature/state of a document
+ class DocumentSignature
+ {
+ public:
+ /** creates a DocumentSignature instance for the given document
+
+ If the given ScriptDocument instance refers to the application, or to a document
+ which does not support being signed, the DocumentSignature instance is invalid afterwards.
+ */
+ explicit DocumentSignature (ScriptDocument const&);
+
+ /** determines whether the instance is valid
+
+ An instance is valid if and only if it has been constructed with a document
+ which supports signatures.
+ */
+ bool supportsSignatures() const;
+
+ /** signs the scripting content inside the document
+
+ @precond
+ isValid returns <TRUE/>
+ */
+ void signScriptingContent(weld::Window* pDialogParent) const;
+
+ /** retrieves the state of the signature of the scripting content inside the document
+
+ If the instance is not valid, then SIGNATURESTATE_NOSIGNATURES is returned.
+ */
+ SignatureState getScriptingSignatureState() const;
+
+ private:
+ DocumentSignature() = delete;
+
+ private:
+ SfxObjectShell* m_pShell;
+ };
+
+
+} // namespace basctl
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/iderid.hxx b/basctl/source/inc/iderid.hxx
new file mode 100644
index 0000000000..83cbc3d0c4
--- /dev/null
+++ b/basctl/source/inc/iderid.hxx
@@ -0,0 +1,31 @@
+/* -*- 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 <rtl/ustring.hxx>
+#include <unotools/resmgr.hxx>
+
+namespace basctl
+{
+OUString IDEResId(TranslateId aId);
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/layout.hxx b/basctl/source/inc/layout.hxx
new file mode 100644
index 0000000000..29b44896b3
--- /dev/null
+++ b/basctl/source/inc/layout.hxx
@@ -0,0 +1,133 @@
+/* -*- 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 "bastypes.hxx"
+#include <vcl/split.hxx>
+#include <vcl/vclptr.hxx>
+
+#include <vector>
+
+class DockingWindow;
+class SfxRequest;
+class SfxItemSet;
+
+namespace basctl
+{
+class DockingWindow;
+class BaseWindow;
+
+// Layout -- the common base of ModulLayout and DialogLayout.
+// Handles the splitting lines and the dockable windows.
+
+class Layout : public vcl::Window
+{
+public:
+ void ArrangeWindows();
+
+ virtual void Activating(BaseWindow&);
+ virtual void Deactivating();
+ virtual void ExecuteGlobal(SfxRequest&) {}
+ virtual void GetState(SfxItemSet&, unsigned nWhich) = 0;
+ virtual void UpdateDebug(bool bBasicStopped) = 0;
+
+ virtual ~Layout() override;
+ virtual void dispose() override;
+
+protected:
+ explicit Layout(vcl::Window* pParent);
+
+ void AddToLeft(DockingWindow* pWin, Size const& rSize) { aLeftSide.Add(pWin, rSize); }
+ void AddToBottom(DockingWindow* pWin, Size const& rSize) { aBottomSide.Add(pWin, rSize); }
+ void Remove(DockingWindow*);
+ bool HasSize() const { return !bFirstSize; }
+
+ // Window:
+ virtual void Resize() override;
+ virtual void DataChanged(DataChangedEvent const& rDCEvt) override;
+ // new:
+ virtual void OnFirstSize(tools::Long nWidth, tools::Long nHeight) = 0;
+
+private:
+ // the main child window (either ModulWindow or DialogWindow)
+ VclPtr<BaseWindow> pChild;
+
+ // when this window has at first (nonempty) size
+ bool bFirstSize;
+
+ // horizontal or vertical split strip
+ class SplittedSide
+ {
+ public:
+ enum class Side
+ {
+ Left,
+ Bottom
+ };
+ SplittedSide(Layout*, Side);
+ void Add(DockingWindow*, Size const&);
+ void Remove(DockingWindow*);
+ bool IsEmpty() const;
+ tools::Long GetSize() const;
+ void ArrangeIn(tools::Rectangle const&);
+ void dispose();
+
+ private:
+ // the layout window
+ Layout& rLayout;
+ // horizontal or vertical strip?
+ bool bVertical;
+ // lower (top or left) or higher (bottom or right) strip?
+ bool bLower;
+ // rectangle to move in
+ tools::Rectangle aRect;
+ // size (width or height)
+ tools::Long nSize;
+ // the main splitting line
+ VclPtr<Splitter> aSplitter;
+ // the dockable windows (and some data)
+ struct Item
+ {
+ // pointer to the dockable window
+ VclPtr<DockingWindow> pWin;
+ // starting and ending position in the strip
+ // They may be different from the actual window position, because
+ // the window may fill the space of the adjacent currently
+ // non-docking windows, but this change is not stored in these
+ // variables. These change only when the splitter lines are moved.
+ tools::Long nStartPos, nEndPos;
+ // splitter line window before the window
+ // (the first one is always nullptr)
+ VclPtr<Splitter> pSplit;
+ };
+ std::vector<Item> vItems;
+
+ Point MakePoint(tools::Long, tools::Long) const;
+ Size MakeSize(tools::Long, tools::Long) const;
+ static bool IsDocking(DockingWindow const&);
+ DECL_LINK(SplitHdl, Splitter*, void);
+ void CheckMarginsFor(Splitter*);
+ void InitSplitter(Splitter&);
+ } aLeftSide, aBottomSide;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/localizationmgr.hxx b/basctl/source/inc/localizationmgr.hxx
new file mode 100644
index 0000000000..3e2ff0fc58
--- /dev/null
+++ b/basctl/source/inc/localizationmgr.hxx
@@ -0,0 +1,151 @@
+/* -*- 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 "scriptdocument.hxx"
+
+#include <com/sun/star/resource/XStringResourceManager.hpp>
+
+namespace basctl
+{
+
+class Shell;
+class DlgEditor;
+
+class LocalizationMgr
+{
+ css::uno::Reference< css::resource::XStringResourceManager > m_xStringResourceManager;
+
+ Shell* m_pShell;
+
+ ScriptDocument m_aDocument;
+ OUString m_aLibName;
+
+ css::lang::Locale m_aLocaleBeforeBasicStart;
+
+ enum HandleResourceMode
+ {
+ SET_IDS,
+ RESET_IDS,
+ RENAME_DIALOG_IDS,
+ RENAME_CONTROL_IDS,
+ REMOVE_IDS_FROM_RESOURCE,
+ MOVE_RESOURCES,
+ COPY_RESOURCES
+ };
+ static sal_Int32 implHandleControlResourceProperties(const css::uno::Any& rControlAny,
+ std::u16string_view aDialogName,
+ std::u16string_view aCtrlName,
+ const css::uno::Reference< css::resource::XStringResourceManager >& xStringResourceManager,
+ const css::uno::Reference< css::resource::XStringResourceResolver >& xSourceStringResolver,
+ HandleResourceMode eMode );
+
+ void enableResourceForAllLibraryDialogs()
+ {
+ implEnableDisableResourceForAllLibraryDialogs( SET_IDS );
+ }
+ void disableResourceForAllLibraryDialogs()
+ {
+ implEnableDisableResourceForAllLibraryDialogs( RESET_IDS );
+ }
+ void implEnableDisableResourceForAllLibraryDialogs( HandleResourceMode eMode );
+
+public:
+ LocalizationMgr(Shell*, ScriptDocument , OUString aLibName,
+ const css::uno::Reference < css::resource::XStringResourceManager >& xStringResourceManager );
+
+ const css::uno::Reference< css::resource::XStringResourceManager >& getStringResourceManager() const
+ {
+ return m_xStringResourceManager;
+ }
+
+ bool isLibraryLocalized();
+
+ void handleTranslationbar();
+
+ void handleAddLocales( const css::uno::Sequence
+ < css::lang::Locale >& aLocaleSeq );
+
+ void handleRemoveLocales( const css::uno::Sequence
+ < css::lang::Locale >& aLocaleSeq );
+
+ void handleSetDefaultLocale(const css::lang::Locale& rLocale);
+
+ void handleSetCurrentLocale(const css::lang::Locale& rLocale);
+
+ void handleBasicStarted();
+
+ void handleBasicStopped();
+
+ static void setControlResourceIDsForNewEditorObject(DlgEditor const * pEditor,
+ const css::uno::Any& rControlAny, std::u16string_view aCtrlName);
+
+ static void renameControlResourceIDsForEditorObject(DlgEditor const * pEditor,
+ const css::uno::Any& rControlAny, std::u16string_view aNewCtrlName);
+
+ static void deleteControlResourceIDsForDeletedEditorObject(DlgEditor const * pEditor,
+ const css::uno::Any& rControlAny, std::u16string_view aCtrlName);
+
+ static void setStringResourceAtDialog( const ScriptDocument& rDocument, const OUString& aLibName, std::u16string_view aDlgName,
+ const css::uno::Reference< css::container::XNameContainer >& xDialogModel );
+
+ static void renameStringResourceIDs( const ScriptDocument& rDocument, const OUString& aLibName, std::u16string_view aDlgName,
+ const css::uno::Reference< css::container::XNameContainer >& xDialogModel );
+
+ static void removeResourceForDialog( const ScriptDocument& rDocument, const OUString& aLibName, std::u16string_view aDlgName,
+ const css::uno::Reference< css::container::XNameContainer >& xDialogModel );
+
+ static css::uno::Reference< css::resource::XStringResourceManager >
+ getStringResourceFromDialogLibrary( const css::uno::Reference< css::container::XNameContainer >& xDialogLib );
+
+ // Clipboard / Drag & Drop
+ static void resetResourceForDialog(
+ const css::uno::Reference< css::container::XNameContainer >& xDialogModel,
+ const css::uno::Reference< css::resource::XStringResourceManager >& xStringResourceManager );
+
+ static void setResourceIDsForDialog(
+ const css::uno::Reference< css::container::XNameContainer >& xDialogModel,
+ const css::uno::Reference< css::resource::XStringResourceManager >& xStringResourceManager );
+
+ static void copyResourcesForPastedEditorObject( DlgEditor const * pEditor,
+ const css::uno::Any& rControlAny, std::u16string_view aCtrlName,
+ const css::uno::Reference< css::resource::XStringResourceResolver >& xSourceStringResolver );
+
+ static void copyResourceForDroppedDialog(
+ const css::uno::Reference< css::container::XNameContainer >& xDialogModel,
+ std::u16string_view aDialogName,
+ const css::uno::Reference< css::resource::XStringResourceManager >& xStringResourceManager,
+ const css::uno::Reference< css::resource::XStringResourceResolver >& xSourceStringResolver );
+
+ static void copyResourceForDialog(
+ const css::uno::Reference< css::container::XNameContainer >& xDialogModel,
+ const css::uno::Reference< css::resource::
+ XStringResourceResolver >& xSourceStringResolver,
+ const css::uno::Reference< css::resource::
+ XStringResourceManager >& xTargetStringResourceManager );
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/managelang.hxx b/basctl/source/inc/managelang.hxx
new file mode 100644
index 0000000000..58dd418905
--- /dev/null
+++ b/basctl/source/inc/managelang.hxx
@@ -0,0 +1,98 @@
+/* -*- 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 <utility>
+#include <vcl/weld.hxx>
+
+class SvxLanguageBox;
+
+namespace basctl
+{
+
+class LocalizationMgr;
+
+struct LanguageEntry
+{
+ css::lang::Locale m_aLocale;
+ bool m_bIsDefault;
+
+ LanguageEntry( css::lang::Locale _aLocale,
+ bool _bIsDefault ) :
+ m_aLocale(std::move( _aLocale )),
+ m_bIsDefault( _bIsDefault ) {}
+};
+
+extern bool localesAreEqual( const css::lang::Locale& rLocaleLeft,
+ const css::lang::Locale& rLocaleRight );
+
+class ManageLanguageDialog : public weld::GenericDialogController
+{
+private:
+ std::shared_ptr<LocalizationMgr> m_xLocalizationMgr;
+
+ OUString m_sDefLangStr;
+ OUString m_sCreateLangStr;
+
+ std::unique_ptr<weld::TreeView> m_xLanguageLB;
+ std::unique_ptr<weld::Button> m_xAddPB;
+ std::unique_ptr<weld::Button> m_xDeletePB;
+ std::unique_ptr<weld::Button> m_xMakeDefPB;
+
+ void Init();
+ void FillLanguageBox();
+ void ClearLanguageBox();
+
+ DECL_LINK(AddHdl, weld::Button&, void);
+ DECL_LINK(DeleteHdl, weld::Button&, void);
+ DECL_LINK(MakeDefHdl, weld::Button&, void);
+ DECL_LINK(SelectHdl, weld::TreeView&, void);
+
+public:
+ ManageLanguageDialog(weld::Window* pParent, std::shared_ptr<LocalizationMgr> _pLMgr);
+ virtual ~ManageLanguageDialog() override;
+};
+
+class SetDefaultLanguageDialog : public weld::GenericDialogController
+{
+private:
+ std::shared_ptr<LocalizationMgr> m_xLocalizationMgr;
+
+ void FillLanguageBox();
+
+ std::unique_ptr<weld::Label> m_xLanguageFT;
+ std::unique_ptr<weld::TreeView> m_xLanguageLB;
+ std::unique_ptr<weld::Label> m_xCheckLangFT;
+ std::unique_ptr<weld::TreeView> m_xCheckLangLB;
+ std::unique_ptr<weld::Label> m_xDefinedFT;
+ std::unique_ptr<weld::Label> m_xAddedFT;
+ std::unique_ptr<weld::Label> m_xAltTitle;
+ std::unique_ptr<SvxLanguageBox> m_xLanguageCB;
+
+public:
+ SetDefaultLanguageDialog(weld::Window* pParent, std::shared_ptr<LocalizationMgr> xLMgr);
+ virtual ~SetDefaultLanguageDialog() override;
+
+ css::uno::Sequence< css::lang::Locale > GetLocales() const;
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/propbrw.hxx b/basctl/source/inc/propbrw.hxx
new file mode 100644
index 0000000000..c9ad803444
--- /dev/null
+++ b/basctl/source/inc/propbrw.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <vector>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/XFrame2.hpp>
+#include <svl/lstner.hxx>
+#include <svl/SfxBroadcaster.hxx>
+#include <svx/svdmark.hxx>
+#include "bastypes.hxx"
+
+class SfxBindings;
+class SdrView;
+class SfxViewShell;
+
+namespace basctl
+{
+
+class DialogWindowLayout;
+
+class PropBrw final : public DockingWindow, public SfxListener, public SfxBroadcaster
+{
+private:
+ VclPtr<vcl::Window> m_xContentArea;
+ bool m_bInitialStateChange;
+
+ css::uno::Reference< css::frame::XFrame2 >
+ m_xMeAsFrame;
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xBrowserController;
+ css::uno::Reference< css::frame::XModel >
+ m_xContextDocument;
+
+ SdrView* pView;
+ virtual bool Close() override;
+
+ typedef std::vector< css::uno::Reference< css::uno::XInterface> > InterfaceArray;
+
+ static css::uno::Sequence< css::uno::Reference< css::uno::XInterface > >
+ CreateMultiSelectionSequence( const SdrMarkList& _rMarkList );
+ void implSetNewObjectSequence( const css::uno::Sequence
+ < css::uno::Reference< css::uno::XInterface > >& _rObjectSeq );
+
+ void implSetNewObject( const css::uno::Reference< css::beans::XPropertySet >& _rxObject);
+
+ static OUString GetHeadlineName( const css::uno::Reference< css::beans::XPropertySet >& _rxObject);
+
+public:
+ explicit PropBrw (DialogWindowLayout&);
+ virtual ~PropBrw() override;
+ virtual void dispose() override;
+ // note: changing the Context document to an instance other than the one given in the ctor is not supported
+ // currently
+ void Update( const SfxViewShell* pShell );
+
+private:
+ void ImplUpdate( const css::uno::Reference< css::frame::XModel >& _rxContextDocument, SdrView* pView );
+ void ImplDestroyController();
+ void ImplReCreateController();
+};
+
+} // namespace basctl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/sbxitem.hxx b/basctl/source/inc/sbxitem.hxx
new file mode 100644
index 0000000000..941ffd3e0e
--- /dev/null
+++ b/basctl/source/inc/sbxitem.hxx
@@ -0,0 +1,65 @@
+/* -*- 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 "scriptdocument.hxx"
+#include <svl/poolitem.hxx>
+
+namespace basctl
+{
+
+enum ItemType
+{
+ TYPE_UNKNOWN,
+ TYPE_SHELL,
+ TYPE_LIBRARY,
+ TYPE_MODULE,
+ TYPE_DIALOG,
+ TYPE_METHOD
+};
+
+class SbxItem : public SfxPoolItem
+{
+ const ScriptDocument m_aDocument;
+ const OUString m_aLibName;
+ const OUString m_aName;
+ const OUString m_aMethodName;
+ ItemType m_eType;
+
+public:
+ static SfxPoolItem* CreateDefault();
+ SbxItem(sal_uInt16 nWhich, ScriptDocument aDocument, OUString aLibName, OUString aName, ItemType);
+ SbxItem(sal_uInt16 nWhich, ScriptDocument aDocument, OUString aLibName, OUString aName, OUString aMethodName, ItemType eType);
+
+ virtual SbxItem* Clone(SfxItemPool *pPool = nullptr) const override;
+ virtual bool operator==(const SfxPoolItem&) const override;
+
+ ScriptDocument const& GetDocument () const { return m_aDocument; }
+ OUString const& GetLibName () const { return m_aLibName; }
+ OUString const& GetName () const { return m_aName; }
+ OUString const& GetMethodName () const { return m_aMethodName; }
+ ItemType GetType () const { return m_eType; }
+};
+
+} // namespace basctl
+
+// For baside.sdi, because I don't know how to use nested names in it.
+using basctl::SbxItem;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basctl/source/inc/scriptdocument.hxx b/basctl/source/inc/scriptdocument.hxx
new file mode 100644
index 0000000000..da7f2b50d3
--- /dev/null
+++ b/basctl/source/inc/scriptdocument.hxx
@@ -0,0 +1,481 @@
+/* -*- 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/script/XLibraryContainer.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/io/XInputStreamProvider.hpp>
+
+#include <memory>
+#include <vector>
+
+class SfxListener;
+
+class BasicManager;
+
+
+namespace basctl
+{
+
+ enum LibraryContainerType
+ {
+ E_SCRIPTS,
+ E_DIALOGS
+ };
+
+ enum LibraryLocation
+ {
+ LIBRARY_LOCATION_UNKNOWN,
+ LIBRARY_LOCATION_USER,
+ LIBRARY_LOCATION_SHARE,
+ LIBRARY_LOCATION_DOCUMENT
+ };
+
+ enum class LibraryType
+ {
+ Module,
+ Dialog,
+ All
+ };
+
+ class ScriptDocument;
+ typedef std::vector< ScriptDocument > ScriptDocuments;
+
+ /** encapsulates a document which contains Basic scripts and dialogs
+ */
+ class ScriptDocument
+ {
+ private:
+ class Impl;
+ std::shared_ptr<Impl> m_pImpl;
+
+ private:
+ /** creates a ScriptDocument instance which operates on the application-wide
+ scripts and dialogs
+ */
+ ScriptDocument();
+
+ public:
+ enum SpecialDocument { NoDocument };
+ /** creates a ScriptDocument instance which does refers to neither the application-wide,
+ nor a specific real document's scripts.
+
+ This constructor might come handy when you need some kind of uninitialized
+ ScriptDocument, which you do not want to operate on (yet), but initialize later
+ by assignment.
+
+ <member>isValid</member> will return <FALSE/> for a ScriptDocument constructed
+ this way.
+ */
+ explicit ScriptDocument( SpecialDocument _eType );
+
+ /** creates a ScriptDocument instance which refers to a document given as
+ XModel
+
+ @param _rxDocument
+ the document. Must not be <NULL/>.
+ */
+ explicit ScriptDocument( const css::uno::Reference< css::frame::XModel >& _rxDocument );
+
+ /** returns a reference to a shared ScriptDocument instance which
+ operates on the application-wide scripts and dialogs
+ */
+ static const ScriptDocument&
+ getApplicationScriptDocument();
+
+ /** returns a (newly created) ScriptDocument instance for the document to
+ which a given BasicManager belongs
+
+ If the basic manager is the application's basic manager, then the (shared)
+ ScriptDocument instance which is responsible for the application is returned.
+
+ @see getApplicationScriptDocument
+ */
+ static ScriptDocument
+ getDocumentForBasicManager( const BasicManager* _pManager );
+
+ /** returns a (newly created) ScriptDocument instance for the document
+ with a given caption or URL
+
+ If there is no document with the given caption, then the (shared)
+ ScriptDocument instance which is responsible for the application is returned.
+
+ @see getApplicationScriptDocument
+ */
+ static ScriptDocument
+ getDocumentWithURLOrCaption( std::u16string_view _rUrlOrCaption );
+
+ /** operation mode for getAllScriptDocuments
+ */
+ enum ScriptDocumentList
+ {
+ /** all ScriptDocuments, including the dedicated one which represents
+ the application-wide scripts/dialogs.
+ */
+ AllWithApplication,
+ /** real documents only, sorted lexicographically by their title (using the sys locale's default
+ collator)
+ */
+ DocumentsSorted
+ };
+
+ /** returns the set of ScriptDocument instances, one for each open document which
+ contains Basic/Dialog containers; plus an additional instance for
+ the application, if desired
+
+ Documents which are not visible - i.e. do not have a visible frame.
+
+ @param _bIncludingApplication
+ <TRUE/> if the application-wide scripts/dialogs should also be represented
+ by a ScriptDocument
+ */
+ static ScriptDocuments
+ getAllScriptDocuments( ScriptDocumentList _eListType );
+
+ // comparison
+ bool operator==( const ScriptDocument& _rhs ) const;
+ bool operator!=( const ScriptDocument& _rhs ) const { return !( *this == _rhs ); }
+
+ /// retrieves a (pretty simple) hash code for the document
+ sal_Int32 hashCode() const;
+
+ /** determines whether the document is actually able to contain Basic/Dialog libraries
+
+ Note that validity does not automatically imply the document can be used for active
+ work. Instead, it is possible the document is closed already (or being closed currently).
+ In this case, isValid will return <TRUE/>, but isAlive will return <FALSE/>.
+
+ @return
+ <TRUE/> if the instance refers to a document which contains Basic/Dialog libraries,
+ or the application as a whole, <FALSE/> otherwise.
+
+ @see isAlive
+ */
+ bool isValid() const;
+
+ /** determines whether the document instance is alive
+
+ If the instance is not valid, <FALSE/> is returned.
+
+ If the instance refers to a real document, which is already closed, or just being closed,
+ the method returns <FALSE/>.
+
+ If the instance refers to the application, <TRUE/> is returned.
+
+ @see isValid
+ */
+ bool isAlive() const;
+
+ bool isInVBAMode() const;
+ /// returns the BasicManager associated with this instance
+ BasicManager*
+ getBasicManager() const;
+
+ /** returns the UNO component representing the document which the instance operates on
+
+ Must not be used when the instance operates on the application-wide
+ Basic/Dialog libraries.
+ */
+ css::uno::Reference< css::frame::XModel >
+ getDocument() const;
+
+ /** returns the UNO component representing the document which the instance operates on
+
+ May be used when the instance operates on the application-wide
+ Basic/Dialog libraries, in this case it returns <NULL/>.
+ */
+ css::uno::Reference< css::frame::XModel >
+ getDocumentOrNull() const;
+
+ /** returns the Basic or Dialog library container of the document
+
+ If the document is not valid, <NULL/> is returned.
+ */
+ css::uno::Reference< css::script::XLibraryContainer >
+ getLibraryContainer( LibraryContainerType _eType ) const;
+
+ /** determines whether there exists a library of the given type, with the given name
+ */
+ bool hasLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const;
+
+ /** returns a script or dialog library given by name
+
+ @param _eType
+ the type of library to load
+ @param _rLibName
+ the name of the script library
+ @param _bLoadLibrary
+ <TRUE/> if and only if the library should be loaded.
+
+ @throws NoSuchElementException
+ if there is no script library with the given name
+ */
+ css::uno::Reference< css::container::XNameContainer >
+ getLibrary( LibraryContainerType _eType, const OUString& _rLibName, bool _bLoadLibrary ) const;
+
+ /** creates a script or dialog library in the document, or returns an existing one
+
+ If <code>_rLibName</code> denotes an existing library which does not need to be created,
+ then this library will automatically be loaded, and then returned.
+ */
+ css::uno::Reference< css::container::XNameContainer >
+ getOrCreateLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const;
+
+ /** returns the names of the modules in a given script or dialog library of the document
+ */
+ css::uno::Sequence< OUString >
+ getObjectNames( LibraryContainerType _eType, const OUString& _rLibName ) const;
+
+ /** retrieves a name for a newly to be created module or dialog
+ */
+ OUString createObjectName( LibraryContainerType _eType, const OUString& _rLibName ) const;
+
+ /** loads a script or dialog library given by name, if there is such a library
+ */
+ void loadLibraryIfExists( LibraryContainerType _eType, const OUString& _rLibrary );
+
+ /// retrieves the (combined) names of all script and dialog libraries
+ css::uno::Sequence< OUString >
+ getLibraryNames() const;
+
+ /** removes a given script module from the document
+
+ @return
+ <TRUE/> if and only if the removal was successful. When <FALSE/> is returned,
+ this will reported as assertion in a non-product build.
+ */
+ bool removeModule( const OUString& _rLibName, const OUString& _rModuleName ) const;
+
+ /** creates a module with the given name in the given library
+ @param _rLibName
+ the library name
+ @param _rModName
+ the name of the to-be-created module
+ @param _bCreateMain
+ determines whether or not a function Main should be created
+ @param _out_rNewModuleCode
+ the source code of the newly created module
+ @return
+ <TRUE/> if and only if the creation was successful
+ */
+ bool createModule( const OUString& _rLibName, const OUString& _rModName, bool _bCreateMain, OUString& _out_rNewModuleCode ) const;
+
+ /** inserts a given piece as code as module
+ @param _rLibName
+ the name of the library to insert the module into. If a library with this name does
+ not yet exist, it will be created.
+ @param _rModName
+ the name of the module to insert the code as. Must denote a name which is not yet
+ used in the module library.
+ @param _rModuleCode
+ the code of the new module
+ @return
+ <TRUE/> if and only if the insertion was successful.
+ */
+ bool insertModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const;
+
+ /** updates a given module with new code
+ @param _rLibName
+ the name of the library the modules lives in. Must denote an existing module library.
+ @param _rModName
+ the name of the module to update. Must denote an existing module in the given library.
+ @param _rModuleCode
+ the new module code.
+ @return
+ <TRUE/> if and only if the insertion was successful.
+ */
+ bool updateModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const;
+
+ /// determines whether a module with the given name exists in the given library
+ bool hasModule( const OUString& _rLibName, const OUString& _rModName ) const;
+
+ /** retrieves a module's source
+ @param _rLibName
+ the library name where the module is located
+ @param _rModName
+ the module name
+ @param _out_rModuleSource
+ takes the module's source upon successful return
+ @return
+ <TRUE/> if and only if the code could be successfully retrieved, <FALSE/> otherwise
+ */
+ bool getModule( const OUString& _rLibName, const OUString& _rModName, OUString& _rModuleSource ) const;
+
+ /** renames a module
+ @param _rLibName
+ the library where the module lives in. Must denote an existing library.
+ @param _rOldName
+ the old module name. Must denote an existing module.
+ @param _rNewName
+ the new module name
+ @return
+ <TRUE/> if and only if renaming was successful.
+ */
+ bool renameModule( const OUString& _rLibName, const OUString& _rOldName, const OUString& _rNewName ) const;
+
+ /** removes a given dialog from the document
+
+ @return
+ <TRUE/> if and only if the removal was successful. When <FALSE/> is returned,
+ this will reported as assertion in a non-product build.
+ */
+ bool removeDialog( const OUString& _rLibName, const OUString& _rDialogName ) const;
+
+ /// determines whether a dialog with the given name exists in the given library
+ bool hasDialog( const OUString& _rLibName, const OUString& _rDialogName ) const;
+
+ /** retrieves a dialog
+ @param _rLibName
+ the library name where the module is located
+ @param _rDialogName
+ the dialog's name
+ @param _out_rDialogSource
+ takes the provider for the dialog's description, upon successful return
+ @return
+ <TRUE/> if and only if the dialog could be successfully retrieved, <FALSE/> otherwise
+ */
+ bool getDialog(
+ const OUString& _rLibName,
+ const OUString& _rDialogName,
+ css::uno::Reference< css::io::XInputStreamProvider >& _out_rDialogProvider
+ ) const;
+
+ /** renames a dialog
+ @param _rLibName
+ the library where the dialog lives in. Must denote an existing library.
+ @param _rOldName
+ the old dialog name. Must denote an existing dialog.
+ @param _rNewName
+ the new dialog name
+ @param _rxExistingDialogModel
+ the existing model of the dialog, if already loaded in the IDE
+ @return
+ <TRUE/> if and only if renaming was successful.
+ */
+ bool renameDialog(
+ const OUString& _rLibName,
+ const OUString& _rOldName,
+ const OUString& _rNewName,
+ const css::uno::Reference< css::container::XNameContainer >& _rxExistingDialogModel
+ ) const;
+
+ /** create a dialog
+ @param _rLibName
+ the library name where the module is located
+ @param _rDialogName
+ the dialog's name
+ @param _out_rDialogSource
+ takes the provider for the dialog's description, upon successful return
+ @return
+ <TRUE/> if and only if the dialog could be successfully retrieved, <FALSE/> otherwise
+ */
+ bool createDialog(
+ const OUString& _rLibName,
+ const OUString& _rDialogName,
+ css::uno::Reference< css::io::XInputStreamProvider >& _out_rDialogProvider
+ ) const;
+
+ /** inserts a given dialog into a given library
+
+ @param _rLibName
+ the name of the library to insert the dialog into. If a library with this name does
+ not yet exist, it will be created.
+ @param _rModName
+ the name of the dialog to insert. Must denote a name which is not yet
+ used in the dialog library.
+ @param _rDialogProvider
+ the provider of the dialog's description
+ @return
+ <TRUE/> if and only if the insertion was successful.
+ */
+ bool insertDialog(
+ const OUString& _rLibName,
+ const OUString& _rDialogName,
+ const css::uno::Reference< css::io::XInputStreamProvider >& _rDialogProvider
+ ) const;
+
+ /** determines whether the document is read-only
+
+ cannot be called if the document operates on the application-wide scripts
+ */
+ bool isReadOnly() const;
+
+ /** determines whether the ScriptDocument instance operates on the whole application,
+ as opposed to a real document
+ */
+ bool isApplication() const;
+
+ /** determines whether the ScriptDocument instance operates on a real document,
+ as opposed to the whole application
+ */
+ bool isDocument() const { return isValid() && !isApplication(); }
+
+ /** marks the document as modified
+ @precond
+ the instance operates on a real document, not on the application
+ @see isDocument
+ */
+ void setDocumentModified() const;
+
+ /** determines whether the document is modified
+ @precond
+ the instance operates on a real document, not on the application
+ @see isDocument
+ */
+ bool isDocumentModified() const;
+
+ /** saves the document, if the instance refers to a real document
+ @precond
+ <code>isApplication</code> returns <FALSE/>
+ */
+ void saveDocument(
+ const css::uno::Reference< css::task::XStatusIndicator >& _rxStatusIndicator
+ ) const;
+
+ /// returns the location of a library given by name
+ LibraryLocation
+ getLibraryLocation( const OUString& _rLibName ) const;
+
+ /// returns the title for the document
+ OUString getTitle( LibraryLocation _eLocation, LibraryType _eType = LibraryType::All ) const;
+
+ /** returns the title of the document
+
+ to be used for valid documents only
+ */
+ OUString getTitle() const;
+
+ /** determines whether the document is currently the one-and-only application-wide active document
+ */
+ bool isActive() const;
+
+ /** determines whether macro execution for this document is allowed
+
+ only to be called for real documents (->isDocument)
+ */
+ bool allowMacros() const;
+ };
+
+
+} // namespace basctl
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */