summaryrefslogtreecommitdiffstats
path: root/scripting
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /scripting
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rwxr-xr-xscripting/Format_java_code.sh2
-rw-r--r--scripting/IwyuFilter_scripting.yaml6
-rw-r--r--scripting/Jar_HelloWorld.mk22
-rw-r--r--scripting/Jar_Highlight.mk22
-rw-r--r--scripting/Jar_MemoryUsage.mk22
-rw-r--r--scripting/Jar_ScriptFramework.mk55
-rw-r--r--scripting/Jar_ScriptProviderForBeanShell.mk41
-rw-r--r--scripting/Jar_ScriptProviderForJava.mk31
-rw-r--r--scripting/Jar_ScriptProviderForJavaScript.mk37
-rw-r--r--scripting/Library_basprov.mk44
-rw-r--r--scripting/Library_dlgprov.mk49
-rw-r--r--scripting/Library_protocolhandler.mk42
-rw-r--r--scripting/Library_scriptframe.mk42
-rw-r--r--scripting/Library_stringresource.mk36
-rw-r--r--scripting/Library_vbaevents.mk42
-rw-r--r--scripting/Makefile14
-rw-r--r--scripting/Module_scripting.mk50
-rw-r--r--scripting/Package_ScriptsBeanShell.mk39
-rw-r--r--scripting/Package_ScriptsJavaScript.mk22
-rw-r--r--scripting/Package_ScriptsPython.mk21
-rw-r--r--scripting/Package_java.mk21
-rw-r--r--scripting/Package_java_jars.mk16
-rw-r--r--scripting/Package_scriptbindinglib.mk18
-rw-r--r--scripting/Package_scriptproviderforpython.mk15
-rw-r--r--scripting/Pyuno_mailmerge.mk19
-rw-r--r--scripting/README.md70
-rw-r--r--scripting/Rdb_scriptproviderforbeanshell.mk12
-rw-r--r--scripting/Rdb_scriptproviderforjavascript.mk12
-rw-r--r--scripting/astyle.options19
-rw-r--r--scripting/examples/basic/InsertColouredText.xba141
-rw-r--r--scripting/examples/basic/InsertColouredTextDialog.xdl34
-rw-r--r--scripting/examples/basic/SearchAndReplace.xba126
-rw-r--r--scripting/examples/basic/SearchAndReplaceDialog.xdl30
-rw-r--r--scripting/examples/basic/dialog.xlb6
-rw-r--r--scripting/examples/basic/script.xlb6
-rw-r--r--scripting/examples/beanshell/Calc/CopyRange.bsh39
-rw-r--r--scripting/examples/beanshell/Calc/FixView.bsh34
-rw-r--r--scripting/examples/beanshell/Calc/InsertSheet.bsh25
-rw-r--r--scripting/examples/beanshell/Calc/ProtectSheet.bsh30
-rw-r--r--scripting/examples/beanshell/Calc/SelectCell.bsh30
-rw-r--r--scripting/examples/beanshell/Calc/parcel-descriptor.xml2
-rw-r--r--scripting/examples/beanshell/Capitalise/capitalise.bsh111
-rw-r--r--scripting/examples/beanshell/Capitalise/parcel-descriptor.xml32
-rw-r--r--scripting/examples/beanshell/HelloWorld/helloworld.bsh34
-rw-r--r--scripting/examples/beanshell/HelloWorld/parcel-descriptor.xml32
-rw-r--r--scripting/examples/beanshell/Highlight/ButtonPressHandler.bsh123
-rw-r--r--scripting/examples/beanshell/Highlight/ShowDialog.bsh140
-rw-r--r--scripting/examples/beanshell/Highlight/highlighter.bsh166
-rw-r--r--scripting/examples/beanshell/Highlight/parcel-descriptor.xml41
-rw-r--r--scripting/examples/beanshell/InteractiveBeanShell/interactive.bsh21
-rw-r--r--scripting/examples/beanshell/InteractiveBeanShell/parcel-descriptor.xml32
-rw-r--r--scripting/examples/beanshell/MemoryUsage/memusage.bsh137
-rw-r--r--scripting/examples/beanshell/MemoryUsage/parcel-descriptor.xml32
-rw-r--r--scripting/examples/beanshell/WordCount/parcel-descriptor.xml32
-rw-r--r--scripting/examples/beanshell/WordCount/wordcount.bsh82
-rw-r--r--scripting/examples/beanshell/Writer/ChangeFont.bsh36
-rw-r--r--scripting/examples/beanshell/Writer/ChangeParaAdjust.bsh37
-rw-r--r--scripting/examples/beanshell/Writer/InsertTable.bsh32
-rw-r--r--scripting/examples/beanshell/Writer/InsertText.bsh28
-rw-r--r--scripting/examples/beanshell/Writer/SetText.bsh21
-rw-r--r--scripting/examples/beanshell/Writer/parcel-descriptor.xml2
-rw-r--r--scripting/examples/java/HelloWorld/HelloWorld.java42
-rw-r--r--scripting/examples/java/HelloWorld/parcel-descriptor.xml33
-rw-r--r--scripting/examples/java/Highlight/HighlightText.java233
-rw-r--r--scripting/examples/java/Highlight/parcel-descriptor.xml33
-rw-r--r--scripting/examples/java/MemoryUsage/MemoryUsage.java157
-rw-r--r--scripting/examples/java/MemoryUsage/parcel-descriptor.xml33
-rw-r--r--scripting/examples/java/Newsgroup/MimeConfiguration.java211
-rw-r--r--scripting/examples/java/Newsgroup/NewsGroup.java39
-rw-r--r--scripting/examples/java/Newsgroup/OfficeAttachment.java250
-rw-r--r--scripting/examples/java/Newsgroup/PostNewsgroup.java633
-rw-r--r--scripting/examples/java/Newsgroup/Sender.java141
-rw-r--r--scripting/examples/java/Newsgroup/StatusWindow.java147
-rw-r--r--scripting/examples/java/Newsgroup/SubscribedNewsgroups.java349
-rw-r--r--scripting/examples/java/debugger/DebugRunner.java87
-rw-r--r--scripting/examples/java/debugger/OOBeanShellDebugger.java393
-rw-r--r--scripting/examples/java/debugger/OORhinoDebugger.java97
-rw-r--r--scripting/examples/java/debugger/OOScriptDebugger.java27
-rw-r--r--scripting/examples/java/debugger/parcel-descriptor.xml34
-rw-r--r--scripting/examples/java/selector/ScriptSelector.java488
-rw-r--r--scripting/examples/java/selector/container.gifbin0 -> 164 bytes
-rw-r--r--scripting/examples/java/selector/parcel-descriptor.xml33
-rw-r--r--scripting/examples/java/selector/script.gifbin0 -> 187 bytes
-rw-r--r--scripting/examples/java/selector/soffice.gifbin0 -> 136 bytes
-rw-r--r--scripting/examples/javascript/ExportSheetsToHTML/exportsheetstohtml.js88
-rw-r--r--scripting/examples/javascript/ExportSheetsToHTML/parcel-descriptor.xml32
-rw-r--r--scripting/examples/javascript/HelloWorld/helloworld.js33
-rw-r--r--scripting/examples/javascript/HelloWorld/parcel-descriptor.xml32
-rw-r--r--scripting/examples/javascript/Highlight/ButtonPressHandler.js122
-rw-r--r--scripting/examples/javascript/Highlight/ShowDialog.js131
-rw-r--r--scripting/examples/javascript/Highlight/parcel-descriptor.xml41
-rw-r--r--scripting/examples/python/Capitalise.py96
-rw-r--r--scripting/examples/python/HelloWorld.py47
-rw-r--r--scripting/examples/python/InsertText.py65
-rw-r--r--scripting/examples/python/NamedRanges.py134
-rw-r--r--scripting/examples/python/SetCellColor.py53
-rw-r--r--scripting/examples/python/TableSample.py131
-rw-r--r--scripting/java/Framework/MANIFEST.MF2
-rw-r--r--scripting/java/Framework/com/sun/star/script/framework/security/SecurityDialog.java583
-rw-r--r--scripting/java/ScriptFramework.component25
-rw-r--r--scripting/java/ScriptProviderForBeanShell.component28
-rw-r--r--scripting/java/ScriptProviderForJava.component28
-rw-r--r--scripting/java/ScriptProviderForJavaScript.component28
-rw-r--r--scripting/java/com/sun/star/script/framework/browse/DialogFactory.java255
-rw-r--r--scripting/java/com/sun/star/script/framework/browse/ParcelBrowseNode.java309
-rw-r--r--scripting/java/com/sun/star/script/framework/browse/PkgProviderBrowseNode.java49
-rw-r--r--scripting/java/com/sun/star/script/framework/browse/ProviderBrowseNode.java264
-rw-r--r--scripting/java/com/sun/star/script/framework/browse/ScriptBrowseNode.java300
-rw-r--r--scripting/java/com/sun/star/script/framework/container/DeployedUnoPackagesDB.java192
-rw-r--r--scripting/java/com/sun/star/script/framework/container/Parcel.java302
-rw-r--r--scripting/java/com/sun/star/script/framework/container/ParcelContainer.java725
-rw-r--r--scripting/java/com/sun/star/script/framework/container/ParcelDescriptor.java354
-rw-r--r--scripting/java/com/sun/star/script/framework/container/ParsedScriptUri.java25
-rw-r--r--scripting/java/com/sun/star/script/framework/container/ScriptEntry.java85
-rw-r--r--scripting/java/com/sun/star/script/framework/container/ScriptMetaData.java328
-rw-r--r--scripting/java/com/sun/star/script/framework/container/UnoPkgContainer.java401
-rw-r--r--scripting/java/com/sun/star/script/framework/container/XMLParser.java30
-rw-r--r--scripting/java/com/sun/star/script/framework/container/XMLParserFactory.java106
-rw-r--r--scripting/java/com/sun/star/script/framework/io/UCBStreamHandler.java275
-rw-r--r--scripting/java/com/sun/star/script/framework/io/XInputStreamImpl.java109
-rw-r--r--scripting/java/com/sun/star/script/framework/io/XInputStreamWrapper.java100
-rw-r--r--scripting/java/com/sun/star/script/framework/io/XOutputStreamWrapper.java113
-rw-r--r--scripting/java/com/sun/star/script/framework/io/XStorageHelper.java249
-rw-r--r--scripting/java/com/sun/star/script/framework/log/LogUtils.java57
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/ClassLoaderFactory.java55
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/EditorScriptContext.java79
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/PathUtils.java83
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/ScriptContext.java143
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/ScriptEditor.java30
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/ScriptEditorBase.java73
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/ScriptProvider.java673
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/SwingInvocation.java39
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/beanshell/MANIFEST.MF2
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/beanshell/PlainSourceView.java395
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptEditorForBeanShell.java400
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptProviderForBeanShell.java367
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptSourceModel.java125
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptSourceView.java29
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/beanshell/UnsavedChangesListener.java13
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/beanshell/template.bsh65
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/java/MANIFEST.MF2
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/java/Resolver.java36
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/java/ScriptDescriptor.java165
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/java/ScriptProviderForJava.java307
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/java/ScriptProxy.java69
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/java/StrictResolver.java113
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/javascript/MANIFEST.MF2
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/javascript/ScriptEditorForJavaScript.java319
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/javascript/ScriptProviderForJavaScript.java330
-rw-r--r--scripting/java/com/sun/star/script/framework/provider/javascript/template.js54
-rw-r--r--scripting/source/basprov/baslibnode.cxx130
-rw-r--r--scripting/source/basprov/baslibnode.hxx70
-rw-r--r--scripting/source/basprov/basmethnode.cxx291
-rw-r--r--scripting/source/basprov/basmethnode.hxx108
-rw-r--r--scripting/source/basprov/basmodnode.cxx134
-rw-r--r--scripting/source/basprov/basmodnode.hxx64
-rw-r--r--scripting/source/basprov/basprov.component29
-rw-r--r--scripting/source/basprov/basprov.cxx477
-rw-r--r--scripting/source/basprov/basprov.hxx97
-rw-r--r--scripting/source/basprov/basscript.cxx314
-rw-r--r--scripting/source/basprov/basscript.hxx103
-rw-r--r--scripting/source/dlgprov/DialogModelProvider.cxx166
-rw-r--r--scripting/source/dlgprov/DialogModelProvider.hxx87
-rw-r--r--scripting/source/dlgprov/dlgevtatt.cxx658
-rw-r--r--scripting/source/dlgprov/dlgevtatt.hxx130
-rw-r--r--scripting/source/dlgprov/dlgprov.component32
-rw-r--r--scripting/source/dlgprov/dlgprov.cxx702
-rw-r--r--scripting/source/dlgprov/dlgprov.hxx148
-rw-r--r--scripting/source/inc/bcholder.hxx44
-rw-r--r--scripting/source/inc/util/MiscUtils.hxx138
-rw-r--r--scripting/source/protocolhandler/protocolhandler.component26
-rw-r--r--scripting/source/protocolhandler/scripthandler.cxx436
-rw-r--r--scripting/source/protocolhandler/scripthandler.hxx114
-rw-r--r--scripting/source/provider/ActiveMSPList.cxx297
-rw-r--r--scripting/source/provider/ActiveMSPList.hxx94
-rw-r--r--scripting/source/provider/BrowseNodeFactoryImpl.cxx650
-rw-r--r--scripting/source/provider/BrowseNodeFactoryImpl.hxx70
-rw-r--r--scripting/source/provider/MasterScriptProvider.cxx676
-rw-r--r--scripting/source/provider/MasterScriptProvider.hxx131
-rw-r--r--scripting/source/provider/MasterScriptProviderFactory.cxx85
-rw-r--r--scripting/source/provider/MasterScriptProviderFactory.hxx74
-rw-r--r--scripting/source/provider/ProviderCache.cxx203
-rw-r--r--scripting/source/provider/ProviderCache.hxx80
-rw-r--r--scripting/source/provider/URIHelper.cxx256
-rw-r--r--scripting/source/provider/URIHelper.hxx87
-rw-r--r--scripting/source/pyprov/mailmerge.README18
-rw-r--r--scripting/source/pyprov/mailmerge.component28
-rw-r--r--scripting/source/pyprov/mailmerge.py503
-rw-r--r--scripting/source/pyprov/msgbox.py241
-rw-r--r--scripting/source/pyprov/pythonscript.py1145
-rw-r--r--scripting/source/pyprov/scriptproviderforpython.rdb28
-rw-r--r--scripting/source/stringresource/stringresource.component34
-rw-r--r--scripting/source/stringresource/stringresource.cxx2598
-rw-r--r--scripting/source/stringresource/stringresource.hxx485
-rw-r--r--scripting/source/vbaevents/eventhelper.cxx982
-rw-r--r--scripting/source/vbaevents/vbaevents.component30
-rw-r--r--scripting/util/scriptframe.component42
-rw-r--r--scripting/workben/bindings/Highlight.xdl31
-rw-r--r--scripting/workben/bindings/dialog.xlb6
-rw-r--r--scripting/workben/bindings/script.xlb4
200 files changed, 29646 insertions, 0 deletions
diff --git a/scripting/Format_java_code.sh b/scripting/Format_java_code.sh
new file mode 100755
index 000000000..bb8e40dd2
--- /dev/null
+++ b/scripting/Format_java_code.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+astyle --options=astyle.options --verbose --recursive ./*.java
diff --git a/scripting/IwyuFilter_scripting.yaml b/scripting/IwyuFilter_scripting.yaml
new file mode 100644
index 000000000..18b80ff99
--- /dev/null
+++ b/scripting/IwyuFilter_scripting.yaml
@@ -0,0 +1,6 @@
+---
+assumeFilename: scripting/source/stringresource/stringresource.cxx
+excludelist:
+ scripting/source/protocolhandler/scripthandler.cxx:
+ # Actually used
+ - com/sun/star/lang/XSingleServiceFactory.hpp
diff --git a/scripting/Jar_HelloWorld.mk b/scripting/Jar_HelloWorld.mk
new file mode 100644
index 000000000..1a44592e1
--- /dev/null
+++ b/scripting/Jar_HelloWorld.mk
@@ -0,0 +1,22 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Jar_Jar,HelloWorld))
+
+$(eval $(call gb_Jar_use_jars,HelloWorld,\
+ libreoffice \
+))
+
+$(eval $(call gb_Jar_add_sourcefiles,HelloWorld,\
+ scripting/examples/java/HelloWorld/HelloWorld \
+))
+
+$(eval $(call gb_Jar_set_packageroot,HelloWorld,org))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Jar_Highlight.mk b/scripting/Jar_Highlight.mk
new file mode 100644
index 000000000..fb756cc8b
--- /dev/null
+++ b/scripting/Jar_Highlight.mk
@@ -0,0 +1,22 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Jar_Jar,Highlight))
+
+$(eval $(call gb_Jar_use_jars,Highlight,\
+ libreoffice \
+))
+
+$(eval $(call gb_Jar_add_sourcefiles,Highlight,\
+ scripting/examples/java/Highlight/HighlightText \
+))
+
+$(eval $(call gb_Jar_set_packageroot,Highlight,org))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Jar_MemoryUsage.mk b/scripting/Jar_MemoryUsage.mk
new file mode 100644
index 000000000..8f917d360
--- /dev/null
+++ b/scripting/Jar_MemoryUsage.mk
@@ -0,0 +1,22 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Jar_Jar,MemoryUsage))
+
+$(eval $(call gb_Jar_use_jars,MemoryUsage,\
+ libreoffice \
+))
+
+$(eval $(call gb_Jar_add_sourcefiles,MemoryUsage,\
+ scripting/examples/java/MemoryUsage/MemoryUsage \
+))
+
+$(eval $(call gb_Jar_set_packageroot,MemoryUsage,org))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Jar_ScriptFramework.mk b/scripting/Jar_ScriptFramework.mk
new file mode 100644
index 000000000..5c3b20776
--- /dev/null
+++ b/scripting/Jar_ScriptFramework.mk
@@ -0,0 +1,55 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Jar_Jar,ScriptFramework))
+
+$(eval $(call gb_Jar_use_jars,ScriptFramework,\
+ libreoffice \
+))
+
+$(eval $(call gb_Jar_set_componentfile,ScriptFramework,scripting/java/ScriptFramework,OOO,services))
+
+$(eval $(call gb_Jar_set_manifest,ScriptFramework,$(SRCDIR)/scripting/java/Framework/MANIFEST.MF))
+
+$(eval $(call gb_Jar_set_packageroot,ScriptFramework,com))
+
+$(eval $(call gb_Jar_add_sourcefiles,ScriptFramework,\
+ scripting/java/com/sun/star/script/framework/browse/DialogFactory \
+ scripting/java/com/sun/star/script/framework/browse/ParcelBrowseNode \
+ scripting/java/com/sun/star/script/framework/browse/PkgProviderBrowseNode \
+ scripting/java/com/sun/star/script/framework/browse/ProviderBrowseNode \
+ scripting/java/com/sun/star/script/framework/browse/ScriptBrowseNode \
+ scripting/java/com/sun/star/script/framework/container/DeployedUnoPackagesDB \
+ scripting/java/com/sun/star/script/framework/container/ParcelContainer \
+ scripting/java/com/sun/star/script/framework/container/ParcelDescriptor \
+ scripting/java/com/sun/star/script/framework/container/Parcel \
+ scripting/java/com/sun/star/script/framework/container/ParsedScriptUri \
+ scripting/java/com/sun/star/script/framework/container/ScriptEntry \
+ scripting/java/com/sun/star/script/framework/container/ScriptMetaData \
+ scripting/java/com/sun/star/script/framework/container/UnoPkgContainer \
+ scripting/java/com/sun/star/script/framework/container/XMLParserFactory \
+ scripting/java/com/sun/star/script/framework/container/XMLParser \
+ scripting/java/com/sun/star/script/framework/io/UCBStreamHandler \
+ scripting/java/com/sun/star/script/framework/io/XInputStreamImpl \
+ scripting/java/com/sun/star/script/framework/io/XInputStreamWrapper \
+ scripting/java/com/sun/star/script/framework/io/XOutputStreamWrapper \
+ scripting/java/com/sun/star/script/framework/io/XStorageHelper \
+ scripting/java/com/sun/star/script/framework/log/LogUtils \
+ scripting/java/com/sun/star/script/framework/provider/ClassLoaderFactory \
+ scripting/java/com/sun/star/script/framework/provider/EditorScriptContext \
+ scripting/java/com/sun/star/script/framework/provider/PathUtils \
+ scripting/java/com/sun/star/script/framework/provider/ScriptContext \
+ scripting/java/com/sun/star/script/framework/provider/ScriptEditor \
+ scripting/java/com/sun/star/script/framework/provider/ScriptEditorBase \
+ scripting/java/com/sun/star/script/framework/provider/ScriptProvider \
+ scripting/java/com/sun/star/script/framework/provider/SwingInvocation \
+ scripting/java/Framework/com/sun/star/script/framework/security/SecurityDialog \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Jar_ScriptProviderForBeanShell.mk b/scripting/Jar_ScriptProviderForBeanShell.mk
new file mode 100644
index 000000000..0d1535d07
--- /dev/null
+++ b/scripting/Jar_ScriptProviderForBeanShell.mk
@@ -0,0 +1,41 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Jar_Jar,ScriptProviderForBeanShell))
+
+$(eval $(call gb_Jar_use_jars,ScriptProviderForBeanShell,\
+ libreoffice \
+ ScriptFramework \
+))
+
+$(eval $(call gb_Jar_use_externals,ScriptProviderForBeanShell,\
+ bsh \
+))
+
+$(eval $(call gb_Jar_set_manifest,ScriptProviderForBeanShell,$(SRCDIR)/scripting/java/com/sun/star/script/framework/provider/beanshell/MANIFEST.MF))
+
+$(eval $(call gb_Jar_set_componentfile,ScriptProviderForBeanShell,scripting/java/ScriptProviderForBeanShell,OOO,scriptproviderforbeanshell))
+
+$(eval $(call gb_Jar_set_packageroot,ScriptProviderForBeanShell,com))
+
+$(eval $(call gb_Jar_add_sourcefiles,ScriptProviderForBeanShell,\
+ scripting/java/com/sun/star/script/framework/provider/beanshell/PlainSourceView \
+ scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptEditorForBeanShell \
+ scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptProviderForBeanShell \
+ scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptSourceModel \
+ scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptSourceView \
+ scripting/java/com/sun/star/script/framework/provider/beanshell/UnsavedChangesListener \
+))
+
+$(eval $(call gb_Jar_add_packagefile,ScriptProviderForBeanShell,\
+ com/sun/star/script/framework/provider/beanshell/template.bsh,\
+ $(SRCDIR)/scripting/java/com/sun/star/script/framework/provider/beanshell/template.bsh \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Jar_ScriptProviderForJava.mk b/scripting/Jar_ScriptProviderForJava.mk
new file mode 100644
index 000000000..d87310d9c
--- /dev/null
+++ b/scripting/Jar_ScriptProviderForJava.mk
@@ -0,0 +1,31 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Jar_Jar,ScriptProviderForJava))
+
+$(eval $(call gb_Jar_use_jars,ScriptProviderForJava,\
+ libreoffice \
+ ScriptFramework \
+))
+
+$(eval $(call gb_Jar_set_componentfile,ScriptProviderForJava,scripting/java/ScriptProviderForJava,OOO,services))
+
+$(eval $(call gb_Jar_set_manifest,ScriptProviderForJava,$(SRCDIR)/scripting/java/com/sun/star/script/framework/provider/java/MANIFEST.MF))
+
+$(eval $(call gb_Jar_set_packageroot,ScriptProviderForJava,com))
+
+$(eval $(call gb_Jar_add_sourcefiles,ScriptProviderForJava,\
+ scripting/java/com/sun/star/script/framework/provider/java/Resolver \
+ scripting/java/com/sun/star/script/framework/provider/java/ScriptDescriptor \
+ scripting/java/com/sun/star/script/framework/provider/java/ScriptProviderForJava \
+ scripting/java/com/sun/star/script/framework/provider/java/ScriptProxy \
+ scripting/java/com/sun/star/script/framework/provider/java/StrictResolver \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Jar_ScriptProviderForJavaScript.mk b/scripting/Jar_ScriptProviderForJavaScript.mk
new file mode 100644
index 000000000..0366016bb
--- /dev/null
+++ b/scripting/Jar_ScriptProviderForJavaScript.mk
@@ -0,0 +1,37 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Jar_Jar,ScriptProviderForJavaScript))
+
+$(eval $(call gb_Jar_use_jars,ScriptProviderForJavaScript,\
+ libreoffice \
+ ScriptFramework \
+))
+
+$(eval $(call gb_Jar_use_externals,ScriptProviderForJavaScript,\
+ rhino \
+))
+
+$(eval $(call gb_Jar_set_manifest,ScriptProviderForJavaScript,$(SRCDIR)/scripting/java/com/sun/star/script/framework/provider/javascript/MANIFEST.MF))
+
+$(eval $(call gb_Jar_set_componentfile,ScriptProviderForJavaScript,scripting/java/ScriptProviderForJavaScript,OOO,scriptproviderforjavascript))
+
+$(eval $(call gb_Jar_set_packageroot,ScriptProviderForJavaScript,com))
+
+$(eval $(call gb_Jar_add_sourcefiles,ScriptProviderForJavaScript,\
+ scripting/java/com/sun/star/script/framework/provider/javascript/ScriptEditorForJavaScript \
+ scripting/java/com/sun/star/script/framework/provider/javascript/ScriptProviderForJavaScript \
+))
+
+$(eval $(call gb_Jar_add_packagefile,ScriptProviderForJavaScript,\
+ com/sun/star/script/framework/provider/javascript/template.js,\
+ $(SRCDIR)/scripting/java/com/sun/star/script/framework/provider/javascript/template.js \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Library_basprov.mk b/scripting/Library_basprov.mk
new file mode 100644
index 000000000..417068001
--- /dev/null
+++ b/scripting/Library_basprov.mk
@@ -0,0 +1,44 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Library_Library,basprov))
+
+$(eval $(call gb_Library_set_componentfile,basprov,scripting/source/basprov/basprov,services))
+
+$(eval $(call gb_Library_set_include,basprov,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/scripting/source/inc \
+))
+
+$(eval $(call gb_Library_use_external,basprov,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,basprov))
+
+$(eval $(call gb_Library_use_libraries,basprov,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ sal \
+ sb \
+ sfx \
+ svl \
+ tl \
+ ucbhelper \
+ vcl \
+))
+
+$(eval $(call gb_Library_add_exception_objects,basprov,\
+ scripting/source/basprov/baslibnode \
+ scripting/source/basprov/basmethnode \
+ scripting/source/basprov/basmodnode \
+ scripting/source/basprov/basprov \
+ scripting/source/basprov/basscript \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Library_dlgprov.mk b/scripting/Library_dlgprov.mk
new file mode 100644
index 000000000..5f53a9f30
--- /dev/null
+++ b/scripting/Library_dlgprov.mk
@@ -0,0 +1,49 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Library_Library,dlgprov))
+
+$(eval $(call gb_Library_set_componentfile,dlgprov,scripting/source/dlgprov/dlgprov,services))
+
+$(eval $(call gb_Library_set_include,dlgprov,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/scripting/source/inc \
+))
+
+$(eval $(call gb_Library_use_external,dlgprov,boost_headers))
+
+$(eval $(call gb_Library_use_api,dlgprov,\
+ offapi \
+ oovbaapi \
+ udkapi \
+))
+
+$(eval $(call gb_Library_use_libraries,dlgprov,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ sal \
+ i18nlangtag \
+ sb \
+ sfx \
+ tl \
+ ucbhelper \
+ utl \
+ vbahelper \
+ vcl \
+ xmlscript \
+))
+
+$(eval $(call gb_Library_add_exception_objects,dlgprov,\
+ scripting/source/dlgprov/DialogModelProvider \
+ scripting/source/dlgprov/dlgevtatt \
+ scripting/source/dlgprov/dlgprov \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Library_protocolhandler.mk b/scripting/Library_protocolhandler.mk
new file mode 100644
index 000000000..31599c3d8
--- /dev/null
+++ b/scripting/Library_protocolhandler.mk
@@ -0,0 +1,42 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Library_Library,protocolhandler))
+
+$(eval $(call gb_Library_set_componentfile,protocolhandler,scripting/source/protocolhandler/protocolhandler,services))
+
+$(eval $(call gb_Library_set_include,protocolhandler,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/scripting/source/inc \
+))
+
+$(eval $(call gb_Library_use_external,protocolhandler,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,protocolhandler))
+
+$(eval $(call gb_Library_use_custom_headers,protocolhandler,\
+ officecfg/registry \
+))
+
+$(eval $(call gb_Library_use_libraries,protocolhandler,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ fwk \
+ sal \
+ sfx \
+ tl \
+ vcl \
+))
+
+$(eval $(call gb_Library_add_exception_objects,protocolhandler,\
+ scripting/source/protocolhandler/scripthandler \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Library_scriptframe.mk b/scripting/Library_scriptframe.mk
new file mode 100644
index 000000000..2cf22376e
--- /dev/null
+++ b/scripting/Library_scriptframe.mk
@@ -0,0 +1,42 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Library_Library,scriptframe))
+
+$(eval $(call gb_Library_set_componentfile,scriptframe,scripting/util/scriptframe,services))
+
+$(eval $(call gb_Library_set_include,scriptframe,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/scripting/source/inc \
+))
+
+$(eval $(call gb_Library_use_external,scriptframe,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,scriptframe))
+
+$(eval $(call gb_Library_use_libraries,scriptframe,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ sal \
+ tl \
+ ucbhelper \
+ utl \
+))
+
+$(eval $(call gb_Library_add_exception_objects,scriptframe,\
+ scripting/source/provider/ActiveMSPList \
+ scripting/source/provider/BrowseNodeFactoryImpl \
+ scripting/source/provider/MasterScriptProvider \
+ scripting/source/provider/MasterScriptProviderFactory \
+ scripting/source/provider/ProviderCache \
+ scripting/source/provider/URIHelper \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Library_stringresource.mk b/scripting/Library_stringresource.mk
new file mode 100644
index 000000000..fa9055421
--- /dev/null
+++ b/scripting/Library_stringresource.mk
@@ -0,0 +1,36 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Library_Library,stringresource))
+
+$(eval $(call gb_Library_set_componentfile,stringresource,scripting/source/stringresource/stringresource,services))
+
+$(eval $(call gb_Library_set_include,stringresource,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/scripting/source/inc \
+))
+
+$(eval $(call gb_Library_use_external,stringresource,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,stringresource))
+
+$(eval $(call gb_Library_use_libraries,stringresource,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ sal \
+ tl \
+ i18nlangtag \
+))
+
+$(eval $(call gb_Library_add_exception_objects,stringresource,\
+ scripting/source/stringresource/stringresource \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Library_vbaevents.mk b/scripting/Library_vbaevents.mk
new file mode 100644
index 000000000..2990a892a
--- /dev/null
+++ b/scripting/Library_vbaevents.mk
@@ -0,0 +1,42 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Library_Library,vbaevents))
+
+$(eval $(call gb_Library_set_componentfile,vbaevents,scripting/source/vbaevents/vbaevents,services))
+
+$(eval $(call gb_Library_set_include,vbaevents,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/scripting/source/inc \
+))
+
+$(eval $(call gb_Library_use_external,vbaevents,boost_headers))
+
+$(eval $(call gb_Library_use_api,vbaevents,\
+ offapi \
+ oovbaapi \
+ udkapi \
+))
+
+$(eval $(call gb_Library_use_libraries,vbaevents,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ msfilter \
+ sal \
+ sfx \
+ sb \
+ tl \
+))
+
+$(eval $(call gb_Library_add_exception_objects,vbaevents,\
+ scripting/source/vbaevents/eventhelper \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Makefile b/scripting/Makefile
new file mode 100644
index 000000000..0997e6284
--- /dev/null
+++ b/scripting/Makefile
@@ -0,0 +1,14 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST))))
+
+include $(module_directory)/../solenv/gbuild/partial_build.mk
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Module_scripting.mk b/scripting/Module_scripting.mk
new file mode 100644
index 000000000..1d974e8e7
--- /dev/null
+++ b/scripting/Module_scripting.mk
@@ -0,0 +1,50 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Module_Module,scripting))
+
+ifneq ($(filter SCRIPTING,$(BUILD_TYPE)),)
+
+$(eval $(call gb_Module_add_targets,scripting,\
+ $(if $(ENABLE_JAVA),\
+ Jar_HelloWorld \
+ Jar_Highlight \
+ Jar_MemoryUsage \
+ Jar_ScriptFramework \
+ $(if $(ENABLE_SCRIPTING_BEANSHELL),\
+ Jar_ScriptProviderForBeanShell \
+ Rdb_scriptproviderforbeanshell \
+ ) \
+ Jar_ScriptProviderForJava \
+ $(if $(ENABLE_SCRIPTING_JAVASCRIPT),\
+ Jar_ScriptProviderForJavaScript \
+ Rdb_scriptproviderforjavascript \
+ ) \
+ Package_java \
+ Package_java_jars \
+ $(if $(ENABLE_SCRIPTING_BEANSHELL),Package_ScriptsBeanShell) \
+ $(if $(ENABLE_SCRIPTING_JAVASCRIPT),Package_ScriptsJavaScript) \
+ ) \
+ Package_scriptbindinglib \
+ $(if $(DISABLE_PYTHON),,\
+ Package_scriptproviderforpython \
+ Package_ScriptsPython \
+ Pyuno_mailmerge \
+ ) \
+ Library_basprov \
+ Library_dlgprov \
+ Library_protocolhandler \
+ Library_scriptframe \
+ Library_stringresource \
+ Library_vbaevents \
+))
+
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Package_ScriptsBeanShell.mk b/scripting/Package_ScriptsBeanShell.mk
new file mode 100644
index 000000000..5b7cf42d3
--- /dev/null
+++ b/scripting/Package_ScriptsBeanShell.mk
@@ -0,0 +1,39 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Package_Package,scripting_ScriptsBeanShell,$(SRCDIR)/scripting/examples))
+
+$(eval $(call gb_Package_add_files_with_dir,scripting_ScriptsBeanShell,$(LIBO_SHARE_FOLDER)/Scripts,\
+ beanshell/Calc/CopyRange.bsh \
+ beanshell/Calc/FixView.bsh \
+ beanshell/Calc/InsertSheet.bsh \
+ beanshell/Calc/parcel-descriptor.xml \
+ beanshell/Calc/ProtectSheet.bsh \
+ beanshell/Calc/SelectCell.bsh \
+ beanshell/Capitalise/capitalise.bsh \
+ beanshell/Capitalise/parcel-descriptor.xml \
+ beanshell/HelloWorld/helloworld.bsh \
+ beanshell/HelloWorld/parcel-descriptor.xml \
+ beanshell/Highlight/ButtonPressHandler.bsh \
+ beanshell/Highlight/highlighter.bsh \
+ beanshell/Highlight/parcel-descriptor.xml \
+ beanshell/Highlight/ShowDialog.bsh \
+ beanshell/MemoryUsage/memusage.bsh \
+ beanshell/MemoryUsage/parcel-descriptor.xml \
+ beanshell/WordCount/parcel-descriptor.xml \
+ beanshell/WordCount/wordcount.bsh \
+ beanshell/Writer/ChangeFont.bsh \
+ beanshell/Writer/ChangeParaAdjust.bsh \
+ beanshell/Writer/InsertTable.bsh \
+ beanshell/Writer/InsertText.bsh \
+ beanshell/Writer/parcel-descriptor.xml \
+ beanshell/Writer/SetText.bsh \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Package_ScriptsJavaScript.mk b/scripting/Package_ScriptsJavaScript.mk
new file mode 100644
index 000000000..df6ee2a25
--- /dev/null
+++ b/scripting/Package_ScriptsJavaScript.mk
@@ -0,0 +1,22 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Package_Package,scripting_ScriptsJavaScript,$(SRCDIR)/scripting/examples))
+
+$(eval $(call gb_Package_add_files_with_dir,scripting_ScriptsJavaScript,$(LIBO_SHARE_FOLDER)/Scripts,\
+ javascript/ExportSheetsToHTML/exportsheetstohtml.js \
+ javascript/ExportSheetsToHTML/parcel-descriptor.xml \
+ javascript/HelloWorld/helloworld.js \
+ javascript/HelloWorld/parcel-descriptor.xml \
+ javascript/Highlight/ButtonPressHandler.js \
+ javascript/Highlight/parcel-descriptor.xml \
+ javascript/Highlight/ShowDialog.js \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Package_ScriptsPython.mk b/scripting/Package_ScriptsPython.mk
new file mode 100644
index 000000000..9d401d383
--- /dev/null
+++ b/scripting/Package_ScriptsPython.mk
@@ -0,0 +1,21 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Package_Package,scripting_ScriptsPython,$(SRCDIR)/scripting/examples))
+
+$(eval $(call gb_Package_add_files_with_dir,scripting_ScriptsPython,$(LIBO_SHARE_FOLDER)/Scripts,\
+ python/Capitalise.py \
+ python/HelloWorld.py \
+ python/InsertText.py \
+ python/NamedRanges.py \
+ python/SetCellColor.py \
+ python/TableSample.py \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Package_java.mk b/scripting/Package_java.mk
new file mode 100644
index 000000000..bbaa6e2b7
--- /dev/null
+++ b/scripting/Package_java.mk
@@ -0,0 +1,21 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Package_Package,scripting_java,$(SRCDIR)/scripting/examples/java))
+
+$(eval $(call gb_Package_add_files_with_dir,scripting_java,$(LIBO_SHARE_FOLDER)/Scripts/java,\
+ HelloWorld/HelloWorld.java \
+ HelloWorld/parcel-descriptor.xml \
+ Highlight/HighlightText.java \
+ Highlight/parcel-descriptor.xml \
+ MemoryUsage/MemoryUsage.java \
+ MemoryUsage/parcel-descriptor.xml \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Package_java_jars.mk b/scripting/Package_java_jars.mk
new file mode 100644
index 000000000..13ba07e8c
--- /dev/null
+++ b/scripting/Package_java_jars.mk
@@ -0,0 +1,16 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Package_Package,scripting_java_jars,$(WORKDIR)/Jar))
+
+$(eval $(call gb_Package_add_file,scripting_java_jars,$(LIBO_SHARE_FOLDER)/Scripts/java/HelloWorld/HelloWorld.jar,HelloWorld.jar))
+$(eval $(call gb_Package_add_file,scripting_java_jars,$(LIBO_SHARE_FOLDER)/Scripts/java/Highlight/Highlight.jar,Highlight.jar))
+$(eval $(call gb_Package_add_file,scripting_java_jars,$(LIBO_SHARE_FOLDER)/Scripts/java/MemoryUsage/MemoryUsage.jar,MemoryUsage.jar))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Package_scriptbindinglib.mk b/scripting/Package_scriptbindinglib.mk
new file mode 100644
index 000000000..54ecbb2cc
--- /dev/null
+++ b/scripting/Package_scriptbindinglib.mk
@@ -0,0 +1,18 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Package_Package,scripting_scriptbindinglib,$(SRCDIR)/scripting/workben/bindings))
+
+$(eval $(call gb_Package_add_files,scripting_scriptbindinglib,$(LIBO_SHARE_FOLDER)/basic/ScriptBindingLibrary,\
+ Highlight.xdl \
+ dialog.xlb \
+ script.xlb \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Package_scriptproviderforpython.mk b/scripting/Package_scriptproviderforpython.mk
new file mode 100644
index 000000000..7e2143998
--- /dev/null
+++ b/scripting/Package_scriptproviderforpython.mk
@@ -0,0 +1,15 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Package_Package,scripting_scriptproviderforpython,$(SRCDIR)/scripting/source/pyprov))
+
+$(eval $(call gb_Package_add_file,scripting_scriptproviderforpython,$(LIBO_ETC_FOLDER)/services/scriptproviderforpython.rdb,scriptproviderforpython.rdb))
+$(eval $(call gb_Package_add_file,scripting_scriptproviderforpython,$(LIBO_LIB_PYUNO_FOLDER)/pythonscript.py,pythonscript.py))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Pyuno_mailmerge.mk b/scripting/Pyuno_mailmerge.mk
new file mode 100644
index 000000000..f5cce752c
--- /dev/null
+++ b/scripting/Pyuno_mailmerge.mk
@@ -0,0 +1,19 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Pyuno_Pyuno,mailmerge,$(SRCDIR)/scripting/source/pyprov))
+
+$(eval $(call gb_Pyuno_set_componentfile,mailmerge,scripting/source/pyprov/mailmerge,services))
+
+$(eval $(call gb_Pyuno_add_files,mailmerge,,\
+ mailmerge.py \
+ msgbox.py \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/README.md b/scripting/README.md
new file mode 100644
index 000000000..0560a73b9
--- /dev/null
+++ b/scripting/README.md
@@ -0,0 +1,70 @@
+# Scripting Framework
+
+This module provides the source code for the Scripting Framework.
+
+For more information on the Scripting Framework, see the project web page:
+<https://framework.openoffice.org/scripting/>
+
+This module uses astyle to keep consistent java coding style. Please run
+
+ ./Format_java_code.sh
+
+before committing.
+
+## Source Code Structure
+
+The following directories contain the source code currently used
+by the Scripting Framework:
+
+- `source/provider`
+
+C++ source for the implementations of the `com.sun.star.script.provider.*`
+and `com.sun.star.script.browse.*` UNO types. These types are used for
+browsing and executing scripts.
+
+- `source/protocolhandler`
+
+C++ for a `ProtocolHandler` implementation that handles `vnd.sun.star.script`
+URIs and dispatches them for execution to the Scripting Framework.
+
+- `source/basprov`
+
+C++ implementation of the `LanguageScriptProvider` UNO service for Basic
+
+- `source/dlgprov`
+
+C++ implementation of the `DialogProvider` UNO service used for loading
+UNO dialogs from various languages
+
+- `source/pyprov`
+
+`LanguageScriptProvider` for Python
+
+- `java/com/sun/star/script/framework/provider`
+
+Implementation of an abstract base class ScriptProvider which provides
+core methods for implementing Java based `LanguageScriptProvider` implementations
+
+- `java/com/sun/star/script/framework/provider/*`
+
+`BeanShell`, JavaScript and Java `LanguageScriptProvider` implementations
+
+- `java/com/sun/star/script/framework/browse/*`
+
+`BrowseNode` implementations for the Java based `LanguageScriptProviders`
+
+- `java/com/sun/star/script/framework/io`
+- `java/com/sun/star/script/framework/container`
+
+Classes for performing script IO
+
+- `examples`
+
+Example scripts in BeanShell, JavaScript, Java and Python
+
+
+## Deprecated Code
+
+- `java/org/openoffice/*`
+
+Support for developing scripts in IDEs such as NetBeans.
diff --git a/scripting/Rdb_scriptproviderforbeanshell.mk b/scripting/Rdb_scriptproviderforbeanshell.mk
new file mode 100644
index 000000000..5b19a1523
--- /dev/null
+++ b/scripting/Rdb_scriptproviderforbeanshell.mk
@@ -0,0 +1,12 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Rdb_Rdb_install,scriptproviderforbeanshell))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/Rdb_scriptproviderforjavascript.mk b/scripting/Rdb_scriptproviderforjavascript.mk
new file mode 100644
index 000000000..06db18fa1
--- /dev/null
+++ b/scripting/Rdb_scriptproviderforjavascript.mk
@@ -0,0 +1,12 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Rdb_Rdb_install,scriptproviderforjavascript))
+
+# vim: set noet sw=4 ts=4:
diff --git a/scripting/astyle.options b/scripting/astyle.options
new file mode 100644
index 000000000..e8b338807
--- /dev/null
+++ b/scripting/astyle.options
@@ -0,0 +1,19 @@
+--style=java
+--mode=java
+--indent-switches
+--indent-cases
+--min-conditional-indent=0
+--max-instatement-indent=40
+--break-blocks
+--unpad-paren
+--align-reference=name
+--pad-oper
+--pad-header
+-s4
+--indent-col1-comments
+--lineend=linux
+--ignore-exclude-errors
+--suffix=none
+--preserve-date
+--formatted
+--max-code-length=80
diff --git a/scripting/examples/basic/InsertColouredText.xba b/scripting/examples/basic/InsertColouredText.xba
new file mode 100644
index 000000000..e97b5dfd8
--- /dev/null
+++ b/scripting/examples/basic/InsertColouredText.xba
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * 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 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="InsertColouredText" script:language="StarBasic">&apos; ***
+&apos; InsertColouredText basic script
+&apos; Uses a user interface to insert text of a specified colour to the
+&apos; start and end of a document
+&apos;
+&apos; author Neil Montgomery
+&apos; created August 12, 2002
+&apos; ***
+
+
+&apos; Main subprocedure to start script
+Sub Main
+ dialogShow()
+End Sub
+
+
+&apos; Global reference to the dialog object
+Dim oDialog as Object
+
+
+&apos; Uses the loadDialog subprocedure to load and execute the dialog box
+Sub dialogShow
+ oDialog = loadDialog(&quot;Standard&quot;,&quot;InsertColouredTextDialog&quot;)
+ oDialog.execute()
+End Sub
+
+
+&apos; ***
+&apos; Loads the dialog from the dialog library
+&apos;
+&apos; param Libname the library name where dialog is stored
+&apos; param DialogName the name of the dialog
+&apos; param oLibContainer library container to hold the loaded dialog library (optional)
+&apos; return runtime dialog object
+&apos; ***
+Function loadDialog(Libname as String, DialogName as String, Optional oLibContainer)
+ Dim oLib as Object
+ Dim oLibDialog as Object
+ Dim oRuntimeDialog as Object
+
+ &apos; If the optional oLibContainer is not passed to the function then
+ &apos; DialogLibraries is loaded by default
+ If isMissing(oLibContainer ) then
+ oLibContainer = DialogLibraries
+ End If
+
+ &apos; Loads the specified library, then loads the dialog
+ oLibContainer.loadLibrary(LibName)
+ oLib = oLibContainer.getByName(Libname)
+ oLibDialog = oLib.getByName(DialogName)
+ oRuntimeDialog = createUnoDialog(oLibDialog)
+
+ &apos; Returns the runtime dialog object
+ loadDialog() = oRuntimeDialog
+End Function
+
+
+
+&apos; ***
+&apos; Gets the RGB integer values and new text string from the dialog
+&apos; then writes the new coloured text to the start and end of the document
+&apos;
+&apos; ***
+Sub getFromDialog
+ Dim oDocument As Object
+ Dim oText As Object
+ Dim oCursor As Object
+
+ &apos; Create a document object for the current document then create text and
+ &apos; cursor objects
+ oDocument = StarDesktop.ActiveFrame.Controller.Model
+ oText = oDocument.Text
+ oCursor = oText.createTextCursor()
+
+ &apos; Write the coloured text to the start and end of the document
+ oCursor.gotoStart(false)
+ oCursor.CharColor = getColor()
+ oCursor.setString(&quot;New text at start: &quot; + getNewText())
+ oCursor.gotoEnd(false)
+ oCursor.CharColor = getColor()
+ oCursor.setString(&quot;New text at end: &quot; + getNewText())
+End Sub
+
+
+
+&apos; ***
+&apos; Reads the RGB integer values from the dialog
+&apos;
+&apos; returns long representing the RGB value
+&apos; ***
+Function getColor() as Long
+ Dim oRedText as Object
+ Dim oGreenText as Object
+ Dim oBlueText as Object
+ Dim nColor As Long
+
+ &apos; Get the three RGB values
+ oRedText = oDialog.GetControl(&quot;RedTextBox&quot;)
+ oGreenText = oDialog.GetControl(&quot;GreenTextBox&quot;)
+ oBlueText = oDialog.GetControl(&quot;BlueTextBox&quot;)
+
+ &apos; Convert the values to long type and return the value
+ nColor = RGB(oRedText.Text,oGreenText.Text,oBlueText.Text)
+ getColor = nColor
+End Function
+
+
+
+&apos; ***
+&apos; Reads the new text from the dialog
+&apos;
+&apos; returns string the new text
+&apos; ***
+Function getNewText() as String
+ Dim oNewText As Object
+ Dim sNewText As String
+
+ &apos; Gets the string from dialog and returns the new text
+ oNewText = oDialog.GetControl(&quot;NewTextBox&quot;)
+ sNewText = oNewText.Text
+ getNewText = sNewText
+End Function</script:module> \ No newline at end of file
diff --git a/scripting/examples/basic/InsertColouredTextDialog.xdl b/scripting/examples/basic/InsertColouredTextDialog.xdl
new file mode 100644
index 000000000..2fa7768bc
--- /dev/null
+++ b/scripting/examples/basic/InsertColouredTextDialog.xdl
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * 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 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="InsertColouredTextDialog" dlg:left="113" dlg:top="112" dlg:width="178" dlg:height="138" dlg:closeable="true" dlg:moveable="true">
+ <dlg:bulletinboard>
+ <dlg:textfield dlg:id="RedTextBox" dlg:tab-index="0" dlg:left="37" dlg:top="26" dlg:width="20" dlg:height="17"/>
+ <dlg:textfield dlg:id="GreenTextBox" dlg:tab-index="1" dlg:left="73" dlg:top="26" dlg:width="20" dlg:height="17"/>
+ <dlg:textfield dlg:id="BlueTextBox" dlg:tab-index="2" dlg:left="109" dlg:top="26" dlg:width="20" dlg:height="17"/>
+ <dlg:textfield dlg:id="NewTextBox" dlg:tab-index="3" dlg:left="57" dlg:top="67" dlg:width="57" dlg:height="15"/>
+ <dlg:button dlg:id="CommandButton1" dlg:tab-index="4" dlg:left="49" dlg:top="97" dlg:width="75" dlg:height="15" dlg:value="Insert New Coloured Text">
+ <script:event script:event-name="on-mousedown" script:location="application" script:macro-name="Standard.InsertColouredText.getFromDialog" script:language="StarBasic"/>
+ </dlg:button>
+ <dlg:text dlg:id="Label1" dlg:tab-index="5" dlg:left="44" dlg:top="12" dlg:width="7" dlg:height="10" dlg:value="R"/>
+ <dlg:text dlg:id="Label2" dlg:tab-index="6" dlg:left="78" dlg:top="12" dlg:width="7" dlg:height="10" dlg:value="G"/>
+ <dlg:text dlg:id="Label3" dlg:tab-index="7" dlg:left="114" dlg:top="12" dlg:width="7" dlg:height="10" dlg:value="B"/>
+ <dlg:text dlg:id="Label4" dlg:tab-index="8" dlg:left="71" dlg:top="56" dlg:width="26" dlg:height="8" dlg:value="New Text"/>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/scripting/examples/basic/SearchAndReplace.xba b/scripting/examples/basic/SearchAndReplace.xba
new file mode 100644
index 000000000..24c61d8e9
--- /dev/null
+++ b/scripting/examples/basic/SearchAndReplace.xba
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * 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 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="SearchAndReplace" script:language="StarBasic">&apos; ***
+&apos; SearchAndReplace basic script
+&apos; Uses a user interface to search and replace the specified strings
+&apos;
+&apos; author Neil Montgomery
+&apos; created August 12, 2002
+&apos; ***
+
+
+&apos; Main subprocedure to start script
+Sub Main
+ dialogShow()
+End Sub
+
+
+&apos; Global reference to the dialog object
+Dim oDialog as Object
+
+
+&apos; Uses the loadDialog subprocedure to load and execute the dialog box
+Sub dialogShow
+ oDialog = loadDialog(&quot;Standard&quot;,&quot;SearchAndReplaceDialog&quot;)
+ oDialog.execute()
+End Sub
+
+
+
+&apos; ***
+&apos; Loads the dialog from the dialog library
+&apos;
+&apos; param Libname the library name where dialog is stored
+&apos; param DialogName the name of the dialog
+&apos; param oLibContainer library container to hold the loaded dialog library (optional)
+&apos; return runtime dialog object
+&apos; ***
+Function loadDialog(Libname as String, DialogName as String, Optional oLibContainer)
+ Dim oLib as Object
+ Dim oLibDialog as Object
+ Dim oRuntimeDialog as Object
+
+ If isMissing(oLibContainer ) then
+ oLibContainer = DialogLibraries
+ End If
+ oLibContainer.loadLibrary(LibName)
+ oLib = oLibContainer.getByName(Libname)
+ oLibDialog = oLib.getByName(DialogName)
+ oRuntimeDialog = createUnoDialog(oLibDialog)
+ loadDialog() = oRuntimeDialog
+End Function
+
+
+
+&apos; ***
+&apos; Creates a connection to the current document.
+&apos; Gets the search and replace keys from the dialog and replaces all
+&apos; instances of the search key with the replace key.
+&apos;
+&apos; ***
+Sub getInfoFromDialog
+ Dim oDocument As Object
+ Dim oSearch As Object
+ Dim oFound As Object
+ Dim oFoundCursor As Object
+ Dim oSearchText as Object
+ Dim oReplaceText as Object
+
+ &apos; Create a document object for the current document then create text and
+ &apos; cursor objects
+ oDocument = StarDesktop.ActiveFrame.Controller.Model
+ oSearch = oDocument.createSearchDescriptor
+
+ &apos; Replace all instances of the search string with the replace string
+ oSearch.SearchString = getSearchKey()
+ oSearch.ReplaceString = getReplaceKey()
+ oDocument.replaceAll(oSearch)
+End Sub
+
+
+&apos; ***
+&apos; Gets the search key string from the dialog
+&apos;
+&apos; returns string representing the search key
+&apos; ***
+Function getSearchKey() as String
+ Dim sSearch As String
+
+ &apos; Get the search key from the dialog
+ oSearchText = oDialog.GetControl(&quot;SearchKeyTextBox&quot;)
+ sSearch = oSearchText.Text
+ getSearchKey = sSearch
+End Function
+
+
+
+&apos; ***
+&apos; Gets the replace key string from the dialog
+&apos;
+&apos; returns string representing the replace key
+&apos; ***
+Function getReplaceKey() as String
+ Dim sReplace As String
+
+ &apos; Get the replace key from the dialog
+ oReplaceText = oDialog.GetControl(&quot;ReplaceKeyTextBox&quot;)
+ sReplace = oReplaceText.Text
+ getReplaceKey = sReplace
+End Function</script:module>
diff --git a/scripting/examples/basic/SearchAndReplaceDialog.xdl b/scripting/examples/basic/SearchAndReplaceDialog.xdl
new file mode 100644
index 000000000..9503dbf57
--- /dev/null
+++ b/scripting/examples/basic/SearchAndReplaceDialog.xdl
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * 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 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="SearchAndReplaceDialog" dlg:left="113" dlg:top="112" dlg:width="178" dlg:height="138" dlg:closeable="true" dlg:moveable="true">
+ <dlg:bulletinboard>
+ <dlg:textfield dlg:id="SearchKeyTextBox" dlg:tab-index="0" dlg:left="28" dlg:top="31" dlg:width="53" dlg:height="13"/>
+ <dlg:textfield dlg:id="ReplaceKeyTextBox" dlg:tab-index="1" dlg:left="102" dlg:top="31" dlg:width="51" dlg:height="13"/>
+ <dlg:button dlg:id="CommandButton1" dlg:tab-index="2" dlg:left="59" dlg:top="79" dlg:width="62" dlg:height="13" dlg:value="Search And Replace">
+ <script:event script:event-name="on-mousedown" script:location="application" script:macro-name="Standard.SearchAndReplace.getInfoFromDialog" script:language="StarBasic"/>
+ </dlg:button>
+ <dlg:text dlg:id="Label1" dlg:tab-index="3" dlg:left="37" dlg:top="20" dlg:width="33" dlg:height="8" dlg:value="Search Key"/>
+ <dlg:text dlg:id="Label2" dlg:tab-index="4" dlg:left="109" dlg:top="20" dlg:width="35" dlg:height="8" dlg:value="Replace Key"/>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/scripting/examples/basic/dialog.xlb b/scripting/examples/basic/dialog.xlb
new file mode 100644
index 000000000..95dc3a123
--- /dev/null
+++ b/scripting/examples/basic/dialog.xlb
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd">
+<library:library xmlns:library="http://openoffice.org/2000/library" library:name="Standard" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="InsertColouredTextDialog"/>
+ <library:element library:name="SearchAndReplaceDialog"/>
+</library:library>
diff --git a/scripting/examples/basic/script.xlb b/scripting/examples/basic/script.xlb
new file mode 100644
index 000000000..fa7dd6103
--- /dev/null
+++ b/scripting/examples/basic/script.xlb
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd">
+<library:library xmlns:library="http://openoffice.org/2000/library" library:name="Standard" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="InsertColouredText"/>
+ <library:element library:name="SearchAndReplace"/>
+</library:library>
diff --git a/scripting/examples/beanshell/Calc/CopyRange.bsh b/scripting/examples/beanshell/Calc/CopyRange.bsh
new file mode 100644
index 000000000..d1e7a49f1
--- /dev/null
+++ b/scripting/examples/beanshell/Calc/CopyRange.bsh
@@ -0,0 +1,39 @@
+/*
+ * 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/.
+ */
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XModel;
+import com.sun.star.sheet.XSpreadsheetDocument;
+import com.sun.star.sheet.XSpreadsheet;
+import com.sun.star.sheet.XSpreadsheets;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.sheet.XCellAddressable;
+import com.sun.star.sheet.XCellRangeAddressable;
+import com.sun.star.table.CellAddress;
+import com.sun.star.table.CellRangeAddress;
+import com.sun.star.sheet.XCellRangeMovement;
+
+oDoc = UnoRuntime.queryInterface(XModel.class,XSCRIPTCONTEXT.getInvocationContext());
+if ( oDoc == null )
+ oDoc = XSCRIPTCONTEXT.getDocument();
+
+XSpreadsheetDocument xDoc = (XSpreadsheetDocument) UnoRuntime.queryInterface(XSpreadsheetDocument.class,oDoc);
+XSpreadsheets xSheets = xDoc.getSheets();
+XIndexAccess xSheetsIA = UnoRuntime.queryInterface(XIndexAccess.class, xSheets);
+XSpreadsheet xSheet = UnoRuntime.queryInterface(com.sun.star.sheet.XSpreadsheet.class, xSheetsIA.getByIndex(0));
+
+XCellRangeAddressable xAddr1 = UnoRuntime.queryInterface(XCellRangeAddressable.class, xSheet.getCellRangeByName("A1:A10") );
+CellRangeAddress source = xAddr1.getRangeAddress();
+
+XCellAddressable xAddr2 = UnoRuntime.queryInterface(XCellAddressable.class, xSheet.getCellRangeByName("B1").getCellByPosition( 0, 0 ) );
+CellAddress target = xAddr2.getCellAddress();
+
+XCellRangeMovement xCRM = UnoRuntime.queryInterface(XCellRangeMovement.class, xSheet);
+xCRM.copyRange(target, source);
+
+return 0;
diff --git a/scripting/examples/beanshell/Calc/FixView.bsh b/scripting/examples/beanshell/Calc/FixView.bsh
new file mode 100644
index 000000000..4ea2c62f9
--- /dev/null
+++ b/scripting/examples/beanshell/Calc/FixView.bsh
@@ -0,0 +1,34 @@
+/*
+ * 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/.
+ */
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XModel;
+import com.sun.star.sheet.XSpreadsheetDocument;
+import com.sun.star.sheet.XSpreadsheet;
+import com.sun.star.sheet.XSpreadsheets;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.sheet.XViewFreezable;
+import com.sun.star.sheet.XViewPane;
+
+oDoc = UnoRuntime.queryInterface(XModel.class,XSCRIPTCONTEXT.getInvocationContext());
+if ( oDoc == null )
+ oDoc = XSCRIPTCONTEXT.getDocument();
+
+XSpreadsheetDocument xDoc = (XSpreadsheetDocument) UnoRuntime.queryInterface(XSpreadsheetDocument.class,oDoc);
+XSpreadsheets xSheets = xDoc.getSheets();
+XIndexAccess xSheetsIA = UnoRuntime.queryInterface(XIndexAccess.class, xSheets);
+XSpreadsheet xSheet = UnoRuntime.queryInterface(com.sun.star.sheet.XSpreadsheet.class, xSheetsIA.getByIndex(0));
+
+XViewFreezable xFreeze = UnoRuntime.queryInterface(XViewFreezable.class, oDoc.getCurrentController() );
+xFreeze.freezeAtPosition(2, 3);
+
+XViewPane xViewPane = UnoRuntime.queryInterface(XViewPane.class, oDoc.getCurrentController() );
+xViewPane.setFirstVisibleColumn(12);
+xViewPane.setFirstVisibleRow(149);
+
+return 0;
diff --git a/scripting/examples/beanshell/Calc/InsertSheet.bsh b/scripting/examples/beanshell/Calc/InsertSheet.bsh
new file mode 100644
index 000000000..ef68f9b3e
--- /dev/null
+++ b/scripting/examples/beanshell/Calc/InsertSheet.bsh
@@ -0,0 +1,25 @@
+/*
+ * 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/.
+ */
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XModel;
+import com.sun.star.sheet.XSpreadsheetDocument;
+import com.sun.star.sheet.XSpreadsheets;
+import com.sun.star.lang.XMultiServiceFactory;
+
+oDoc = UnoRuntime.queryInterface(XModel.class,XSCRIPTCONTEXT.getInvocationContext());
+if ( oDoc == null )
+ oDoc = XSCRIPTCONTEXT.getDocument();
+
+XSpreadsheetDocument xDoc = (XSpreadsheetDocument) UnoRuntime.queryInterface(XSpreadsheetDocument.class,oDoc);
+XSpreadsheets xSheets = xDoc.getSheets();
+
+xSheets.insertNewByName("First new sheet", (short)0);
+xSheets.insertNewByName("Second new sheet", (short)1);
+
+return 0;
diff --git a/scripting/examples/beanshell/Calc/ProtectSheet.bsh b/scripting/examples/beanshell/Calc/ProtectSheet.bsh
new file mode 100644
index 000000000..eea3bd511
--- /dev/null
+++ b/scripting/examples/beanshell/Calc/ProtectSheet.bsh
@@ -0,0 +1,30 @@
+/*
+ * 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/.
+ */
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XModel;
+import com.sun.star.sheet.XSpreadsheetDocument;
+import com.sun.star.sheet.XSpreadsheet;
+import com.sun.star.sheet.XSpreadsheets;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.util.XProtectable;
+
+oDoc = UnoRuntime.queryInterface(XModel.class,XSCRIPTCONTEXT.getInvocationContext());
+if ( oDoc == null )
+ oDoc = XSCRIPTCONTEXT.getDocument();
+
+XSpreadsheetDocument xDoc = (XSpreadsheetDocument) UnoRuntime.queryInterface(XSpreadsheetDocument.class, oDoc);
+XSpreadsheets xSheets = xDoc.getSheets();
+XIndexAccess xSheetsIA = UnoRuntime.queryInterface(XIndexAccess.class, xSheets);
+XSpreadsheet xSheet = UnoRuntime.queryInterface(XSpreadsheet.class, xSheetsIA.getByIndex(0));
+XProtectable xProtectable = UnoRuntime.queryInterface(XProtectable.class, xSheet);
+xProtectable.protect("myPassword");
+
+//xProtectable.unprotect("myPassword");
+
+return 0;
diff --git a/scripting/examples/beanshell/Calc/SelectCell.bsh b/scripting/examples/beanshell/Calc/SelectCell.bsh
new file mode 100644
index 000000000..7d8f5a381
--- /dev/null
+++ b/scripting/examples/beanshell/Calc/SelectCell.bsh
@@ -0,0 +1,30 @@
+/*
+ * 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/.
+ */
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XModel;
+import com.sun.star.sheet.XSpreadsheetDocument;
+import com.sun.star.sheet.XSpreadsheet;
+import com.sun.star.sheet.XSpreadsheets;
+import com.sun.star.view.XSelectionSupplier;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.table.XCellRange;
+
+oDoc = UnoRuntime.queryInterface(XModel.class,XSCRIPTCONTEXT.getInvocationContext());
+if ( oDoc == null )
+ oDoc = XSCRIPTCONTEXT.getDocument();
+
+XSpreadsheetDocument xDoc = (XSpreadsheetDocument) UnoRuntime.queryInterface(XSpreadsheetDocument.class,oDoc);
+XSpreadsheets xSheets = xDoc.getSheets();
+XIndexAccess xSheetsIA = UnoRuntime.queryInterface(XIndexAccess.class, xSheets);
+XSpreadsheet xSheet = UnoRuntime.queryInterface(com.sun.star.sheet.XSpreadsheet.class, xSheetsIA.getByIndex(0));
+XCellRange xResultRange = xSheet.getCellRangeByName("B20");
+XSelectionSupplier xSel = UnoRuntime.queryInterface(XSelectionSupplier.class, oDoc.getCurrentController());
+xSel.select(xResultRange);
+
+return 0;
diff --git a/scripting/examples/beanshell/Calc/parcel-descriptor.xml b/scripting/examples/beanshell/Calc/parcel-descriptor.xml
new file mode 100644
index 000000000..155d53c9b
--- /dev/null
+++ b/scripting/examples/beanshell/Calc/parcel-descriptor.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><parcel xmlns:parcel="scripting.dtd" language="BeanShell">
+<script language="BeanShell"><locale lang="en"><displayname value="SelectCell.bsh"/><description>SelectCell.bsh</description></locale><logicalname value="SelectCell.bsh"/><functionname value="SelectCell.bsh"/></script><script language="BeanShell"><locale lang="en"><displayname value="InsertSheet.bsh"/><description>InsertSheet.bsh</description></locale><logicalname value="InsertSheet.bsh"/><functionname value="InsertSheet.bsh"/></script><script language="BeanShell"><locale lang="en"><displayname value="ProtectSheet.bsh"/><description>ProtectSheet.bsh</description></locale><logicalname value="ProtectSheet.bsh"/><functionname value="ProtectSheet.bsh"/></script><script language="BeanShell"><locale lang="en"><displayname value="CopyRange.bsh"/><description>CopyRange.bsh</description></locale><logicalname value="CopyRange.bsh"/><functionname value="CopyRange.bsh"/></script><script language="BeanShell"><locale lang="en"><displayname value="FixView.bsh"/><description>FixView.bsh</description></locale><logicalname value="FixView.bsh"/><functionname value="FixView.bsh"/></script></parcel> \ No newline at end of file
diff --git a/scripting/examples/beanshell/Capitalise/capitalise.bsh b/scripting/examples/beanshell/Capitalise/capitalise.bsh
new file mode 100644
index 000000000..6b68e010f
--- /dev/null
+++ b/scripting/examples/beanshell/Capitalise/capitalise.bsh
@@ -0,0 +1,111 @@
+/*
+ * 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 .
+ */
+// Change the case of a selection, or current word from upper case,
+// to first char upper case, to all lower case to upper case...
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XModel;
+import com.sun.star.view.XSelectionSupplier;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.text.XText;
+import com.sun.star.text.XTextRange;
+import com.sun.star.text.XWordCursor;
+import com.sun.star.script.provider.XScriptContext;
+
+// return the new string based on the string passed in
+String getNewString( theString ) {
+ String newString;
+ if(theString==null || theString.length()==0) {
+ return newString;
+ }
+ // should we tokenize on "."?
+ if(Character.isUpperCase(theString.charAt(0)) && theString.length()>=2 && Character.isUpperCase(theString.charAt(1))) { // first two chars are UC => first UC, rest LC
+ newString=theString.substring(0,1).toUpperCase()+theString.substring(1).toLowerCase();
+ } else if (Character.isUpperCase(theString.charAt(0))) { // first char UC => all to LC
+ newString=theString.toLowerCase();
+ } else { // all to UC.
+ newString=theString.toUpperCase();
+ }
+ return newString;
+}
+
+//the method that does the work
+void capitalise() {
+
+ // get the number of regions selected
+ count = xIndexAccess.getCount();
+ if(count>=1) { //ie we have a selection
+ for(i=0;i<count;i++) {
+ // get the i-th region selected
+ xTextRange = (XTextRange)
+ UnoRuntime.queryInterface(XTextRange.class, xIndexAccess.getByIndex(i));
+ System.out.println("string: "+xTextRange.getString());
+ // get the selected string
+ theString = xTextRange.getString();
+ if(theString.length()==0) {
+ // sadly we can have a selection where nothing is selected
+ // in this case we get the XWordCursor and make a selection!
+ xText = (XText)
+ UnoRuntime.queryInterface(XText.class, xTextRange.getText());
+ xWordCursor = (XWordCursor)
+ UnoRuntime.queryInterface(XWordCursor.class, xText.createTextCursorByRange(xTextRange));
+ // move the Word cursor to the start of the word if it's not
+ // already there
+ if(!xWordCursor.isStartOfWord()) {
+ xWordCursor.gotoStartOfWord(false);
+ }
+ // move the cursor to the next word, selecting all chars
+ // in between
+ xWordCursor.gotoNextWord(true);
+ // get the selected string
+ theString = xWordCursor.getString();
+ // get the new string
+ newString = getNewString(theString);
+ if(newString!=null) {
+ // set the new string
+ xWordCursor.setString(newString);
+ // keep the current selection
+ xSelectionSupplier.select(xWordCursor);
+ }
+ } else {
+ newString = getNewString( theString );
+ if(newString!=null) {
+ // set the new string
+ xTextRange.setString(newString);
+ // keep the current selection
+ xSelectionSupplier.select(xTextRange);
+ }
+ }
+
+ }
+ }
+}
+
+// The XSCRIPTCONTEXT variable is of type XScriptContext and is available to
+// all BeanShell scripts executed by the Script Framework
+xModel = (XModel)
+ UnoRuntime.queryInterface(XModel.class, XSCRIPTCONTEXT.getDocument());
+//the writer controller impl supports the css.view.XSelectionSupplier interface
+xSelectionSupplier = (XSelectionSupplier)
+ UnoRuntime.queryInterface(XSelectionSupplier.class, xModel.getCurrentController());
+//see section 7.5.1 of developers' guide
+xIndexAccess = (XIndexAccess)
+ UnoRuntime.queryInterface(XIndexAccess.class, xSelectionSupplier.getSelection());
+
+//call the method that does the work
+capitalise();
+return 0;
diff --git a/scripting/examples/beanshell/Capitalise/parcel-descriptor.xml b/scripting/examples/beanshell/Capitalise/parcel-descriptor.xml
new file mode 100644
index 000000000..d6fb419aa
--- /dev/null
+++ b/scripting/examples/beanshell/Capitalise/parcel-descriptor.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="BeanShell" xmlns:parcel="scripting.dtd">
+
+ <script language="BeanShell">
+ <locale lang="en">
+ <displayname value="Capitalise"/>
+ <description>
+ Change the case of a selection, or current word from upper case, to first char upper case, to all lower case to upper case...
+ </description>
+ </locale>
+ <functionname value="capitalise.bsh"/>
+ <logicalname value="Capitalise.BeanShell"/>
+ </script>
+
+</parcel>
diff --git a/scripting/examples/beanshell/HelloWorld/helloworld.bsh b/scripting/examples/beanshell/HelloWorld/helloworld.bsh
new file mode 100644
index 000000000..4ff9cd42e
--- /dev/null
+++ b/scripting/examples/beanshell/HelloWorld/helloworld.bsh
@@ -0,0 +1,34 @@
+/*
+ * 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 .
+ */
+// Hello World in BeanShell
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.text.XTextDocument;
+import com.sun.star.text.XText;
+import com.sun.star.text.XTextRange;
+
+// get the document from the scripting context which is made available to all
+// scripts
+oDoc = XSCRIPTCONTEXT.getDocument();
+//get the XTextDocument interface
+xTextDoc = (XTextDocument) UnoRuntime.queryInterface(XTextDocument.class,oDoc);
+//get the XText interface
+xText = xTextDoc.getText();
+// get an (empty) XTextRange at the end of the document
+xTextRange = xText.getEnd();
+// set the string
+xTextRange.setString( "Hello World (in BeanShell)" );
diff --git a/scripting/examples/beanshell/HelloWorld/parcel-descriptor.xml b/scripting/examples/beanshell/HelloWorld/parcel-descriptor.xml
new file mode 100644
index 000000000..e4c073b5f
--- /dev/null
+++ b/scripting/examples/beanshell/HelloWorld/parcel-descriptor.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="BeanShell" xmlns:parcel="scripting.dtd">
+
+ <script language="BeanShell">
+ <locale lang="en">
+ <displayname value="Hello World"/>
+ <description>
+ Adds the string "Hello World" into the current text doc.
+ </description>
+ </locale>
+ <functionname value="helloworld.bsh"/>
+ <logicalname value="HelloWorld.BeanShell"/>
+ </script>
+
+</parcel>
diff --git a/scripting/examples/beanshell/Highlight/ButtonPressHandler.bsh b/scripting/examples/beanshell/Highlight/ButtonPressHandler.bsh
new file mode 100644
index 000000000..ac6efacce
--- /dev/null
+++ b/scripting/examples/beanshell/Highlight/ButtonPressHandler.bsh
@@ -0,0 +1,123 @@
+/*
+ * 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 .
+ */
+// this code is bound to the events generated by the buttons in the dialog
+// it will close the dialog or find and highlight the text entered in the
+// dialog (depending on the button pressed)
+import com.sun.star.uno.*;
+import com.sun.star.awt.*;
+import com.sun.star.lang.*;
+import com.sun.star.beans.*;
+import com.sun.star.util.*;
+import com.sun.star.script.framework.browse.DialogFactory;
+
+// Get the ActionEvent object from the ARGUMENTS list
+ActionEvent event = (ActionEvent) ARGUMENTS[0];
+
+// Each argument is of type Any so we must use the AnyConverter class to
+// convert it into the interface or primitive type we expect
+XButton button = (XButton)AnyConverter.toObject(
+ new Type(XButton.class), event.Source);
+
+// We can now query for the model of the button and get its properties
+XControl control = (XControl)UnoRuntime.queryInterface(XControl.class, button);
+XControlModel cmodel = control.getModel();
+XPropertySet pset = (XPropertySet)UnoRuntime.queryInterface(
+ XPropertySet.class, cmodel);
+
+if (pset.getPropertyValue("Label").equals("Exit"))
+{
+ // We can get the XDialog in which this control appears by calling
+ // getContext() on the XControl interface
+ XDialog xDialog = (XDialog)UnoRuntime.queryInterface(
+ XDialog.class, control.getContext());
+
+ // Close the dialog
+ xDialog.endExecute();
+}
+else
+{
+ // We can get the list of controls for this dialog by calling
+ // getContext() on the XControl interface of the button
+ XControlContainer controls = (XControlContainer)UnoRuntime.queryInterface(
+ XControlContainer.class, control.getContext());
+
+ // Now get the text field control from the list
+ XTextComponent textField = (XTextComponent)
+ UnoRuntime.queryInterface(
+ XTextComponent.class, controls.getControl("HighlightTextField"));
+
+ String searchKey = textField.getText();
+
+ // highlight the text in red
+ java.awt.Color cRed = new java.awt.Color(255, 0, 0);
+ int red = cRed.getRGB();
+
+ XReplaceable replaceable = (XReplaceable)
+ UnoRuntime.queryInterface(XReplaceable.class, XSCRIPTCONTEXT.getDocument());
+
+ XReplaceDescriptor descriptor =
+ (XReplaceDescriptor) replaceable.createReplaceDescriptor();
+
+ // Gets a XPropertyReplace object for altering the properties
+ // of the replaced text
+ XPropertyReplace xPropertyReplace = (XPropertyReplace)
+ UnoRuntime.queryInterface(XPropertyReplace.class, descriptor);
+
+ // Sets the replaced text property fontweight value to Bold
+ PropertyValue wv = new PropertyValue("CharWeight", -1,
+ new Float(com.sun.star.awt.FontWeight.BOLD),
+ com.sun.star.beans.PropertyState.DIRECT_VALUE);
+
+ // Sets the replaced text property color value to RGB parameter
+ PropertyValue cv = new PropertyValue("CharColor", -1,
+ new Integer(red),
+ com.sun.star.beans.PropertyState.DIRECT_VALUE);
+
+ // Apply the properties
+ PropertyValue[] props = new PropertyValue[] { cv, wv };
+
+ try {
+ xPropertyReplace.setReplaceAttributes(props);
+
+ // Only matches whole words and case sensitive
+ descriptor.setPropertyValue(
+ "SearchCaseSensitive", new Boolean(true));
+ descriptor.setPropertyValue("SearchWords", new Boolean(true));
+ }
+ catch (com.sun.star.beans.UnknownPropertyException upe) {
+ System.err.println("Error setting up search properties");
+ return;
+ }
+ catch (com.sun.star.beans.PropertyVetoException pve) {
+ System.err.println("Error setting up search properties");
+ return;
+ }
+ catch (com.sun.star.lang.WrappedTargetException wte) {
+ System.err.println("Error setting up search properties");
+ return;
+ }
+
+ // Replaces all instances of searchKey with new Text properties
+ // and gets the number of instances of the searchKey
+ descriptor.setSearchString(searchKey);
+ descriptor.setReplaceString(searchKey);
+ replaceable.replaceAll(descriptor);
+}
+
+// BeanShell scripts in LibreOffice should always return 0
+return 0;
diff --git a/scripting/examples/beanshell/Highlight/ShowDialog.bsh b/scripting/examples/beanshell/Highlight/ShowDialog.bsh
new file mode 100644
index 000000000..95ccc32bb
--- /dev/null
+++ b/scripting/examples/beanshell/Highlight/ShowDialog.bsh
@@ -0,0 +1,140 @@
+/*
+ * 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 .
+ */
+// this script serves as an example of how to launch a Basic Dialog
+// from a script
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.script.provider.XScriptContext;
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lang.EventObject;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.text.XTextDocument;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.script.XLibraryContainer;
+import com.sun.star.awt.*;
+import com.sun.star.util.*;
+
+boolean tryLoadingLibrary( xmcf, context, name )
+{
+ try
+ {
+ obj = xmcf.createInstanceWithContext(
+ "com.sun.star.script.Application" + name + "LibraryContainer",
+ context.getComponentContext());
+
+ xLibraryContainer = (XLibraryContainer)
+ UnoRuntime.queryInterface(XLibraryContainer.class, obj);
+
+ System.err.println("Got XLibraryContainer");
+
+ serviceObj = context.getComponentContext().getValueByName(
+ "/singletons/com.sun.star.util.theMacroExpander");
+
+ xme = (XMacroExpander) AnyConverter.toObject(
+ new Type(XMacroExpander.class), serviceObj);
+
+ bootstrapName = "bootstraprc";
+ if (System.getProperty("os.name").startsWith("Windows"))
+ {
+ bootstrapName = "bootstrap.ini";
+ }
+
+ libURL = xme.expandMacros(
+ "$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR/basic/ScriptBindingLibrary/" +
+ name.toLowerCase() + ".xlb/");
+
+ System.err.println("libURL is: " + libURL);
+
+ xLibraryContainer.createLibraryLink(
+ "ScriptBindingLibrary", libURL, false);
+
+ System.err.println("liblink created");
+
+ }
+ catch (com.sun.star.uno.Exception e)
+ {
+ System.err.println("Got an exception loading lib: " + e.getMessage());
+ return false;
+ }
+ return true;
+}
+
+// get the XMultiComponentFactory from the XSCRIPTCONTEXT
+XMultiComponentFactory xmcf =
+ XSCRIPTCONTEXT.getComponentContext().getServiceManager();
+
+Object[] args = new Object[1];
+args[0] = XSCRIPTCONTEXT.getDocument();
+
+Object obj;
+try {
+ // try to create an instance of the DialogProvider
+ obj = xmcf.createInstanceWithArgumentsAndContext(
+ "com.sun.star.awt.DialogProvider", args,
+ XSCRIPTCONTEXT.getComponentContext());
+ /*
+ obj = xmcf.createInstanceWithContext(
+ "com.sun.star.awt.DialogProvider",
+ XSCRIPTCONTEXT.getComponentContext());
+ */
+}
+catch (com.sun.star.uno.Exception e) {
+ System.err.println("Error getting DialogProvider object");
+ return 0;
+}
+
+// get the XDialogProvider interface from the object created above
+XDialogProvider xDialogProvider = (XDialogProvider)
+ UnoRuntime.queryInterface(XDialogProvider.class, obj);
+
+System.err.println("Got DialogProvider, now get dialog");
+
+try {
+ // try to create the Highlight dialog (found in the ScriptBindingLibrary)
+ findDialog = xDialogProvider.createDialog("vnd.sun.star.script:" +
+ "ScriptBindingLibrary.Highlight?location=application");
+ if( findDialog == null )
+ {
+ if (tryLoadingLibrary(xmcf, XSCRIPTCONTEXT, "Dialog") == false ||
+ tryLoadingLibrary(xmcf, XSCRIPTCONTEXT, "Script") == false)
+ {
+ System.err.println("Error loading ScriptBindingLibrary");
+ return 0;
+ }
+ else
+ {
+ // try to create the Highlight dialog (found in the ScriptBindingLibrary)
+ findDialog = xDialogProvider.createDialog("vnd.sun.star.script:" +
+ "ScriptBindingLibrary.Highlight?location=application");
+ }
+ }
+}
+catch (java.lang.Exception e) {
+ System.err.println("Got exception on first creating dialog: " +
+ e.getMessage());
+}
+
+// execute the dialog in a new thread (so that this script can finish)
+Thread t = new Thread() {
+ public void run() {
+ findDialog.execute();
+ }
+};
+t.start();
+
+return 0;
diff --git a/scripting/examples/beanshell/Highlight/highlighter.bsh b/scripting/examples/beanshell/Highlight/highlighter.bsh
new file mode 100644
index 000000000..a69f76e1a
--- /dev/null
+++ b/scripting/examples/beanshell/Highlight/highlighter.bsh
@@ -0,0 +1,166 @@
+/*
+ * 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 .
+ */
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.XReplaceable;
+import com.sun.star.util.XReplaceDescriptor;
+import com.sun.star.util.XPropertyReplace;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.text.XTextDocument;
+import com.sun.star.script.provider.XScriptContext;
+
+int replaceText(searchKey, color, bold) {
+
+ result = 0;
+
+ try {
+ // Create an XReplaceable object and an XReplaceDescriptor
+ replaceable = (XReplaceable)
+ UnoRuntime.queryInterface(XReplaceable.class, xTextDocument);
+
+ descriptor =
+ (XReplaceDescriptor) replaceable.createReplaceDescriptor();
+
+ // Gets a XPropertyReplace object for altering the properties
+ // of the replaced text
+ xPropertyReplace = (XPropertyReplace)
+ UnoRuntime.queryInterface(XPropertyReplace.class, descriptor);
+
+ // Sets the replaced text property fontweight value to Bold or Normal
+ wv = null;
+ if (bold) {
+ wv = new PropertyValue("CharWeight", -1,
+ new Float(com.sun.star.awt.FontWeight.BOLD),
+ com.sun.star.beans.PropertyState.DIRECT_VALUE);
+ }
+ else {
+ wv = new PropertyValue("CharWeight", -1,
+ new Float(com.sun.star.awt.FontWeight.NORMAL),
+ com.sun.star.beans.PropertyState.DIRECT_VALUE);
+ }
+
+ // Sets the replaced text property color value to RGB color parameter
+ cv = new PropertyValue("CharColor", -1, new Integer(color),
+ com.sun.star.beans.PropertyState.DIRECT_VALUE);
+
+ // Apply the properties
+ PropertyValue[] props = { cv, wv };
+ xPropertyReplace.setReplaceAttributes(props);
+
+ // Only matches whole words and case sensitive
+ descriptor.setPropertyValue("SearchCaseSensitive", new Boolean(true));
+ descriptor.setPropertyValue("SearchWords", new Boolean(true));
+
+ // Replaces all instances of searchKey with new Text properties
+ // and gets the number of instances of the searchKey
+ descriptor.setSearchString(searchKey);
+ descriptor.setReplaceString(searchKey);
+ result = replaceable.replaceAll(descriptor);
+
+ }
+ catch (Exception e) {
+ }
+
+ return result;
+}
+
+searchKey = "";
+
+// The XSCRIPTCONTEXT variable is of type XScriptContext and is available to
+// all BeanShell scripts executed by the Script Framework
+xTextDocument = (XTextDocument)
+ UnoRuntime.queryInterface(XTextDocument.class, XSCRIPTCONTEXT.getDocument());
+
+// Create a JButton and add an ActionListener
+// When clicked the value for the searchKey is read and passed to replaceText
+myListener = new ActionListener() {
+ actionPerformed(ActionEvent e) {
+ searchKey = findTextBox.getText();
+
+ if(searchKey.equalsIgnoreCase("")) {
+ JOptionPane.showMessageDialog(null,
+ "No text entered for search",
+ "No text", JOptionPane.INFORMATION_MESSAGE);
+ }
+ else {
+ // highlight the text in red
+ cRed = new Color(255, 0, 0);
+ red = cRed.getRGB();
+ num = replaceText(searchKey, red, true);
+
+ if(num > 0) {
+ int response = JOptionPane.showConfirmDialog(null,
+ searchKey + " was found " + num +
+ " times\nDo you wish to keep the text highlighted?",
+ "Confirm highlight", JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE);
+
+ if (response == 1) {
+ cBlack = new Color(255, 255, 255);
+ black = cBlack.getRGB();
+ replaceText(searchKey, black, false);
+ }
+ }
+ else {
+ JOptionPane.showMessageDialog(null,
+ "No matches were found", "Not found",
+ JOptionPane.INFORMATION_MESSAGE);
+ }
+ }
+ }
+};
+
+
+exitListener = new ActionListener() {
+ actionPerformed(ActionEvent e) {
+ frame.dispose();
+ }
+};
+
+
+searchButton = new JButton("Highlight");
+searchButton.addActionListener(myListener);
+
+exitButton = new JButton("Exit");
+exitButton.addActionListener(exitListener);
+
+buttonPanel = new JPanel();
+buttonPanel.setLayout(new FlowLayout());
+buttonPanel.add(searchButton);
+buttonPanel.add(exitButton);
+
+
+// Create a JPanel containing one JTextField for the search text.
+searchPanel = new JPanel();
+searchPanel.setLayout(new FlowLayout());
+findTextBox = new JTextField(20);
+findWhat = new JLabel("Find What: ");
+searchPanel.add(findWhat);
+searchPanel.add(findTextBox);
+
+// Create frame and add a window listener
+frame = new JFrame("Highlight Text");
+frame.setSize(350,130);
+frame.setLocation(430,430);
+frame.setResizable(false);
+// Add the panel and button to the frame
+frame.getContentPane().setLayout(new GridLayout(2,1,10,10));
+frame.getContentPane().add(searchPanel);
+frame.getContentPane().add(buttonPanel);
+
+frame.setVisible(true);
+frame.pack();
diff --git a/scripting/examples/beanshell/Highlight/parcel-descriptor.xml b/scripting/examples/beanshell/Highlight/parcel-descriptor.xml
new file mode 100644
index 000000000..a2a3773a9
--- /dev/null
+++ b/scripting/examples/beanshell/Highlight/parcel-descriptor.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="BeanShell" xmlns:parcel="scripting.dtd">
+ <script language="BeanShell">
+ <locale lang="en">
+ <displayname value="ShowDialog" />
+ <description>
+ Example of how to show a dialog from BeanShell
+ </description>
+ </locale>
+ <functionname value="ShowDialog.bsh" />
+ <logicalname value="ShowDialog.BeanShell" />
+ </script>
+ <script language="BeanShell">
+ <locale lang="en">
+ <displayname value="ButtonPressHandler" />
+ <description>
+ Example of handle button press events for the Dialog
+ </description>
+ </locale>
+ <functionname value="ButtonPressHandler.bsh" />
+ <logicalname value="ButtonPressHandler.BeanShell" />
+ </script>
+</parcel>
+
diff --git a/scripting/examples/beanshell/InteractiveBeanShell/interactive.bsh b/scripting/examples/beanshell/InteractiveBeanShell/interactive.bsh
new file mode 100644
index 000000000..0e82f1df0
--- /dev/null
+++ b/scripting/examples/beanshell/InteractiveBeanShell/interactive.bsh
@@ -0,0 +1,21 @@
+/*
+ * 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 .
+ */
+// Pops up a window into which you can type BeanShell code and run it
+// against the current document
+editor();
+return 0;
diff --git a/scripting/examples/beanshell/InteractiveBeanShell/parcel-descriptor.xml b/scripting/examples/beanshell/InteractiveBeanShell/parcel-descriptor.xml
new file mode 100644
index 000000000..0911ac56a
--- /dev/null
+++ b/scripting/examples/beanshell/InteractiveBeanShell/parcel-descriptor.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="BeanShell" xmlns:parcel="scripting.dtd">
+
+ <script language="BeanShell">
+ <locale lang="en">
+ <displayname value="Interactive BeanShell"/>
+ <description>
+ Pops up a window into which you can type BeanShell code and run it against the current document
+ </description>
+ </locale>
+ <functionname value="interactive.bsh"/>
+ <logicalname value="Interactive.BeanShell"/>
+ </script>
+
+</parcel>
diff --git a/scripting/examples/beanshell/MemoryUsage/memusage.bsh b/scripting/examples/beanshell/MemoryUsage/memusage.bsh
new file mode 100644
index 000000000..3929f6435
--- /dev/null
+++ b/scripting/examples/beanshell/MemoryUsage/memusage.bsh
@@ -0,0 +1,137 @@
+/*
+ * 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 .
+ */
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.Type;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.document.XEmbeddedObjectSupplier;
+import com.sun.star.awt.ActionEvent;
+import com.sun.star.awt.Rectangle;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.beans.PropertyValue;
+
+import com.sun.star.container.*;
+import com.sun.star.chart.*;
+import com.sun.star.table.*;
+import com.sun.star.sheet.*;
+
+import com.sun.star.script.provider.XScriptContext;
+
+createSpreadsheet()
+{
+ loader = (XComponentLoader)
+ UnoRuntime.queryInterface(
+ XComponentLoader.class, XSCRIPTCONTEXT.getDesktop());
+
+ comp = loader.loadComponentFromURL(
+ "private:factory/scalc", "_blank", 4, new PropertyValue[0]);
+
+ doc = (XSpreadsheetDocument)
+ UnoRuntime.queryInterface(XSpreadsheetDocument.class, comp);
+
+ index = (XIndexAccess)
+ UnoRuntime.queryInterface(XIndexAccess.class, doc.getSheets());
+
+ sheet = (XSpreadsheet) AnyConverter.toObject(
+ new Type(com.sun.star.sheet.XSpreadsheet.class), index.getByIndex(0));
+
+ return sheet;
+}
+
+addData(sheet, date, total, free)
+{
+ // set the labels
+ sheet.getCellByPosition(0, 0).setFormula("Used");
+ sheet.getCellByPosition(0, 1).setFormula("Free");
+ sheet.getCellByPosition(0, 2).setFormula("Total");
+
+ // set the values in the cells
+ sheet.getCellByPosition(1, 0).setValue(total - free);
+ sheet.getCellByPosition(1, 1).setValue(free);
+ sheet.getCellByPosition(1, 2).setValue(total);
+}
+
+addChart(sheet)
+{
+ rect = new Rectangle();
+ rect.X = 500;
+ rect.Y = 3000;
+ rect.Width = 10000;
+ rect.Height = 8000;
+
+ range = (XCellRange) UnoRuntime.queryInterface(XCellRange.class, sheet);
+ myRange = range.getCellRangeByName("A1:B2");
+
+ rangeAddr = (XCellRangeAddressable)
+ UnoRuntime.queryInterface(XCellRangeAddressable.class, myRange);
+
+ myAddr = rangeAddr.getRangeAddress();
+
+ CellRangeAddress[] addr = new CellRangeAddress[1];
+ addr[0] = myAddr;
+
+ supp = (XTableChartsSupplier)
+ UnoRuntime.queryInterface( XTableChartsSupplier.class, sheet);
+ charts = supp.getCharts();
+ charts.addNewByName("Example", rect, addr, false, true);
+
+ try { Thread.sleep(3000); } catch (java.lang.InterruptedException e) { }
+
+ // get the diagram and Change some of the properties
+ chartsAccess = (XNameAccess)
+ UnoRuntime.queryInterface( XNameAccess.class, charts);
+
+ tchart = (XTableChart)
+ UnoRuntime.queryInterface(
+ XTableChart.class, chartsAccess.getByName("Example"));
+
+ eos = (XEmbeddedObjectSupplier)
+ UnoRuntime.queryInterface( XEmbeddedObjectSupplier.class, tchart );
+ xifc = eos.getEmbeddedObject();
+
+ xChart = (XChartDocument)
+ UnoRuntime.queryInterface(XChartDocument.class, xifc);
+
+ xDocMSF = (XMultiServiceFactory)
+ UnoRuntime.queryInterface(XMultiServiceFactory.class, xChart);
+
+ diagObject = xDocMSF.createInstance("com.sun.star.chart.PieDiagram");
+ xDiagram = (XDiagram)
+ UnoRuntime.queryInterface(XDiagram.class, diagObject);
+ xChart.setDiagram(xDiagram);
+
+ propset = (XPropertySet)
+ UnoRuntime.queryInterface( XPropertySet.class, xChart.getTitle() );
+ propset.setPropertyValue("String", "JVM Memory Usage");
+}
+
+runtime = Runtime.getRuntime();
+generator = new Random();
+date = new Date();
+
+// allocate a random number of bytes so that the data changes
+len = (int)(generator.nextFloat() * runtime.freeMemory() / 5);
+bytes = new byte[len];
+
+sheet = createSpreadsheet();
+addData(sheet, date.toString(), runtime.totalMemory(), runtime.freeMemory());
+addChart(sheet);
+
+return 0;
diff --git a/scripting/examples/beanshell/MemoryUsage/parcel-descriptor.xml b/scripting/examples/beanshell/MemoryUsage/parcel-descriptor.xml
new file mode 100644
index 000000000..46c7ce422
--- /dev/null
+++ b/scripting/examples/beanshell/MemoryUsage/parcel-descriptor.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="BeanShell" xmlns:parcel="scripting.dtd">
+
+ <script language="BeanShell">
+ <locale lang="en">
+ <displayname value="BeanShell JVM Usage"/>
+ <description>
+ Updates a spreadsheet with the current memory usage statistics for the Java Virtual Machine
+ </description>
+ </locale>
+ <functionname value="memusage.bsh"/>
+ <logicalname value="MemoryUsage.BeanShell"/>
+ </script>
+
+</parcel>
diff --git a/scripting/examples/beanshell/WordCount/parcel-descriptor.xml b/scripting/examples/beanshell/WordCount/parcel-descriptor.xml
new file mode 100644
index 000000000..5887e4991
--- /dev/null
+++ b/scripting/examples/beanshell/WordCount/parcel-descriptor.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="BeanShell" xmlns:parcel="scripting.dtd">
+
+ <script language="BeanShell">
+ <locale lang="en">
+ <displayname value="Word Count"/>
+ <description>
+ Provides a word count of the selected text in A Writer document.
+ </description>
+ </locale>
+ <functionname value="wordcount.bsh"/>
+ <logicalname value="WordCount.BeanShell"/>
+ </script>
+
+</parcel>
diff --git a/scripting/examples/beanshell/WordCount/wordcount.bsh b/scripting/examples/beanshell/WordCount/wordcount.bsh
new file mode 100644
index 000000000..b068d8a7d
--- /dev/null
+++ b/scripting/examples/beanshell/WordCount/wordcount.bsh
@@ -0,0 +1,82 @@
+/*
+ * 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 .
+ */
+
+//Provides a word count of the selected text in a Writer document.
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XModel;
+import com.sun.star.view.XSelectionSupplier;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.text.XText;
+import com.sun.star.text.XTextRange;
+import com.sun.star.script.provider.XScriptContext;
+
+// display the count in a Swing dialog
+void doDisplay(numWords) {
+ wordsLabel = new JLabel("Word count = " + numWords);
+ closeButton = new JButton("Close");
+ frame = new JFrame("Word Count");
+ closeButton.addActionListener(new ActionListener() {
+ actionPerformed(ActionEvent e) {
+ frame.setVisible(false);
+ }
+ });
+ frame.getContentPane().setLayout(new BorderLayout());
+ frame.getContentPane().add(wordsLabel, BorderLayout.CENTER);
+ frame.getContentPane().add(closeButton, BorderLayout.SOUTH);
+ frame.pack();
+ frame.setSize(190,90);
+ frame.setLocation(430,430);
+ frame.setVisible(true);
+}
+
+int wordcount() {
+
+ result = 0;
+
+ // iterate through each of the selections
+ count = xIndexAccess.getCount();
+ for(i=0;i<count;i++) {
+ // get the XTextRange of the selection
+ xTextRange = (XTextRange)
+ UnoRuntime.queryInterface(XTextRange.class, xIndexAccess.getByIndex(i));
+ //System.out.println("string: "+xTextRange.getString());
+ // use the standard J2SE delimiters to tokenize the string
+ // obtained from the XTextRange
+ strTok = new StringTokenizer(xTextRange.getString());
+ result += strTok.countTokens();
+ }
+
+ doDisplay(result);
+ return result;
+}
+
+// The XSCRIPTCONTEXT variable is of type XScriptContext and is available to
+// all BeanShell scripts executed by the Script Framework
+xModel = (XModel)
+ UnoRuntime.queryInterface(XModel.class, XSCRIPTCONTEXT.getDocument());
+//the writer controller impl supports the css.view.XSelectionSupplier interface
+xSelectionSupplier = (XSelectionSupplier)
+ UnoRuntime.queryInterface(XSelectionSupplier.class, xModel.getCurrentController());
+//see section 7.5.1 of developers' guide
+// the getSelection provides an XIndexAccess to the one or more selections
+xIndexAccess = (XIndexAccess)
+ UnoRuntime.queryInterface(XIndexAccess.class, xSelectionSupplier.getSelection());
+
+count = wordcount();
+System.out.println("count = "+count);
+return 0;
diff --git a/scripting/examples/beanshell/Writer/ChangeFont.bsh b/scripting/examples/beanshell/Writer/ChangeFont.bsh
new file mode 100644
index 000000000..7cbea8fc3
--- /dev/null
+++ b/scripting/examples/beanshell/Writer/ChangeFont.bsh
@@ -0,0 +1,36 @@
+/*
+ * 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/.
+ */
+
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XModel;
+import com.sun.star.container.XEnumeration;
+import com.sun.star.container.XEnumerationAccess;
+
+import com.sun.star.text.XTextDocument;
+
+oDoc = UnoRuntime.queryInterface(XModel.class,XSCRIPTCONTEXT.getInvocationContext());
+if ( oDoc == null )
+ oDoc = XSCRIPTCONTEXT.getDocument();
+
+xTextDoc = (XTextDocument) UnoRuntime.queryInterface(XTextDocument.class,oDoc);
+xText = xTextDoc.getText();
+XEnumerationAccess xEnumAcc = (XEnumerationAccess)(UnoRuntime.queryInterface(XEnumerationAccess.class, xText));
+XEnumeration xEnum = xEnumAcc.createEnumeration();
+while (xEnum.hasMoreElements()) {
+ Object xObj = xEnum.nextElement();
+ XServiceInfo xServiceInfo = (XServiceInfo) UnoRuntime.queryInterface(XServiceInfo.class, xObj);
+ if (xServiceInfo.supportsService("com.sun.star.text.Paragraph")) {
+ XPropertySet xSet = UnoRuntime.queryInterface(XPropertySet.class, xServiceInfo );
+ xSet.setPropertyValue( "CharHeight", 28 );
+ xSet.setPropertyValue( "CharFontName", "Liberation Sans" );
+ }
+}
+
+return 0;
diff --git a/scripting/examples/beanshell/Writer/ChangeParaAdjust.bsh b/scripting/examples/beanshell/Writer/ChangeParaAdjust.bsh
new file mode 100644
index 000000000..db5e5b66a
--- /dev/null
+++ b/scripting/examples/beanshell/Writer/ChangeParaAdjust.bsh
@@ -0,0 +1,37 @@
+/*
+ * 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/.
+ */
+
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XModel;
+import com.sun.star.container.XEnumeration;
+import com.sun.star.container.XEnumerationAccess;
+
+import com.sun.star.text.XTextDocument;
+import com.sun.star.text.XText;
+
+oDoc = UnoRuntime.queryInterface(XModel.class,XSCRIPTCONTEXT.getInvocationContext());
+if ( oDoc == null )
+ oDoc = XSCRIPTCONTEXT.getDocument();
+
+xTextDoc = (XTextDocument) UnoRuntime.queryInterface(XTextDocument.class,oDoc);
+xText = xTextDoc.getText();
+XEnumerationAccess xEnumAcc = (XEnumerationAccess)(UnoRuntime.queryInterface(XEnumerationAccess.class, xText));
+XEnumeration xEnum = xEnumAcc.createEnumeration();
+while (xEnum.hasMoreElements()) {
+ Object xObj = xEnum.nextElement();
+ XServiceInfo xServiceInfo = (XServiceInfo) UnoRuntime.queryInterface(XServiceInfo.class, xObj);
+ if (xServiceInfo.supportsService("com.sun.star.text.Paragraph")) {
+ XPropertySet xSet = UnoRuntime.queryInterface(XPropertySet.class, xServiceInfo );
+ // Set the justification to be center justified
+ xSet.setPropertyValue( "ParaAdjust", com.sun.star.style.ParagraphAdjust.CENTER );
+ }
+}
+
+return 0;
diff --git a/scripting/examples/beanshell/Writer/InsertTable.bsh b/scripting/examples/beanshell/Writer/InsertTable.bsh
new file mode 100644
index 000000000..099c45e68
--- /dev/null
+++ b/scripting/examples/beanshell/Writer/InsertTable.bsh
@@ -0,0 +1,32 @@
+/*
+ * 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/.
+ */
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XModel;
+import com.sun.star.lang.XMultiServiceFactory;
+
+import com.sun.star.text.XTextDocument;
+import com.sun.star.text.XText;
+import com.sun.star.text.XTextContent;
+import com.sun.star.text.XTextTable;
+
+oDoc = UnoRuntime.queryInterface(XModel.class,XSCRIPTCONTEXT.getInvocationContext());
+if ( oDoc == null )
+ oDoc = XSCRIPTCONTEXT.getDocument();
+
+XMultiServiceFactory xDocMSF = (XMultiServiceFactory) UnoRuntime.queryInterface(XMultiServiceFactory.class, oDoc);
+Object oTab = xDocMSF.createInstance("com.sun.star.text.TextTable");
+XTextTable xTextTable = (XTextTable)UnoRuntime.queryInterface(XTextTable.class, oTab);
+xTextTable.initialize(4,3); // four rows, three columns
+xTextContent = (XTextContent)UnoRuntime.queryInterface(XTextContent.class, xTextTable);
+
+xTextDoc = (XTextDocument) UnoRuntime.queryInterface(XTextDocument.class,oDoc);
+xText = (XText) UnoRuntime.queryInterface(XText.class, xTextDoc.getText());
+xText.insertTextContent(xText.getEnd(), xTextContent, false);
+
+return 0;
diff --git a/scripting/examples/beanshell/Writer/InsertText.bsh b/scripting/examples/beanshell/Writer/InsertText.bsh
new file mode 100644
index 000000000..a1cfd3566
--- /dev/null
+++ b/scripting/examples/beanshell/Writer/InsertText.bsh
@@ -0,0 +1,28 @@
+/*
+ * 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/.
+ */
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XModel;
+
+import com.sun.star.text.XTextDocument;
+import com.sun.star.text.XText;
+import com.sun.star.text.XTextRange;
+
+oDoc = UnoRuntime.queryInterface(XModel.class,XSCRIPTCONTEXT.getInvocationContext());
+if ( oDoc == null )
+ oDoc = XSCRIPTCONTEXT.getDocument();
+
+String sText = "This text is inserted before the existing text\n" +
+ "Here comes a second line\n";
+
+xTextDoc = (XTextDocument) UnoRuntime.queryInterface(XTextDocument.class,oDoc);
+xText = xTextDoc.getText();
+xTextRange = xText.getEnd();
+xTextRange.setString(sText);
+
+return 0;
diff --git a/scripting/examples/beanshell/Writer/SetText.bsh b/scripting/examples/beanshell/Writer/SetText.bsh
new file mode 100644
index 000000000..99f267c63
--- /dev/null
+++ b/scripting/examples/beanshell/Writer/SetText.bsh
@@ -0,0 +1,21 @@
+/*
+ * 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/.
+ */
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XModel;
+
+import com.sun.star.text.XTextDocument;
+
+oDoc = UnoRuntime.queryInterface(XModel.class,XSCRIPTCONTEXT.getInvocationContext());
+if ( oDoc == null )
+ oDoc = XSCRIPTCONTEXT.getDocument();
+
+xTextDoc = (XTextDocument) UnoRuntime.queryInterface(XTextDocument.class,oDoc);
+xTextDoc.getText().setString("Hello from Beanshell!");
+
+return 0;
diff --git a/scripting/examples/beanshell/Writer/parcel-descriptor.xml b/scripting/examples/beanshell/Writer/parcel-descriptor.xml
new file mode 100644
index 000000000..e0f034b3d
--- /dev/null
+++ b/scripting/examples/beanshell/Writer/parcel-descriptor.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><parcel xmlns:parcel="scripting.dtd" language="BeanShell">
+<script language="BeanShell"><locale lang="en"><displayname value="InsertText.bsh"/><description>InsertText.bsh</description></locale><logicalname value="InsertText.bsh"/><functionname value="InsertText.bsh"/></script><script language="BeanShell"><locale lang="en"><displayname value="SetText.bsh"/><description>SetText.bsh</description></locale><logicalname value="SetText.bsh"/><functionname value="SetText.bsh"/></script><script language="BeanShell"><locale lang="en"><displayname value="InsertTable.bsh"/><description>InsertTable.bsh</description></locale><logicalname value="InsertTable.bsh"/><functionname value="InsertTable.bsh"/></script><script language="BeanShell"><locale lang="en"><displayname value="ChangeParaAdjust.bsh"/><description>ChangeParaAdjust.bsh</description></locale><logicalname value="ChangeParaAdjust.bsh"/><functionname value="ChangeParaAdjust.bsh"/></script><script language="BeanShell"><locale lang="en"><displayname value="ChangeFont.bsh"/><description>ChangeFont.bsh</description></locale><logicalname value="ChangeFont.bsh"/><functionname value="ChangeFont.bsh"/></script></parcel> \ No newline at end of file
diff --git a/scripting/examples/java/HelloWorld/HelloWorld.java b/scripting/examples/java/HelloWorld/HelloWorld.java
new file mode 100644
index 000000000..1c960da32
--- /dev/null
+++ b/scripting/examples/java/HelloWorld/HelloWorld.java
@@ -0,0 +1,42 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+import com.sun.star.script.provider.XScriptContext;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.text.XTextDocument;
+import com.sun.star.text.XTextRange;
+import com.sun.star.text.XText;
+/**
+ * HelloWorld class
+ *
+ */
+public class HelloWorld {
+ public static void printHW(XScriptContext xSc) {
+
+ // getting the text document object
+ XTextDocument xtextdocument = (XTextDocument) UnoRuntime.queryInterface(
+ XTextDocument.class, xSc.getDocument());
+ XText xText = xtextdocument.getText();
+ XTextRange xTextRange = xText.getEnd();
+ xTextRange.setString("Hello World (in Java)");
+
+ }// printHW
+
+}
diff --git a/scripting/examples/java/HelloWorld/parcel-descriptor.xml b/scripting/examples/java/HelloWorld/parcel-descriptor.xml
new file mode 100644
index 000000000..57e2e04c9
--- /dev/null
+++ b/scripting/examples/java/HelloWorld/parcel-descriptor.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="Java" xmlns:parcel="scripting.dtd">
+ <script language="Java">
+ <locale lang="en">
+ <displayname value="HelloWorld.Java"/>
+ <description>
+ Prints "Hello World".
+ </description>
+ </locale>
+ <functionname value="org.libreoffice.example.java_scripts.HelloWorld.printHW"/>
+ <logicalname value="HelloWorld.printHW"/>
+ <languagedepprops>
+ <prop name="classpath" value="HelloWorld.jar"/>
+ </languagedepprops>
+ </script>
+</parcel>
diff --git a/scripting/examples/java/Highlight/HighlightText.java b/scripting/examples/java/Highlight/HighlightText.java
new file mode 100644
index 000000000..f39ccbfa2
--- /dev/null
+++ b/scripting/examples/java/Highlight/HighlightText.java
@@ -0,0 +1,233 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.script.provider.XScriptContext;
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lang.EventObject;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.text.XTextDocument;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.script.XLibraryContainer;
+import com.sun.star.awt.*;
+import com.sun.star.util.*;
+
+import java.awt.Color;
+
+public class HighlightText implements com.sun.star.awt.XActionListener {
+
+ // UNO awt components of the Highlight dialog
+ XDialog findDialog = null;
+ XTextComponent findTextBox;
+
+ // The document being searched
+ XTextDocument theDocument;
+
+ // The text to be searched for
+ private String searchKey = "";
+
+ public void showForm(XScriptContext context) {
+ System.err.println("Starting showForm");
+
+ XMultiComponentFactory xmcf =
+ context.getComponentContext().getServiceManager();
+
+ Object[] args = new Object[1];
+ args[0] = context.getDocument();
+
+ Object obj;
+
+ try {
+ obj = xmcf.createInstanceWithArgumentsAndContext(
+ "com.sun.star.awt.DialogProvider", args,
+ context.getComponentContext());
+ } catch (com.sun.star.uno.Exception e) {
+ System.err.println("Error getting DialogProvider object");
+ return;
+ }
+
+ XDialogProvider xDialogProvider = (XDialogProvider)
+ UnoRuntime.queryInterface(XDialogProvider.class, obj);
+
+ System.err.println("Got DialogProvider, now get dialog");
+
+ try {
+ findDialog = xDialogProvider.createDialog(
+ "vnd.sun.star.script:" +
+ "ScriptBindingLibrary.Highlight?location=application");
+ } catch (java.lang.Exception e) {
+ System.err.println("Got exception on first creating dialog: " +
+ e.getMessage());
+ }
+
+ if (findDialog == null) {
+ if (!tryLoadingLibrary(xmcf, context, "Dialog") ||
+ !tryLoadingLibrary(xmcf, context, "Script")) {
+ System.err.println("Error loading ScriptBindingLibrary");
+ return;
+ }
+
+ try {
+ findDialog = xDialogProvider.createDialog(
+ "vnd.sun.star.script://" +
+ "ScriptBindingLibrary.Highlight?location=application");
+ } catch (com.sun.star.lang.IllegalArgumentException iae) {
+ System.err.println("Error loading ScriptBindingLibrary");
+ return;
+ }
+ }
+
+ XControlContainer controls = (XControlContainer)
+ UnoRuntime.queryInterface(XControlContainer.class, findDialog);
+
+ XButton highlightButton = (XButton) UnoRuntime.queryInterface(
+ XButton.class, controls.getControl("HighlightButton"));
+ highlightButton.setActionCommand("Highlight");
+
+ findTextBox = (XTextComponent) UnoRuntime.queryInterface(
+ XTextComponent.class, controls.getControl("HighlightTextField"));
+
+ XButton exitButton = (XButton) UnoRuntime.queryInterface(
+ XButton.class, controls.getControl("ExitButton"));
+ exitButton.setActionCommand("Exit");
+
+ theDocument = (XTextDocument) UnoRuntime.queryInterface(
+ XTextDocument.class, context.getDocument());
+
+ highlightButton.addActionListener(this);
+ exitButton.addActionListener(this);
+
+ findDialog.execute();
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.ActionCommand.equals("Exit")) {
+ findDialog.endExecute();
+ return;
+ } else if (e.ActionCommand.equals("Highlight")) {
+ searchKey = findTextBox.getText();
+
+ // highlight the text in red
+ Color cRed = new Color(255, 0, 0);
+ int red = cRed.getRGB();
+
+ XReplaceable replaceable = (XReplaceable)
+ UnoRuntime.queryInterface(XReplaceable.class, theDocument);
+
+ XReplaceDescriptor descriptor =
+ (XReplaceDescriptor) replaceable.createReplaceDescriptor();
+
+ // Gets a XPropertyReplace object for altering the properties
+ // of the replaced text
+ XPropertyReplace xPropertyReplace = (XPropertyReplace)
+ UnoRuntime.queryInterface(XPropertyReplace.class, descriptor);
+
+ // Sets the replaced text property fontweight value to Bold
+ PropertyValue wv = new PropertyValue("CharWeight", -1,
+ new Float(com.sun.star.awt.FontWeight.BOLD),
+ com.sun.star.beans.PropertyState.DIRECT_VALUE);
+
+ // Sets the replaced text property color value to RGB parameter
+ PropertyValue cv = new PropertyValue("CharColor", -1,
+ Integer.valueOf(red),
+ com.sun.star.beans.PropertyState.DIRECT_VALUE);
+
+ // Apply the properties
+ PropertyValue[] props = new PropertyValue[] { cv, wv };
+
+ try {
+ xPropertyReplace.setReplaceAttributes(props);
+
+ // Only matches whole words and case sensitive
+ descriptor.setPropertyValue(
+ "SearchCaseSensitive", Boolean.TRUE);
+ descriptor.setPropertyValue("SearchWords", Boolean.TRUE);
+ } catch (com.sun.star.beans.UnknownPropertyException upe) {
+ System.err.println("Error setting up search properties");
+ return;
+ } catch (com.sun.star.beans.PropertyVetoException pve) {
+ System.err.println("Error setting up search properties");
+ return;
+ } catch (com.sun.star.lang.WrappedTargetException wte) {
+ System.err.println("Error setting up search properties");
+ return;
+ } catch (com.sun.star.lang.IllegalArgumentException iae) {
+ System.err.println("Error setting up search properties");
+ return;
+ }
+
+ // Replaces all instances of searchKey with new Text properties
+ // and gets the number of instances of the searchKey
+ descriptor.setSearchString(searchKey);
+ descriptor.setReplaceString(searchKey);
+ replaceable.replaceAll(descriptor);
+ }
+ }
+
+ public void disposing(EventObject o) {
+ // do nothing
+ }
+
+ private boolean tryLoadingLibrary(
+ XMultiComponentFactory xmcf, XScriptContext context, String name) {
+ System.err.println("Try to load ScriptBindingLibrary");
+
+ try {
+ Object obj = xmcf.createInstanceWithContext(
+ "com.sun.star.script.Application" + name + "LibraryContainer",
+ context.getComponentContext());
+
+ XLibraryContainer xLibraryContainer = (XLibraryContainer)
+ UnoRuntime.queryInterface(XLibraryContainer.class, obj);
+
+ System.err.println("Got XLibraryContainer");
+
+ Object serviceObj = context.getComponentContext().getValueByName(
+ "/singletons/com.sun.star.util.theMacroExpander");
+
+ XMacroExpander xme = (XMacroExpander) AnyConverter.toObject(
+ new Type(XMacroExpander.class), serviceObj);
+
+ String bootstrapName = "bootstraprc";
+
+ if (System.getProperty("os.name").startsWith("Windows")) {
+ bootstrapName = "bootstrap.ini";
+ }
+
+ String libURL = xme.expandMacros(
+ "$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR/basic/ScriptBindingLibrary/" +
+ name.toLowerCase() + ".xlb/");
+
+ System.err.println("libURL is: " + libURL);
+
+ xLibraryContainer.createLibraryLink(
+ "ScriptBindingLibrary", libURL, false);
+
+ System.err.println("liblink created");
+
+ } catch (com.sun.star.uno.Exception e) {
+ System.err.println("Got an exception loading lib: " + e.getMessage());
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/scripting/examples/java/Highlight/parcel-descriptor.xml b/scripting/examples/java/Highlight/parcel-descriptor.xml
new file mode 100644
index 000000000..bf3a86f94
--- /dev/null
+++ b/scripting/examples/java/Highlight/parcel-descriptor.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="Java" xmlns:parcel="scripting.dtd">
+ <script language="Java">
+ <locale lang="en">
+ <displayname value="HighlightText.showForm"/>
+ <description>
+ Text highlighting
+ </description>
+ </locale>
+ <functionname value="org.libreoffice.example.java_scripts.HighlightText.showForm"/>
+ <logicalname value="HighlightText.showForm"/>
+ <languagedepprops>
+ <prop name="classpath" value="Highlight.jar"/>
+ </languagedepprops>
+ </script>
+</parcel>
diff --git a/scripting/examples/java/MemoryUsage/MemoryUsage.java b/scripting/examples/java/MemoryUsage/MemoryUsage.java
new file mode 100644
index 000000000..a01d2bace
--- /dev/null
+++ b/scripting/examples/java/MemoryUsage/MemoryUsage.java
@@ -0,0 +1,157 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+import java.util.Random;
+import java.util.Date;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.XInterface;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.document.XEmbeddedObjectSupplier;
+import com.sun.star.awt.Rectangle;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.beans.PropertyValue;
+
+import com.sun.star.container.*;
+import com.sun.star.chart.*;
+import com.sun.star.table.*;
+import com.sun.star.sheet.*;
+
+import com.sun.star.script.provider.XScriptContext;
+
+public class MemoryUsage {
+ public void updateMemoryUsage(XScriptContext ctxt)
+ throws Exception {
+ XSpreadsheet sheet = createSpreadsheet(ctxt);
+
+ Runtime runtime = Runtime.getRuntime();
+ Random generator = new Random();
+ Date date = new Date();
+
+ // allocate a random amount of memory
+ int len = (int)(generator.nextFloat() * runtime.freeMemory() / 5);
+ byte[] bytes = new byte[len];
+
+ addData(sheet, date.toString(),
+ runtime.totalMemory(), runtime.freeMemory());
+
+ addChart(sheet);
+ }
+
+ private XSpreadsheet createSpreadsheet(XScriptContext ctxt)
+ throws Exception {
+ XComponentLoader loader = (XComponentLoader)
+ UnoRuntime.queryInterface(
+ XComponentLoader.class, ctxt.getDesktop());
+
+ XComponent comp = loader.loadComponentFromURL(
+ "private:factory/scalc", "_blank", 4, new PropertyValue[0]);
+
+ XSpreadsheetDocument doc = (XSpreadsheetDocument)
+ UnoRuntime.queryInterface(XSpreadsheetDocument.class, comp);
+
+ XIndexAccess index = (XIndexAccess)
+ UnoRuntime.queryInterface(XIndexAccess.class, doc.getSheets());
+
+ XSpreadsheet sheet = (XSpreadsheet) AnyConverter.toObject(
+ new Type(com.sun.star.sheet.XSpreadsheet.class), index.getByIndex(0));
+
+ return sheet;
+ }
+
+ private void addData(
+ XSpreadsheet sheet, String date, long total, long free)
+ throws Exception {
+ sheet.getCellByPosition(0, 0).setFormula("Used");
+ sheet.getCellByPosition(0, 1).setFormula("Free");
+ sheet.getCellByPosition(0, 2).setFormula("Total");
+
+ sheet.getCellByPosition(1, 0).setValue(total - free);
+ sheet.getCellByPosition(1, 1).setValue(free);
+ sheet.getCellByPosition(1, 2).setValue(total);
+ }
+
+ private void addChart(XSpreadsheet sheet)
+ throws Exception {
+ Rectangle rect = new Rectangle();
+ rect.X = 500;
+ rect.Y = 3000;
+ rect.Width = 10000;
+ rect.Height = 8000;
+
+ XCellRange range = (XCellRange)
+ UnoRuntime.queryInterface(XCellRange.class, sheet);
+
+ XCellRange myRange =
+ range.getCellRangeByName("A1:B2");
+
+ XCellRangeAddressable rangeAddr = (XCellRangeAddressable)
+ UnoRuntime.queryInterface(XCellRangeAddressable.class, myRange);
+
+ CellRangeAddress myAddr = rangeAddr.getRangeAddress();
+
+ CellRangeAddress[] addr = new CellRangeAddress[1];
+ addr[0] = myAddr;
+
+ XTableChartsSupplier supp = (XTableChartsSupplier)
+ UnoRuntime.queryInterface(XTableChartsSupplier.class, sheet);
+
+ XTableCharts charts = supp.getCharts();
+ charts.addNewByName("Example", rect, addr, false, true);
+
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e) { }
+
+ // get the diagram and Change some of the properties
+ XNameAccess chartsAccess = (XNameAccess)
+ UnoRuntime.queryInterface(XNameAccess.class, charts);
+
+ XTableChart tchart = (XTableChart)
+ UnoRuntime.queryInterface(
+ XTableChart.class, chartsAccess.getByName("Example"));
+
+ XEmbeddedObjectSupplier eos = (XEmbeddedObjectSupplier)
+ UnoRuntime.queryInterface(XEmbeddedObjectSupplier.class, tchart);
+
+ XInterface xifc = eos.getEmbeddedObject();
+
+ XChartDocument xChart = (XChartDocument)
+ UnoRuntime.queryInterface(XChartDocument.class, xifc);
+
+ XMultiServiceFactory xDocMSF = (XMultiServiceFactory)
+ UnoRuntime.queryInterface(XMultiServiceFactory.class, xChart);
+
+ Object diagObject =
+ xDocMSF.createInstance("com.sun.star.chart.PieDiagram");
+
+ XDiagram xDiagram = (XDiagram)
+ UnoRuntime.queryInterface(XDiagram.class, diagObject);
+
+ xChart.setDiagram(xDiagram);
+
+ XPropertySet propset = (XPropertySet)
+ UnoRuntime.queryInterface(XPropertySet.class, xChart.getTitle());
+ propset.setPropertyValue("String", "JVM Memory Usage");
+ }
+}
diff --git a/scripting/examples/java/MemoryUsage/parcel-descriptor.xml b/scripting/examples/java/MemoryUsage/parcel-descriptor.xml
new file mode 100644
index 000000000..eb55ffe9a
--- /dev/null
+++ b/scripting/examples/java/MemoryUsage/parcel-descriptor.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="Java" xmlns:parcel="scripting.dtd">
+ <script language="Java">
+ <locale lang="en">
+ <displayname value="MemoryUtils.MemUsage"/>
+ <description>
+ Text highlighting
+ </description>
+ </locale>
+ <functionname value="org.libreoffice.example.java_scripts.MemoryUsage.updateMemoryUsage"/>
+ <logicalname value="MemoryUtils.MemUsage"/>
+ <languagedepprops>
+ <prop name="classpath" value="MemoryUsage.jar"/>
+ </languagedepprops>
+ </script>
+</parcel>
diff --git a/scripting/examples/java/Newsgroup/MimeConfiguration.java b/scripting/examples/java/Newsgroup/MimeConfiguration.java
new file mode 100644
index 000000000..03b964834
--- /dev/null
+++ b/scripting/examples/java/Newsgroup/MimeConfiguration.java
@@ -0,0 +1,211 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.script.framework.runtime.XScriptContext;
+import com.sun.star.util.XStringSubstitution;
+
+import javax.mail.*;
+import javax.activation.*;
+
+import java.io.*;
+
+
+public class MimeConfiguration {
+
+ // Office Installation path
+ private static String instPath = "";
+
+
+ public static boolean createFiles(XScriptContext xsc) {
+ try {
+ XComponentContext xcc = xsc.getComponentContext();
+ XMultiComponentFactory xmf = xcc.getServiceManager();
+
+ Object pathSub =
+ xmf.createInstanceWithContext("com.sun.star.comp.framework.PathSubstitution",
+ xcc);
+ XStringSubstitution stringSub = (XStringSubstitution) UnoRuntime.queryInterface(
+ XStringSubstitution.class, pathSub);
+ instPath = stringSub.getSubstituteVariableValue("$(inst)");
+
+ } catch (com.sun.star.beans.UnknownPropertyException upe) {
+ System.out.println("com.sun.star.beans.UnknownPropertyException");
+ upe.printStackTrace();
+ } catch (com.sun.star.uno.Exception e) {
+ System.out.println("com.sun.star.uno.Exception");
+ e.printStackTrace();
+ }
+
+ writeMailCap();
+ writeMimeTypes();
+
+ // ToDo: include status feedback to StatusWindow
+ return true;
+ }
+
+
+
+
+ private static void writeMailCap() {
+ String mailcapPath = getConfigDir() + System.getProperty("file.separator") +
+ "mailcap";
+
+ try {
+ if (! new File(java.net.URLDecoder.decode(mailcapPath)).exists()) {
+ File mailcapFile = new File(mailcapPath);
+ FileWriter out = new FileWriter(mailcapFile);
+ String[] lines = getMailcapText();
+
+ for (int i = 0; i < lines.length; i++) {
+ out.write(lines[i], 0, lines[i].length());
+ }
+
+ out.close();
+ } else {
+ }
+
+
+
+ // use prog dir, if not there then java.io to create/write new file
+ MailcapCommandMap map = new MailcapCommandMap(mailcapPath);
+ CommandMap.setDefaultCommandMap(map);
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ private static String[] getMailcapText() {
+ String[] mailcapText = {
+ "#\n",
+ "# Default mailcap file for the JavaMail System.\n",
+ "#\n",
+ "# JavaMail content-handlers:\n",
+ "#\n",
+ "text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain\n",
+ "text/html;; x-java-content-handler=com.sun.mail.handlers.text_html\n",
+ "text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml\n",
+ "image/gif;; x-java-content-handler=com.sun.mail.handlers.image_gif\n",
+ "image/jpeg;; x-java-content-handler=com.sun.mail.handlers.image_jpeg\n",
+ "multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed\n",
+ "message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822\n"
+ };
+
+ return mailcapText;
+ }
+
+
+
+ private static void writeMimeTypes() {
+ String mimetypesPath = getConfigDir() + System.getProperty("file.separator") +
+ "mimetypes.default";
+
+ try {
+ if (! new File(java.net.URLDecoder.decode(mimetypesPath)).exists()) {
+ File mimetypesFile = new File(mimetypesPath);
+ FileWriter out = new FileWriter(mimetypesFile);
+ String[] lines = getMimeTypesText();
+
+ for (int i = 0; i < lines.length; i++) {
+ out.write(lines[i], 0, lines[i].length());
+ }
+
+ out.close();
+ } else {
+ }
+
+ MimetypesFileTypeMap mimeTypes = new MimetypesFileTypeMap(mimetypesPath);
+ FileTypeMap.setDefaultFileTypeMap(mimeTypes);
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ private static String[] getMimeTypesText() {
+ String[] mimesText = {
+ "#\n",
+ "# A simple, old format, mime.types file\n",
+ "#\n",
+ "text/html html htm HTML HTM\n",
+ "text/plain txt text TXT TEXT\n",
+ "image/gif gif GIF\n",
+ "image/ief ief\n",
+ "image/jpeg jpeg jpg jpe JPG\n",
+ "image/tiff tiff tif\n",
+ "image/x-xwindowdump xwd\n",
+ "application/postscript ai eps ps\n",
+ "application/rtf rtf\n",
+ "application/x-tex tex\n",
+ "application/x-texinfo texinfo texi\n",
+ "application/x-troff t tr roff\n",
+ "audio/basic au\n",
+ "audio/midi midi mid\n",
+ "audio/x-aifc aifc\n",
+ "audio/x-aiff aif aiff\n",
+ "audio/x-mpeg mpeg mpg\n",
+ "audio/x-wav wav\n",
+ "video/mpeg mpeg mpg mpe\n",
+ "video/quicktime qt mov\n",
+ "video/x-msvideo avi\n"
+ };
+
+ return mimesText;
+ }
+
+
+ private static String getConfigDir() {
+ // mailcap file must be written to the Office user/config directory
+
+ // instPath is a URL, needs to be converted to a system pathname
+ String config = instPath + "/user/config";
+ String configNonURL = "";
+
+ if (System.getProperty("os.name").indexOf("Windows") != -1) {
+ // Windows
+ // removes "file:///"
+ int start = 8;
+ configNonURL = config.substring(start, config.length());
+
+ // Convert forward to back-slashes
+ while (configNonURL.indexOf("/") != -1) {
+ int fSlash = configNonURL.indexOf("/");
+ String firstPart = configNonURL.substring(0, fSlash);
+ String secondPart = configNonURL.substring(fSlash + 1, configNonURL.length());
+ configNonURL = firstPart + "\\" + secondPart;
+ }
+ } else {
+ // Unix/Linux
+ // removes "file://"
+ int start = 7;
+ configNonURL = config.substring(start, config.length());
+ }
+
+ return configNonURL;
+ }
+
+}
diff --git a/scripting/examples/java/Newsgroup/NewsGroup.java b/scripting/examples/java/Newsgroup/NewsGroup.java
new file mode 100644
index 000000000..4c1708a05
--- /dev/null
+++ b/scripting/examples/java/Newsgroup/NewsGroup.java
@@ -0,0 +1,39 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+public class NewsGroup {
+
+ private String hostname = "";
+ private String newsgroupName = "";
+
+ public NewsGroup(String host, String group) {
+ hostname = host;
+ newsgroupName = group;
+ }
+
+ public String getHostName() {
+ return hostname;
+ }
+
+ public String getNewsgroupName() {
+ return newsgroupName;
+ }
+
+}
diff --git a/scripting/examples/java/Newsgroup/OfficeAttachment.java b/scripting/examples/java/Newsgroup/OfficeAttachment.java
new file mode 100644
index 000000000..75c0f4d45
--- /dev/null
+++ b/scripting/examples/java/Newsgroup/OfficeAttachment.java
@@ -0,0 +1,250 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+//import com.sun.star.frame.XComponentLoader;
+import java.io.*;
+import com.sun.star.lang.XComponent;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.frame.XStorable;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XModel;
+import com.sun.star.script.framework.runtime.XScriptContext;
+
+// for debug only
+import javax.swing.JOptionPane;
+
+public class OfficeAttachment {
+
+ private StatusWindow status = null;
+ private XStorable storedDoc = null;
+ private File htmlFile = null;
+ private File officeFile = null;
+ private boolean isHtmlDoc = false;
+ private boolean isOfficeDoc = false;
+ private String templocationURL = "";
+ private String templocationSystem = "";
+ private String attachmentName = "";
+ private String statusLine = "";
+
+ public OfficeAttachment(XScriptContext xsc, StatusWindow sw, boolean html,
+ boolean office) {
+ status = sw;
+ isHtmlDoc = html;
+ isOfficeDoc = office;
+
+ templocationSystem = templocationURL = System.getProperty("user.home");
+
+ if (System.getProperty("os.name").indexOf("Windows") != -1) {
+ while (templocationURL.indexOf("\\") != -1) {
+ int sepPos = templocationURL.indexOf("\\");
+ String firstPart = templocationURL.substring(0, sepPos);
+ String lastPart = templocationURL.substring(sepPos + 1,
+ templocationURL.length());
+ templocationURL = firstPart + "/" + lastPart;
+ }
+ }
+
+ try {
+ statusLine = "Querying Office for current document";
+ status.setStatus(1, statusLine);
+ XScriptContext scriptcontext = xsc;
+ XModel xmodel = scriptcontext.getDocument();
+ storedDoc = (XStorable) UnoRuntime.queryInterface(XStorable.class, xmodel);
+ // find document name from storedDoc
+ attachmentName = storedDoc.getLocation();
+ } catch (Exception e) {
+ //UNO error
+ status.setStatus(1, "Error: " + statusLine);
+ }
+
+ if (attachmentName.equalsIgnoreCase("")) {
+ attachmentName = "Attachment";
+ } else {
+ int lastSep = attachmentName.lastIndexOf("/");
+ attachmentName = attachmentName.substring(lastSep + 1, attachmentName.length());
+ int dot = attachmentName.indexOf(".");
+ attachmentName = attachmentName.substring(0, dot);
+ }
+ }
+
+
+ public boolean createTempDocs() {
+ String filenameURL = "file:///" + templocationURL + "/" + attachmentName;
+
+ try {
+ if (isHtmlDoc) {
+ statusLine = "Saving doc in HTML format";
+ status.setStatus(4, statusLine);
+ PropertyValue[] propertyvalue_html = new PropertyValue[2];
+ propertyvalue_html[0] = new PropertyValue();
+ propertyvalue_html[0].Name = "Overwrite";
+ propertyvalue_html[0].Value = Boolean.TRUE;
+ propertyvalue_html[1] = new PropertyValue();
+ propertyvalue_html[1].Name = ("FilterName");
+ propertyvalue_html[1].Value = "swriter: HTML (StarWriter)";
+ storedDoc.storeAsURL(filenameURL + ".html", propertyvalue_html);
+
+ File homedir = new File(templocationSystem);
+ File homefiles[] = homedir.listFiles();
+ String file = "";
+
+ for (int i = 0; i < homefiles.length; i++) {
+ if (homefiles[i].getName().equals(attachmentName + ".html")) {
+ file = homefiles[i].getAbsolutePath();
+ }
+ }
+
+ htmlFile = new File(file);
+ }
+
+ if (isOfficeDoc) {
+ statusLine = "Saving doc in .sxw format";
+ status.setStatus(4, statusLine);
+ PropertyValue[] propertyvalue_sxw = new PropertyValue[2];
+ propertyvalue_sxw[0] = new PropertyValue();
+ propertyvalue_sxw[0].Name = "Overwrite";
+ propertyvalue_sxw[0].Value = Boolean.TRUE;
+ propertyvalue_sxw[1] = new PropertyValue();
+ propertyvalue_sxw[1].Name = "Overwrite";
+ propertyvalue_sxw[1].Value = Boolean.TRUE;
+ storedDoc.storeAsURL(filenameURL + ".sxw", propertyvalue_sxw);
+
+ File homedir = new File(templocationSystem);
+
+ File homefiles[] = homedir.listFiles();
+ String file = "";
+
+ for (int i = 0; i < homefiles.length; i++) {
+ if (homefiles[i].getName().equals(attachmentName + ".sxw")) {
+ file = homefiles[i].getAbsolutePath();
+ }
+ }
+
+ officeFile = new File(file);
+ }
+
+ } catch (SecurityException se) {
+ status.setStatus(4, "Error: " + statusLine);
+ System.out.println("Security error while saving temporary Document(s). Check file permissions in home directory.");
+ se.printStackTrace();
+ htmlFile = null;
+ officeFile = null;
+ return false;
+ } catch (Exception e) {
+ status.setStatus(4, "Error: " + statusLine);
+ System.out.println("Error saving temporary Document(s)");
+ e.printStackTrace();
+ htmlFile = null;
+ officeFile = null;
+ return false;
+ }
+
+ return true;
+ }
+
+
+ public boolean removeTempDocs() {
+ /*
+ if( !htmlFile.exists() && !officeFile.exists() )
+ {
+ System.out.println("Error: Document(s) have not been saved." );
+ }
+ */
+
+ statusLine = "Removing temp docs";
+ status.setStatus(13, statusLine);
+
+ try {
+ if (isOfficeDoc && isHtmlDoc) {
+ htmlFile.delete();
+ officeFile.delete();
+ } else {
+ if (isOfficeDoc) {
+ officeFile.delete();
+ } else {
+ htmlFile.delete();
+ }
+ }
+ } catch (SecurityException se) {
+ status.setStatus(13, "Error: " + statusLine);
+ System.out.println("Security Error while deleting temporary Document(s). Check file permissions in home directory.");
+ se.printStackTrace();
+ return false;
+ }
+
+ return true;
+ }
+
+
+ public void cleanUpOnError() {
+ try {
+ if (isOfficeDoc && isHtmlDoc) {
+ htmlFile.delete();
+ officeFile.delete();
+ } else {
+ if (isOfficeDoc) {
+ officeFile.delete();
+ } else {
+ htmlFile.delete();
+ }
+ }
+ } catch (SecurityException se) {
+ System.out.println("Security Error while deleting temporary Document(s). Check file permissions in home directory.");
+ se.printStackTrace();
+ }
+ }
+
+
+ public File[] getAttachments() {
+
+ statusLine = "Retrieving temp docs";
+ status.setStatus(8, statusLine);
+
+ File attachments[] = null;
+
+ if (isOfficeDoc && isHtmlDoc) {
+ attachments = new File[2];
+ attachments[0] = htmlFile;
+ attachments[1] = officeFile;
+ } else {
+ if (isOfficeDoc) {
+ attachments = new File[1];
+ attachments[0] = officeFile;
+ } else {
+ attachments = new File[1];
+ attachments[0] = htmlFile;
+ }
+ }
+
+ return attachments;
+ }
+
+
+ public boolean isHtmlAttachment() {
+ return isHtmlDoc;
+ }
+
+
+ public boolean isOfficeAttachment() {
+ return isOfficeDoc;
+ }
+
+}
diff --git a/scripting/examples/java/Newsgroup/PostNewsgroup.java b/scripting/examples/java/Newsgroup/PostNewsgroup.java
new file mode 100644
index 000000000..6c6ecdf37
--- /dev/null
+++ b/scripting/examples/java/Newsgroup/PostNewsgroup.java
@@ -0,0 +1,633 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import java.util.Vector;
+import com.sun.star.script.framework.runtime.XScriptContext;
+
+
+public class PostNewsgroup extends JFrame {
+
+ // Post to newsgroup objects
+ private NewsGroup[] subscribedNewsgroups = null;
+ private XScriptContext xscriptcontext = null;
+
+ private final int FRAMEX = 300;
+ private final int FRAMEY = 300;
+ private final int TEXTBOXWIDTH = 300;
+ private final int TEXTBOXHEIGHT = 24;
+ private final int TEXTAREAHEIGHT = 70;
+ private final int BUTTONWIDTH = 80;
+ private final int BUTTONHEIGHT = 30;
+
+ private PostNewsgroup window = null;
+ private JComboBox newsgroupComboBox = null;
+ private JTextField hostTextField = null;
+ private JTextField replyTextField = null;
+ private JTextField subjectTextField = null;
+ private JTextArea commentTextArea = null;
+ private JRadioButton officeHtmlButton = null;
+ private JRadioButton officeButton = null;
+ private JRadioButton htmlButton = null;
+ private JButton postButton = null;
+ private JButton cancelButton = null;
+
+ // JFrame for launch progress dialog
+ private StatusWindow statusWindow = null;
+ private String statusLine = "";
+
+ // Tool tip text
+ private final String newsgroupText = "Newsgroup name";
+ private final String hostText = "Newsgroup host/server name";
+ private final String replyText = "Email address to reply to";
+ private final String subjectText = "Subject title for the mail";
+ private final String commentText = "Additional comment on mail";
+ private final String officeHtmlText =
+ "Post as both Office and HTML attachments";
+ private final String officeText = "Post as Office attachment only";
+ private final String htmlText = "Post as HTML attachment only";
+ private final String postText = "Post to newsgroup";
+ private final String cancelText = "Cancel post to newsgroup";
+
+
+ public void post(XScriptContext xsc) {
+ xscriptcontext = xsc;
+ window = this;
+
+ // create mailcap and mimetypes files (fix for classloader problem)
+ MimeConfiguration.createFiles(xscriptcontext);
+
+ this.setTitle("Post Document To Newsgroup");
+ this.setLocation(FRAMEX, FRAMEY);
+
+ this.addFocusListener(new FocusAdapter() {
+ public void focusGained(FocusEvent event) {
+ System.out.println("Focus gained");
+ window.update(window.getGraphics());
+ }
+
+ public void focusLost(FocusEvent event) {
+ System.out.println("Focus lost");
+ }
+ });
+
+ Container container = getContentPane();
+ container.setLayout(new GridBagLayout());
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.fill = GridBagConstraints.BOTH;
+
+ JPanel labelPanel = constructLabelPanel();
+ JPanel textPanel = constructTextPanel();
+ JPanel optionPanel = constructOptionPanel();
+ JPanel buttonPanel = constructButtonPanel();
+
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 3;
+ constraints.insets = new Insets(15, 15, 5, 5);
+ container.add(labelPanel, constraints);
+
+ constraints.gridx = 1;
+ constraints.gridy = 0;
+ constraints.gridwidth = 4;
+ constraints.gridheight = 3;
+ constraints.insets = new Insets(15, 5, 5, 15);
+ container.add(textPanel, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 3;
+ constraints.gridwidth = 5;
+ constraints.gridheight = 1;
+ constraints.insets = new Insets(5, 15, 5, 15);
+ container.add(optionPanel, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 4;
+ constraints.gridwidth = 5;
+ constraints.gridheight = 1;
+ constraints.insets = new Insets(5, 5, 5, 5);
+ container.add(buttonPanel, constraints);
+
+ this.pack();
+ this.setResizable(false);
+ this.setVisible(true);
+ }
+
+
+ private JPanel constructLabelPanel() {
+ JLabel newsgroupLabel = new JLabel("Newsgroup:");
+ JLabel hostLabel = new JLabel("Host:");
+ JLabel replyLabel = new JLabel("Reply:");
+ JLabel subjectLabel = new JLabel("Subject:");
+ JLabel commentLabel = new JLabel("Comment:");
+
+ newsgroupLabel.setToolTipText(newsgroupText);
+ hostLabel.setToolTipText(hostText);
+ replyLabel.setToolTipText(replyText);
+ subjectLabel.setToolTipText(subjectText);
+ commentLabel.setToolTipText(commentText);
+
+ JPanel newsgroupPanel = new JPanel();
+ newsgroupPanel.setLayout(new BorderLayout());
+ newsgroupPanel.add(newsgroupLabel, "West");
+ JPanel hostPanel = new JPanel();
+ hostPanel.setLayout(new BorderLayout());
+ hostPanel.add(hostLabel, "West");
+ JPanel replyPanel = new JPanel();
+ replyPanel.setLayout(new BorderLayout());
+ replyPanel.add(replyLabel, "West");
+ JPanel subjectPanel = new JPanel();
+ subjectPanel.setLayout(new BorderLayout());
+ subjectPanel.add(subjectLabel, "West");
+ JPanel commentPanel = new JPanel();
+ commentPanel.setLayout(new BorderLayout());
+ commentPanel.add(commentLabel, "West");
+ JPanel emptyPanel = new JPanel();
+
+ final int labelWidth = 80;
+ newsgroupPanel.setPreferredSize(new Dimension(labelWidth, TEXTBOXHEIGHT));
+ hostPanel.setPreferredSize(new Dimension(labelWidth, TEXTBOXHEIGHT));
+ replyPanel.setPreferredSize(new Dimension(labelWidth, TEXTBOXHEIGHT));
+ subjectPanel.setPreferredSize(new Dimension(labelWidth, TEXTBOXHEIGHT));
+ commentPanel.setPreferredSize(new Dimension(labelWidth, TEXTBOXHEIGHT));
+
+ JPanel panel = new JPanel();
+ panel.setLayout(new GridBagLayout());
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.fill = GridBagConstraints.BOTH;
+ constraints.insets = new Insets(5, 5, 5, 5);
+
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.weightx = constraints.weighty = 0.0;
+ panel.add(newsgroupPanel, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 1;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ panel.add(hostPanel, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 2;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ panel.add(replyPanel, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 3;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ panel.add(subjectPanel, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 4;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ panel.add(commentPanel, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 5;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.weightx = constraints.weighty = 1.0;
+ panel.add(emptyPanel, constraints);
+
+ return panel;
+ }
+
+
+ private JPanel constructTextPanel() {
+ hostTextField = new JTextField();
+ hostTextField.setPreferredSize(new Dimension(TEXTBOXWIDTH, TEXTBOXHEIGHT));
+ hostTextField.setToolTipText(hostText);
+ hostTextField.setBorder(new EtchedBorder());
+
+ //optionPanel.setBorder( new TitledBorder( new EtchedBorder(), "Document Format" ) );
+ newsgroupComboBox = getNewsgroupCombo();
+
+ replyTextField = new JTextField();
+ replyTextField.setPreferredSize(new Dimension(TEXTBOXWIDTH, TEXTBOXHEIGHT));
+ replyTextField.setToolTipText(replyText);
+ replyTextField.setBorder(new EtchedBorder());
+
+ subjectTextField = new JTextField();
+ subjectTextField.setPreferredSize(new Dimension(TEXTBOXWIDTH, TEXTBOXHEIGHT));
+ subjectTextField.setToolTipText(subjectText);
+ subjectTextField.setBorder(new EtchedBorder());
+
+ commentTextArea = new JTextArea();
+ commentTextArea.setPreferredSize(new Dimension(TEXTBOXWIDTH, TEXTAREAHEIGHT));
+ commentTextArea.setToolTipText(commentText);
+ commentTextArea.setBorder(new EtchedBorder());
+
+ JPanel panel = new JPanel();
+ panel.setLayout(new GridBagLayout());
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.fill = GridBagConstraints.BOTH;
+ constraints.insets = new Insets(5, 5, 5, 5);
+
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ panel.add(newsgroupComboBox, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 1;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ panel.add(hostTextField, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 2;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ panel.add(replyTextField, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 3;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ panel.add(subjectTextField, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 4;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 2;
+ panel.add(commentTextArea, constraints);
+
+ return panel;
+ }
+
+
+ private JComboBox getNewsgroupCombo() {
+ newsgroupComboBox = new JComboBox();
+ //newsgroupComboBox.setBorder( new EtchedBorder() );
+
+ newsgroupComboBox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ // when newsgroup is selected
+ if (subscribedNewsgroups != null) {
+ int position = newsgroupComboBox.getSelectedIndex();
+
+ if (position != -1) {
+ hostTextField.setText(subscribedNewsgroups[ position ].getHostName());
+ newsgroupComboBox.setToolTipText("Newsgroup name: " +
+ subscribedNewsgroups[ position ].getNewsgroupName() + " (Host name: " +
+ subscribedNewsgroups[ position ].getHostName() + ")");
+ }
+ }
+ }
+ });
+
+ NewsGroup groupToSend = null;
+ SubscribedNewsgroups newsgroups = new SubscribedNewsgroups();
+ subscribedNewsgroups = newsgroups.getNewsGroups();
+
+ // Test for no .mozilla or no subscribed newsgroups
+ // subscribedNewsgroups = null;
+
+ if (subscribedNewsgroups == null) {
+ JOptionPane.showMessageDialog(window,
+ "No subscribed newsgroups found in mozilla/netscape profile \nPlease enter newsgroup and host name",
+ "Newsgroups Information", JOptionPane.INFORMATION_MESSAGE);
+ } else {
+ // Copy all newsgroups into a vector for comparison
+ // Alter entries (to include host name) if duplication is found
+ ArrayList vector = new ArrayList(subscribedNewsgroups.length);
+
+ for (int i = 0; i < subscribedNewsgroups.length; i++) {
+ vector.add(subscribedNewsgroups[i].getNewsgroupName());
+ }
+
+ // Compare and alter
+ for (int i = 0; i < subscribedNewsgroups.length; i++) {
+ // check if combo box already has a newsgroup with same name
+ // then add host name to differentiate
+ for (int j = 0; j < subscribedNewsgroups.length; j++) {
+ if (j != i
+ && subscribedNewsgroups[j].getNewsgroupName().equalsIgnoreCase(
+ subscribedNewsgroups[i].getNewsgroupName())) {
+ vector.set(j, subscribedNewsgroups[j].getNewsgroupName() + " (" +
+ subscribedNewsgroups[j].getHostName() + ")");
+ vector.set(i, subscribedNewsgroups[i].getNewsgroupName() + " (" +
+ subscribedNewsgroups[i].getHostName() + ")");
+ }
+ }
+ }
+
+ // Copy converted newsgroups from vector to combo box
+ for (int i = 0; i < subscribedNewsgroups.length; i++) {
+ newsgroupComboBox.addItem(vector.elementAt(i));
+ }
+ }// else
+
+ newsgroupComboBox.setPreferredSize(new Dimension(TEXTBOXWIDTH, TEXTBOXHEIGHT));
+ newsgroupComboBox.setEditable(true);
+
+ return newsgroupComboBox;
+ }
+
+
+
+ private JPanel constructOptionPanel() {
+ officeHtmlButton = new JRadioButton("Office and HTML", true);
+ officeHtmlButton.setToolTipText(officeHtmlText);
+
+ officeButton = new JRadioButton("Office");
+ officeButton.setToolTipText(officeText);
+
+ htmlButton = new JRadioButton("HTML");
+ htmlButton.setToolTipText(htmlText);
+
+ JRadioButton[] rbuttons = { officeHtmlButton, officeButton, htmlButton };
+ ButtonGroup radioButtonGroup = new ButtonGroup();
+
+ for (int i = 0; i < rbuttons.length; i++) {
+ radioButtonGroup.add(rbuttons[i]);
+ }
+
+ JPanel optionPanel = new JPanel();
+ optionPanel.setBorder(new TitledBorder(new EtchedBorder(), "Document Format"));
+ optionPanel.setLayout(new GridBagLayout());
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.fill = GridBagConstraints.BOTH;
+
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.insets = new Insets(5, 5, 5, 30);
+ optionPanel.add(officeHtmlButton, constraints);
+
+ constraints.gridx = 1;
+ constraints.gridy = 0;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.insets = new Insets(5, 20, 5, 30);
+ optionPanel.add(officeButton, constraints);
+
+ constraints.gridx = 2;
+ constraints.gridy = 0;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.insets = new Insets(5, 20, 5, 5);
+ optionPanel.add(htmlButton, constraints);
+
+ return optionPanel;
+ }
+
+
+
+ public boolean sendingActions() {
+ // posting actions
+ // Validate the data
+ if (isValidData()) {
+ // Create status window
+ StatusWindow statusWindow = new StatusWindow(window, "Posting to Newsgroup",
+ FRAMEX, FRAMEY);
+
+ statusWindow.setVisible(true);
+ statusLine = "Ready to send...";
+ statusWindow.setStatus(0, statusLine);
+
+ // Get the boolean values for HTML/Office document
+ // params: ( XScriptContext, StatusWindow, html document, office document )
+
+ boolean html = false;
+ boolean office = false;
+
+ if (officeHtmlButton.isSelected()) {
+ html = true;
+ office = true;
+ }
+
+ if (officeButton.isSelected()) {
+ office = true;
+ html = false;
+ }
+
+ if (htmlButton.isSelected()) {
+ html = true;
+ office = false;
+ }
+
+ OfficeAttachment officeAttach = new OfficeAttachment(xscriptcontext,
+ statusWindow, html, office);
+
+ statusLine = "Getting user input";
+ statusWindow.setStatus(2, statusLine);
+ // Get replyto, subject, comment from textboxes
+ String replyto = replyTextField.getText();
+ String subject = subjectTextField.getText();
+ String comment = commentTextArea.getText();
+
+ // Get newsgroup from combo box (corresponding position)
+ String host = "";
+ String group = "";
+ int position = newsgroupComboBox.getSelectedIndex();
+
+ if (subscribedNewsgroups == null || position == -1) {
+ host = hostTextField.getText();
+ group = newsgroupComboBox.getSelectedItem().toString();
+ } else {
+ host = subscribedNewsgroups[ position ].getHostName();
+ group = subscribedNewsgroups[ position ].getNewsgroupName();
+ }
+
+ statusLine = "Creating sender object";
+ statusWindow.setStatus(3, statusLine);
+ Sender sender = new Sender(statusWindow, officeAttach, replyto, subject,
+ comment, host, group);
+
+ if (!sender.sendMail()) {
+ statusWindow.enableCancelButton(true);
+ officeAttach.cleanUpOnError();
+ return false;
+ }
+
+ statusLine = "Send is complete";
+ statusWindow.setStatus(14, statusLine);
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ private JPanel constructButtonPanel() {
+ Action postAction = new AbstractAction() {
+ public void actionPerformed(ActionEvent event) {
+ // posting actions
+ sendingActions();
+ }// actionPerformed
+ };
+
+ Action cancelAction = new AbstractAction() {
+ public void actionPerformed(ActionEvent event) {
+ // cancelling actions
+ window.dispose();
+ }
+ };
+
+ postButton = new JButton();
+ postButton.setAction(postAction);
+ postButton.setToolTipText(postText);
+ postButton.setText("Post");
+ postButton.setPreferredSize(new Dimension(BUTTONWIDTH + 20, BUTTONHEIGHT));
+
+ cancelButton = new JButton();
+ cancelButton.setAction(cancelAction);
+ cancelButton.setToolTipText(cancelText);
+ cancelButton.setText("Cancel");
+ cancelButton.setPreferredSize(new Dimension(BUTTONWIDTH + 20, BUTTONHEIGHT));
+
+ JSeparator sep = new JSeparator(SwingConstants.HORIZONTAL);
+
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new GridBagLayout());
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.fill = GridBagConstraints.BOTH;
+ constraints.insets = new Insets(5, 5, 5, 5);
+
+ JPanel emptyPanel1 = new JPanel();
+ emptyPanel1.setPreferredSize(new Dimension(BUTTONWIDTH, BUTTONHEIGHT));
+
+ JPanel emptyPanel2 = new JPanel();
+ emptyPanel2.setPreferredSize(new Dimension(BUTTONWIDTH, BUTTONHEIGHT));
+
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.gridwidth = 4;
+ constraints.gridheight = 1;
+ buttonPanel.add(sep, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 1;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ buttonPanel.add(emptyPanel1, constraints);
+
+ constraints.gridx = 1;
+ constraints.gridy = 1;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ buttonPanel.add(emptyPanel2, constraints);
+
+ constraints.gridx = 2;
+ constraints.gridy = 1;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ buttonPanel.add(postButton, constraints);
+
+ constraints.gridx = 3;
+ constraints.gridy = 1;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.insets = new Insets(5, 5, 5, 0);
+ buttonPanel.add(cancelButton, constraints);
+
+ return buttonPanel;
+ }
+
+
+ public void enableButtons(boolean enable) {
+ if (enable) {
+ postButton.setEnabled(true);
+ cancelButton.setEnabled(true);
+ } else {
+ postButton.setEnabled(false);
+ cancelButton.setEnabled(false);
+ }
+ }
+
+
+ private boolean isValidData() {
+ // newsgroupComboBox must not be blank (format? dots and whitespace)
+ String newsgroupString = "";
+ int position = newsgroupComboBox.getSelectedIndex();
+
+ if (subscribedNewsgroups == null || position == -1) {
+ newsgroupString = newsgroupComboBox.getSelectedItem().toString();
+ } else {
+ newsgroupString = subscribedNewsgroups[ position ].getNewsgroupName();
+ }
+
+ if (newsgroupString.length() == 0) {
+ newsgroupComboBox.requestFocus();
+ JOptionPane.showMessageDialog(window, "Please enter a newsgroup name",
+ "Input Error", JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+
+
+ // hostTextField must not be blank (format?)
+ String hostString = hostTextField.getText();
+
+ if (hostString.length() == 0) {
+ hostTextField.requestFocus();
+ JOptionPane.showMessageDialog(window, "Please enter a hostname", "Input Error",
+ JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+
+
+ // replyTextField must have <string>@<string>.<string>
+ // (string at least 2 chars long)
+ // consider <s>.<s>@<s>.<s>.<s> format? (array of dot positions?)
+ String replyString = replyTextField.getText();
+ int atPos = replyString.indexOf("@");
+ int dotPos = replyString.lastIndexOf(".");
+ int length = replyString.length();
+
+ if (length == 0 || atPos == -1 || dotPos == -1 || atPos < 2 || dotPos < atPos
+ || dotPos + 2 == length || atPos + 2 == dotPos
+ || atPos != replyString.lastIndexOf("@") || replyString.indexOf(" ") != -1) {
+ replyTextField.requestFocus();
+ JOptionPane.showMessageDialog(window,
+ "Please enter a valid reply to email address", "Input Error",
+ JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+
+
+ // subjectTextField must not be blank?
+ String subjectString = subjectTextField.getText();
+
+ if (subjectString.length() == 0) {
+ subjectTextField.requestFocus();
+ JOptionPane.showMessageDialog(window, "Please enter subject title",
+ "Input Error", JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+
+ // details are valid
+ return true;
+ }
+
+}
diff --git a/scripting/examples/java/Newsgroup/Sender.java b/scripting/examples/java/Newsgroup/Sender.java
new file mode 100644
index 000000000..00b3db87b
--- /dev/null
+++ b/scripting/examples/java/Newsgroup/Sender.java
@@ -0,0 +1,141 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+import javax.mail.*;
+import javax.mail.internet.*;
+import com.msoft.mail.provider.nntp.NNTPTransport;
+import java.util.Properties;
+import java.io.*;
+import javax.activation.*;
+
+
+public class Sender {
+ // Constructor params:
+ private StatusWindow status = null;
+ private OfficeAttachment attachments = null;
+ private String replyto = "";
+ private String subject = "";
+ private String comment = "";
+ private String hostname = "";
+ private String newsgroup = "";
+ private String statusLine = "";
+
+
+
+ public Sender(StatusWindow sw, OfficeAttachment attach, String reply,
+ String sub, String com, String host, String group) {
+ status = sw;
+ attachments = attach;
+ replyto = reply;
+ subject = sub;
+ comment = com;
+ hostname = host;
+ newsgroup = group;
+ }
+
+
+
+ public boolean sendMail() {
+ int statusPos = 5;
+
+ try {
+ attachments.createTempDocs();
+ // Property for any information
+ Properties props = new Properties();
+
+ // Create unique session (null is unused authenticator info)
+ statusLine = "Creating unique session";
+ status.setStatus(statusPos, statusLine); // 5
+ Session session = Session.getInstance(props, null);
+
+ // Create message
+ statusPos++; // 6
+ statusLine = "Creating message";
+ status.setStatus(statusPos, statusLine);
+ MimeMessage message = new MimeMessage(session);
+ message.setFrom(new InternetAddress(replyto));
+ message.setSubject(subject);
+ message.setText(comment);
+ message.addHeader("Newsgroups", newsgroup);
+
+ // Buildup bodypart with text and attachments
+ Multipart multipart = new MimeMultipart();
+
+ BodyPart messageBodyPart = new MimeBodyPart();
+ messageBodyPart.setText(comment);
+ multipart.addBodyPart(messageBodyPart);
+
+ statusPos++; // 7
+ statusLine = "Adding attachment(s)";
+ status.setStatus(statusPos, statusLine);
+ File attachs[] = attachments.getAttachments();
+
+ for (int i = 0; i < attachs.length; i++) {
+ messageBodyPart = new MimeBodyPart();
+ DataSource filesource = new FileDataSource(attachs[i]);
+ messageBodyPart.setDataHandler(new DataHandler(filesource));
+ messageBodyPart.setFileName(attachs[i].getName());
+ multipart.addBodyPart(messageBodyPart);
+ }
+
+ // Add multipart to mail
+ message.setContent(multipart);
+
+ // Create and send NNTP transport
+ statusPos += 2; // 9
+ statusLine = "Creating NNTP transport";
+ status.setStatus(statusPos, statusLine);
+ Transport transport = new NNTPTransport(session,
+ new URLName("news:" + newsgroup));
+
+ // Null parameters are for user name and password
+ statusPos++; // 10
+ statusLine = "Connecting to mail server";
+ status.setStatus(statusPos, statusLine);
+ transport.connect(hostname, null, null);
+
+ statusPos++; // 11
+ statusLine = "Sending message";
+ status.setStatus(statusPos, statusLine);
+ transport.sendMessage(message, message.getAllRecipients());
+
+ statusPos++; // 12
+ statusLine = "Closing transport";
+ status.setStatus(statusPos, statusLine);
+ transport.close();
+
+ // Clean up when finished
+ attachments.removeTempDocs();
+
+ return true;
+ } catch (MessagingException me) {
+ if (statusPos == 10) {
+ statusLine = "Error connecting (User authentication?)";
+ }
+
+ status.setStatus(statusPos, statusLine);
+ System.out.println("Error sending message: ");
+ me.printStackTrace();
+ return false;
+ }
+
+ }
+
+}
diff --git a/scripting/examples/java/Newsgroup/StatusWindow.java b/scripting/examples/java/Newsgroup/StatusWindow.java
new file mode 100644
index 000000000..7b37c8fa7
--- /dev/null
+++ b/scripting/examples/java/Newsgroup/StatusWindow.java
@@ -0,0 +1,147 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+
+public class StatusWindow extends JFrame {
+
+ private JProgressBar progressBar = null;
+ private JTextField statusLabel = null;
+ private JButton cancelButton = null;
+ private JFrame statusWindow = null;
+ private PostNewsgroup mainWindow = null;
+
+ private final int MAXPROGRESS = 13;
+ private final int MINPROGRESS = 0;
+
+
+ public StatusWindow(PostNewsgroup mw, String title, int parentX, int parentY) {
+ this.setTitle(title);
+ this.setLocation(parentX + 100, parentY + 100);
+ statusWindow = this;
+ mainWindow = mw;
+
+ mainWindow.enableButtons(false);
+
+ statusWindow.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent event) {
+ mainWindow.enableButtons(true);
+ }
+ });
+
+ progressBar = new JProgressBar();
+ progressBar.setStringPainted(true);
+ progressBar.setMaximum(MAXPROGRESS);
+ progressBar.setMinimum(MINPROGRESS);
+ progressBar.setSize(30, 400);
+
+ JLabel progLabel = new JLabel("Progress:");
+
+ JPanel progressPanel = new JPanel();
+ progressPanel.setLayout(new BorderLayout(10, 0));
+ progressPanel.add(progLabel, "West");
+ progressPanel.add(progressBar, "East");
+
+ statusLabel = new JTextField();
+ statusLabel.setColumns(25);
+ statusLabel.setEditable(false);
+ statusLabel.setBorder(null);
+ JPanel statusPanel = new JPanel();
+ statusPanel.setLayout(new BorderLayout());
+ statusPanel.add(statusLabel, "West");
+
+ cancelButton = new JButton("Cancel");
+ cancelButton.setSize(30, 100);
+ cancelButton.setEnabled(false);
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event) {
+ // cancelling actions
+ mainWindow.enableButtons(true);
+ statusWindow.dispose();
+ }
+ });
+
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new BorderLayout(0, 5));
+ buttonPanel.add(cancelButton, "East");
+ buttonPanel.add(new JSeparator(SwingConstants.HORIZONTAL), "North");
+
+ Container container = getContentPane();
+ container.setLayout(new GridBagLayout());
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.fill = GridBagConstraints.BOTH;
+
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.insets = new Insets(15, 15, 10, 15);
+ container.add(progressPanel, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 1;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.insets = new Insets(10, 15, 10, 15);
+ container.add(statusPanel, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 2;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.insets = new Insets(10, 15, 5, 15);
+ container.add(buttonPanel, constraints);
+
+ this.pack();
+ this.setResizable(false);
+
+ }
+
+
+ public void setStatus(int progress, String status) {
+ progressBar.setValue(progress);
+ statusLabel.setText(status);
+ statusLabel.setToolTipText(status);
+
+ if (progress == MAXPROGRESS) {
+ cancelButton.setEnabled(true);
+ cancelButton.setText("Close");
+ }
+
+ update(getGraphics());
+ mainWindow.update(mainWindow.getGraphics());
+ }
+
+
+ public void enableCancelButton(boolean enable) {
+ if (enable) {
+ cancelButton.setEnabled(true);
+ cancelButton.setText("Finish");
+ } else {
+ cancelButton.setEnabled(false);
+ cancelButton.setText("Cancel");
+ }
+
+ }
+
+}
diff --git a/scripting/examples/java/Newsgroup/SubscribedNewsgroups.java b/scripting/examples/java/Newsgroup/SubscribedNewsgroups.java
new file mode 100644
index 000000000..eb135a3e8
--- /dev/null
+++ b/scripting/examples/java/Newsgroup/SubscribedNewsgroups.java
@@ -0,0 +1,349 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+import java.io.*;
+import java.util.Vector;
+
+
+public class SubscribedNewsgroups {
+
+
+ private static NewsGroup[] allSubscribed = null;
+ private static boolean windows = false;
+
+ public static void main(String[] args) {
+ // Test the class
+ SubscribedNewsgroups subscribed = new SubscribedNewsgroups();
+
+ NewsGroup allGroups[] = subscribed.getNewsGroups();
+
+ if (allGroups == null) {
+ System.out.println("Could not find subscribed newsgroups from mozilla/netscape mailrc files");
+ } else {
+ for (int i = 0; i < allGroups.length; i++) {
+ System.out.println("Hostname is: " + allGroups[i].getHostName() +
+ " Newsgroup is: " + allGroups[i].getNewsgroupName());
+ }
+ }
+ }
+
+
+
+ // Only public method of the class
+ // Returns and array of unique NewsGroup objects
+ public NewsGroup[] getNewsGroups() {
+ windows = false;
+
+ if (System.getProperty("os.name").indexOf("Windows") != -1) {
+ windows = true;
+ }
+
+ String mozillaHome = "";
+
+ if (windows) {
+ mozillaHome = System.getProperty("user.home") +
+ System.getProperty("file.separator") + "Application Data" +
+ System.getProperty("file.separator") + "Mozilla" +
+ System.getProperty("file.separator") + "Profiles";
+ } else {
+ mozillaHome = System.getProperty("user.home") +
+ System.getProperty("file.separator") + ".mozilla";
+ }
+
+ if (!new File(mozillaHome).isDirectory()) {
+ return null;
+ }
+
+ // Get all the profiles belonging to the user
+ File profiles[] = findProfiles(new File(mozillaHome));
+
+ if (profiles.length < 1) {
+ return null;
+ }
+
+ // Get the News directory for each profile
+ File allNewsDirs[] = new File[ profiles.length ];
+
+ for (int i = 0; i < profiles.length; i++) {
+ File newsDir = findNewsDir(profiles[i]);
+ allNewsDirs[i] = newsDir;
+ }
+
+ // Check that at least one News directory exists and remove nulls
+ boolean newsFound = false;
+
+ for (int i = 0; i < allNewsDirs.length; i++) {
+ if (allNewsDirs[i] != null) {
+ newsFound = true;
+ break;
+ }
+ }
+
+ if (!newsFound) {
+ return null;
+ }
+
+ // Get all the mailrc files for each News directory
+ File allMailrcs[] = findMailrcFiles(allNewsDirs);
+
+ if (allMailrcs == null) {
+ return null;
+ }
+
+ ArrayList<NewsGroup> subscribed = new ArrayList<NewsGroup>();
+
+ // Get the newsgroups in each mailrc file
+ for (int i = 0; i < allMailrcs.length; i++) {
+ File mailrc = (File) allMailrcs[i];
+ NewsGroup newsgroup[] = findNewsgroups(mailrc);
+
+ //if the Newsgroup has not already been added to the list
+ for (int j = 0; j < newsgroup.length; j++) {
+ // if newsgroup is unique then add to the list
+ if (!listed(newsgroup[j], subscribed)) {
+ subscribed.addElement(newsgroup[j]);
+ }
+ }
+ }
+
+ // Copy all unique Newsgroups into the global array
+ allSubscribed = new NewsGroup[ subscribed.size() ];
+ subscribed.toArray(allSubscribed);
+
+ // Test that at least one subscribed newsgroup has been found
+ if (allSubscribed.length < 1) {
+ return null;
+ }
+
+ return allSubscribed;
+ }
+
+
+
+
+ // Tests if the NewsGroup object has already been listed by another mailrc file
+ private static boolean listed(NewsGroup newsgroup,
+ ArrayList<NewsGroup> uniqueSubscription) {
+ for (int i = 0; i < uniqueSubscription.size(); i++) {
+ NewsGroup tempGroup = uniqueSubscription.elementAt(i);
+
+ // Test for duplication
+ if (newsgroup.getHostName().equalsIgnoreCase(tempGroup.getHostName()) &&
+ newsgroup.getNewsgroupName().equalsIgnoreCase(tempGroup.getNewsgroupName()))
+ return true;
+ }
+
+ return false;
+ }
+
+
+
+
+ // Finds all the NewsGroups in an individual mailrc file
+ private static NewsGroup[] findNewsgroups(File mailrcfile) {
+
+ String hostname = "";
+ String newsgroup = "";
+ NewsGroup mailrcNewsGroups[] = null;
+
+ //Retrieve name of news host/server from file name
+ //Sequentially access each of the newsgroups
+ //If the newsgroup is not already contained in the global NewsGroup[] array then add it
+
+ String filename = mailrcfile.getPath();
+
+ if (windows) {
+ // Windows format "staroffice-news.germany.sun.com.rc"
+ int hostNameStart = filename.lastIndexOf("\\") + 1;
+ int hostNameEnd = filename.indexOf(".rc");
+ hostname = filename.substring(hostNameStart, hostNameEnd);
+ } else {
+ // Unix/Linux format "newsrc-staroffice-news.germany.sun.com"
+ int hostNameStart = filename.lastIndexOf("newsrc-") + 7;
+ hostname = filename.substring(hostNameStart, filename.length());
+ }
+
+ // Assumes the content format in Window is the same as Unix/Linux (unknown at the moment)
+ // i.e. a list of newsgroups each ending with a ":"
+ LineNumberReader in = null;
+
+ try {
+ in = new LineNumberReader(new FileReader(mailrcfile));
+ ArrayList groups = new ArrayList();
+ String inString = "";
+ int line = 0;
+
+ while (inString != null) {
+ in.setLineNumber(line);
+ inString = in.readLine();
+ line++;
+
+ if (inString != null) {
+ int newsgroupEnd = inString.indexOf(":");
+ newsgroup = inString.substring(0, newsgroupEnd);
+ NewsGroup group = new NewsGroup(hostname, newsgroup);
+ groups.addElement(group);
+ }
+ }
+
+ mailrcNewsGroups = new NewsGroup[ groups.size() ];
+ groups.copyInto(mailrcNewsGroups);
+ in.close();
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+
+ return mailrcNewsGroups;
+ }
+
+
+ // Finds all the mailrc files for all the given News directories
+ private static File[] findMailrcFiles(File[] newsDirs) {
+ ArrayList allFiles = new ArrayList();
+
+ for (int i = 0; i < newsDirs.length; i++) {
+ if (newsDirs[i] != null) {
+ File mailrcFiles[] = newsDirs[i].listFiles(new VersionFilter());
+
+ if (mailrcFiles != null) {
+ for (int j = 0; j < mailrcFiles.length; j++) {
+ allFiles.addElement(mailrcFiles[j]);
+ }
+ }
+ }
+ }
+
+ File allMailrcFiles[] = new File[ allFiles.size() ];
+ allFiles.copyInto(allMailrcFiles);
+
+ if (allMailrcFiles.length == 0) {
+ return null;
+ }
+
+ return allMailrcFiles;
+ }
+
+
+ // Finds all profiles belonging to one user (can be more than one)
+ private static File[] findProfiles(File start) {
+ // Get all files and directories in .mozilla
+ File allFiles[] = start.listFiles();
+ File[] dirs = new File[allFiles.length];
+ int dirCounter = 0;
+
+ // Remove files leaving directories only
+ for (int i = 0; i < allFiles.length; i++) {
+ if (allFiles[i].isDirectory()) {
+ dirs[dirCounter] = allFiles[i];
+ dirCounter++;
+ }
+ }
+
+ // Add each directory to a user profile array
+ File[] profileDirs = new File[dirCounter];
+
+ for (int i = 0; i < dirCounter; i++) {
+ profileDirs[i] = dirs[i];
+ }
+
+ // return a File array containing the profile dirs
+ return profileDirs;
+ }
+
+
+ // Recursively searches for the News directory for a given profile directory
+ private static File findNewsDir(File start) {
+ File mailrcFile = null;
+
+ // File array containing all matches for the version filter ("News")
+ File files[] = start.listFiles(new VersionFilter());
+
+ // If the array is empty then no matches were found
+ if (files.length == 0) {
+ // File array of all the directories in File start
+ File dirs[] = start.listFiles(new DirFilter());
+
+ // for each of the directories check for a match
+ for (int i = 0; i < dirs.length; i++) {
+ mailrcFile = findNewsDir(dirs[i]);
+
+ if (mailrcFile != null) {
+ // break the for loop
+ break;
+ }
+ }
+ } else {
+ // end recursion
+ // Check for a News directory inside the News directory (fix for bug)
+ // Original solution had only "mailrcFile = files[0];"
+
+ boolean noChildNews = true;
+ File checkChildNewsDirs[] = files[0].listFiles(new VersionFilter());
+
+ if (checkChildNewsDirs != null) {
+ for (int i = 0; i < checkChildNewsDirs.length; i++) {
+ if (checkChildNewsDirs[i].getName().equals("News")) {
+ noChildNews = false;
+ break;
+ }
+ }
+ }
+
+ if (noChildNews) {
+ mailrcFile = files[0];
+ } else {
+ String childNewsPathName = files[0].getAbsolutePath() +
+ System.getProperty("file.separator") + "News";
+ mailrcFile = new File(childNewsPathName);
+ }
+
+ }
+
+ // return a File representing the News dir in a profile
+ return mailrcFile;
+ }
+}
+
+
+
+class DirFilter implements FileFilter {
+ public boolean accept(File aFile) {
+ return aFile.isDirectory();
+ }
+}
+
+
+class VersionFilter implements FileFilter {
+ public boolean accept(File aFile) {
+ if (System.getProperty("os.name").indexOf("Windows") != -1) {
+ if (aFile.getName().compareToIgnoreCase("News") == 0 ||
+ aFile.getName().indexOf(".rc") != -1) {
+ return true;
+ }
+ } else {
+ if (aFile.getName().compareToIgnoreCase("News") == 0 ||
+ aFile.getName().indexOf("newsrc") != -1) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/scripting/examples/java/debugger/DebugRunner.java b/scripting/examples/java/debugger/DebugRunner.java
new file mode 100644
index 000000000..a3b4869fe
--- /dev/null
+++ b/scripting/examples/java/debugger/DebugRunner.java
@@ -0,0 +1,87 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLDecoder;
+
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.script.framework.provider.PathUtils;
+import com.sun.star.script.provider.XScriptContext;
+
+public class DebugRunner {
+
+ private static final String FILE_URL_PREFIX =
+ System.getProperty("os.name").startsWith("Windows") == true ?
+ "file:///" : "file://";
+
+ public void go(final XScriptContext xsctxt, String language, String uri,
+ String filename) {
+
+ OOScriptDebugger debugger;
+ String path = "";
+
+ if (language.equals("JavaScript")) {
+ debugger = new OORhinoDebugger();
+ } else if (language.equals("BeanShell")) {
+ debugger = new OOBeanShellDebugger();
+ } else {
+ return;
+ }
+
+ if (uri.startsWith(FILE_URL_PREFIX)) {
+ uri = URLDecoder.decode(uri);
+ String s = uri.substring(FILE_URL_PREFIX.length());
+ File f = new File(s);
+
+ if (f.exists()) {
+ if (f.isDirectory()) {
+ if (!filename.equals("")) {
+ path = new File(f, filename).getAbsolutePath();
+ }
+ } else {
+ path = f.getAbsolutePath();
+ }
+ }
+
+ debugger.go(xsctxt, path);
+ } else {
+ if (!uri.endsWith("/")) {
+ uri += "/";
+ }
+
+ String script = uri + filename;
+ InputStream is;
+
+ try {
+ is = PathUtils.getScriptFileStream(
+ script, xsctxt.getComponentContext());
+
+ if (is != null) {
+ debugger.go(xsctxt, is);
+ }
+ } catch (IOException ioe) {
+ System.out.println("Error loading script: " + script);
+ }
+ }
+ }
+}
diff --git a/scripting/examples/java/debugger/OOBeanShellDebugger.java b/scripting/examples/java/debugger/OOBeanShellDebugger.java
new file mode 100644
index 000000000..68a508784
--- /dev/null
+++ b/scripting/examples/java/debugger/OOBeanShellDebugger.java
@@ -0,0 +1,393 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+import javax.swing.JFrame;
+import javax.swing.JTextArea;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+import javax.swing.text.Document;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.DocumentEvent;
+
+import java.awt.FlowLayout;
+import java.awt.Graphics;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.Dimension;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import com.sun.star.script.provider.XScriptContext;
+import bsh.Interpreter;
+
+public class OOBeanShellDebugger implements OOScriptDebugger, ActionListener,
+ DocumentListener {
+
+ private JFrame frame;
+ private JTextArea ta;
+ private GlyphGutter gg;
+ private XScriptContext context;
+ private int currentPosition = -1;
+ private int linecount;
+ private Interpreter sessionInterpreter;
+ private Thread execThread = null;
+ private String filename = null;
+
+ /* Entry point for script execution */
+ public void go(XScriptContext context, String filename) {
+ if (filename != null && filename != "") {
+ try {
+ FileInputStream fis = new FileInputStream(filename);
+ this.filename = filename;
+ go(context, fis);
+ } catch (IOException ioe) {
+ JOptionPane.showMessageDialog(frame,
+ "Error loading file: " + ioe.getMessage(),
+ "Error", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+
+ /* Entry point for script execution */
+ public void go(XScriptContext context, InputStream in) {
+ this.context = context;
+ initUI();
+
+ if (in != null) {
+ try {
+ loadFile(in);
+ } catch (IOException ioe) {
+ JOptionPane.showMessageDialog(frame,
+ "Error loading stream: " + ioe.getMessage(),
+ "Error", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+
+ public void loadFile(InputStream in) throws IOException {
+
+ /* Remove ourselves as a DocumentListener while loading the file
+ so we don't get a storm of DocumentEvents during loading */
+ ta.getDocument().removeDocumentListener(this);
+
+ byte[] contents = new byte[1024];
+ int len = 0, pos = 0;
+
+ while ((len = in.read(contents, 0, 1024)) != -1) {
+ ta.insert(new String(contents, 0, len), pos);
+ pos += len;
+ }
+
+ try {
+ in.close();
+ } catch (IOException ignore) {
+ }
+
+ /* Update the GlyphGutter and add back the DocumentListener */
+ gg.update();
+ ta.getDocument().addDocumentListener(this);
+ }
+
+ private void initUI() {
+ frame = new JFrame("BeanShell Debug Window");
+ ta = new JTextArea();
+ ta.setRows(15);
+ ta.setColumns(40);
+ ta.setLineWrap(false);
+ linecount = ta.getLineCount();
+
+ gg = new GlyphGutter(this);
+
+ final JScrollPane sp = new JScrollPane();
+ sp.setViewportView(ta);
+ sp.setRowHeaderView(gg);
+
+ ta.getDocument().addDocumentListener(this);
+ String[] labels = {"Run", "Clear", "Save", "Close"};
+ JPanel p = new JPanel();
+ p.setLayout(new FlowLayout());
+
+ for (int i = 0; i < labels.length; i++) {
+ JButton b = new JButton(labels[i]);
+ b.addActionListener(this);
+ p.add(b);
+
+ if (labels[i].equals("Save") && filename == null) {
+ b.setEnabled(false);
+ }
+ }
+
+ frame.getContentPane().add(sp, "Center");
+ frame.getContentPane().add(p, "South");
+ frame.pack();
+ frame.show();
+ }
+
+ /* Implementation of DocumentListener interface */
+ public void insertUpdate(DocumentEvent e) {
+ doChanged(e);
+ }
+
+ public void removeUpdate(DocumentEvent e) {
+ doChanged(e);
+ }
+
+ public void changedUpdate(DocumentEvent e) {
+ doChanged(e);
+ }
+
+ /* If the number of lines in the JTextArea has changed then update the
+ GlyphGutter */
+ public void doChanged(DocumentEvent e) {
+ if (linecount != ta.getLineCount()) {
+ gg.update();
+ linecount = ta.getLineCount();
+ }
+ }
+
+ private void startExecution() {
+ execThread = new Thread() {
+ public void run() {
+ Interpreter interpreter = new Interpreter();
+ interpreter.getNameSpace().clear();
+
+ // reset position and repaint gutter so no red arrow appears
+ currentPosition = -1;
+ gg.repaint();
+
+ try {
+ interpreter.set("context", context);
+ interpreter.eval(ta.getText());
+ } catch (bsh.EvalError err) {
+ currentPosition = err.getErrorLineNumber() - 1;
+
+ try {
+ // scroll to line of the error
+ int line = ta.getLineStartOffset(currentPosition);
+ Rectangle rect = ta.modelToView(line);
+ ta.scrollRectToVisible(rect);
+ } catch (Exception e) {
+ // couldn't scroll to line, do nothing
+ }
+
+ gg.repaint();
+
+ JOptionPane.showMessageDialog(frame, "Error at line " +
+ String.valueOf(err.getErrorLineNumber()) +
+ "\n\n: " + err.getErrorText(),
+ "Error", JOptionPane.ERROR_MESSAGE);
+ } catch (Exception e) {
+ JOptionPane.showMessageDialog(frame,
+ "Error: " + e.getMessage(),
+ "Error", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ };
+ execThread.start();
+ }
+
+ private void promptForSaveName() {
+ JFileChooser chooser = new JFileChooser();
+ chooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
+ public boolean accept(File f) {
+ if (f.isDirectory() || f.getName().endsWith(".bsh")) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public String getDescription() {
+ return ("BeanShell files: *.bsh");
+ }
+ });
+
+ int ret = chooser.showSaveDialog(frame);
+
+ if (ret == JFileChooser.APPROVE_OPTION) {
+ filename = chooser.getSelectedFile().getAbsolutePath();
+
+ if (!filename.endsWith(".bsh")) {
+ filename += ".bsh";
+ }
+ }
+
+ }
+
+ private void saveTextArea() {
+ if (filename == null) {
+ promptForSaveName();
+ }
+
+ FileOutputStream fos = null;
+
+ if (filename != null) {
+ try {
+ File f = new File(filename);
+ fos = new FileOutputStream(f);
+ String s = ta.getText();
+ fos.write(s.getBytes(), 0, s.length());
+ } catch (IOException ioe) {
+ JOptionPane.showMessageDialog(frame,
+ "Error saving file: " + ioe.getMessage(),
+ "Error", JOptionPane.ERROR_MESSAGE);
+ } finally {
+ if (fos != null) {
+ try {
+ fos.close();
+ } catch (IOException ignore) {
+ }
+ }
+ }
+ }
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getActionCommand().equals("Run")) {
+ startExecution();
+ } else if (e.getActionCommand().equals("Close")) {
+ frame.dispose();
+ } else if (e.getActionCommand().equals("Save")) {
+ saveTextArea();
+ } else if (e.getActionCommand().equals("Clear")) {
+ ta.setText("");
+ }
+ }
+
+ public JTextArea getTextArea() {
+ return ta;
+ }
+
+ public int getCurrentPosition() {
+ return currentPosition;
+ }
+}
+
+class GlyphGutter extends JComponent {
+
+ private OOBeanShellDebugger debugger;
+ private final String DUMMY_STRING = "99";
+
+ GlyphGutter(OOBeanShellDebugger debugger) {
+ this.debugger = debugger;
+ update();
+ }
+
+ public void update() {
+ JTextArea textArea = debugger.getTextArea();
+ Font font = textArea.getFont();
+ setFont(font);
+
+ FontMetrics metrics = getFontMetrics(font);
+ int h = metrics.getHeight();
+ int lineCount = textArea.getLineCount() + 1;
+
+ String dummy = Integer.toString(lineCount);
+
+ if (dummy.length() < 2) {
+ dummy = DUMMY_STRING;
+ }
+
+ Dimension d = new Dimension();
+ d.width = metrics.stringWidth(dummy) + 16;
+ d.height = lineCount * h + 100;
+ setPreferredSize(d);
+ setSize(d);
+ }
+
+ public void paintComponent(Graphics g) {
+ JTextArea textArea = debugger.getTextArea();
+
+ Font font = textArea.getFont();
+ g.setFont(font);
+
+ FontMetrics metrics = getFontMetrics(font);
+ Rectangle clip = g.getClipBounds();
+
+ g.setColor(getBackground());
+ g.fillRect(clip.x, clip.y, clip.width, clip.height);
+
+ int ascent = metrics.getMaxAscent();
+ int h = metrics.getHeight();
+ int lineCount = textArea.getLineCount() + 1;
+
+ int startLine = clip.y / h;
+ int endLine = (clip.y + clip.height) / h + 1;
+ int width = getWidth();
+
+ if (endLine > lineCount) {
+ endLine = lineCount;
+ }
+
+ for (int i = startLine; i < endLine; i++) {
+ String text;
+ text = Integer.toString(i + 1) + " ";
+ int w = metrics.stringWidth(text);
+ int y = i * h;
+ g.setColor(Color.blue);
+ g.drawString(text, 0, y + ascent);
+ int x = width - ascent;
+
+ // if currentPosition is not -1 then a red arrow will be drawn
+ if (i == debugger.getCurrentPosition()) {
+ drawArrow(g, ascent, x, y);
+ }
+ }
+ }
+
+ private void drawArrow(Graphics g, int ascent, int x, int y) {
+ Polygon arrow = new Polygon();
+ int dx = x;
+ y += ascent - 10;
+ int dy = y;
+ arrow.addPoint(dx, dy + 3);
+ arrow.addPoint(dx + 5, dy + 3);
+
+ for (x = dx + 5; x <= dx + 10; x++, y++) {
+ arrow.addPoint(x, y);
+ }
+
+ for (x = dx + 9; x >= dx + 5; x--, y++) {
+ arrow.addPoint(x, y);
+ }
+
+ arrow.addPoint(dx + 5, dy + 7);
+ arrow.addPoint(dx, dy + 7);
+
+ g.setColor(Color.red);
+ g.fillPolygon(arrow);
+ g.setColor(Color.black);
+ g.drawPolygon(arrow);
+ }
+};
+
diff --git a/scripting/examples/java/debugger/OORhinoDebugger.java b/scripting/examples/java/debugger/OORhinoDebugger.java
new file mode 100644
index 000000000..5144637ac
--- /dev/null
+++ b/scripting/examples/java/debugger/OORhinoDebugger.java
@@ -0,0 +1,97 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+import javax.swing.SwingUtilities;
+import java.io.InputStream;
+
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ImporterTopLevel;
+import org.mozilla.javascript.tools.debugger.Main;
+import org.mozilla.javascript.tools.debugger.ScopeProvider;
+
+import com.sun.star.script.provider.XScriptContext;
+
+public class OORhinoDebugger implements OOScriptDebugger {
+
+ public void go(final XScriptContext xsctxt, String filename) {
+ Main sdb = initUI(xsctxt);
+
+ // This is the method we've added to open a file when starting
+ // the Rhino debugger
+ sdb.openFile(filename);
+ }
+
+ public void go(final XScriptContext xsctxt, InputStream in) {
+ Main sdb = initUI(xsctxt);
+
+ // Open a stream in the debugger
+ sdb.openStream(in);
+ }
+
+ // This code is based on the main method of the Rhino Debugger Main class
+ // We pass in the XScriptContext in the global scope for script execution
+ private Main initUI(final XScriptContext xsctxt) {
+ try {
+ final Main sdb = new Main("Rhino JavaScript Debugger");
+ swingInvoke(new Runnable() {
+ public void run() {
+ sdb.pack();
+ sdb.setSize(640, 640);
+ sdb.setVisible(true);
+ }
+ });
+ sdb.setExitAction(new Runnable() {
+ public void run() {
+ sdb.dispose();
+ }
+ });
+ Context.addContextListener(sdb);
+ sdb.setScopeProvider(new ScopeProvider() {
+ public Scriptable getScope() {
+ Context ctxt = Context.enter();
+ ImporterTopLevel scope = new ImporterTopLevel(ctxt);
+ Scriptable jsArgs = Context.toObject(xsctxt, scope);
+ scope.put("XSCRIPTCONTEXT", scope, jsArgs);
+ Context.exit();
+ return scope;
+ }
+ });
+ return sdb;
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ }
+
+ return null;
+ }
+
+ static void swingInvoke(Runnable f) {
+ if (SwingUtilities.isEventDispatchThread()) {
+ f.run();
+ return;
+ }
+
+ try {
+ SwingUtilities.invokeAndWait(f);
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ }
+ }
+}
diff --git a/scripting/examples/java/debugger/OOScriptDebugger.java b/scripting/examples/java/debugger/OOScriptDebugger.java
new file mode 100644
index 000000000..61fdbe73d
--- /dev/null
+++ b/scripting/examples/java/debugger/OOScriptDebugger.java
@@ -0,0 +1,27 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+import java.io.InputStream;
+import com.sun.star.script.provider.XScriptContext;
+
+public interface OOScriptDebugger {
+ public void go(XScriptContext ctxt, String filename);
+ public void go(XScriptContext ctxt, InputStream in);
+}
diff --git a/scripting/examples/java/debugger/parcel-descriptor.xml b/scripting/examples/java/debugger/parcel-descriptor.xml
new file mode 100644
index 000000000..93fbeabbe
--- /dev/null
+++ b/scripting/examples/java/debugger/parcel-descriptor.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="Java">
+
+ <script language="Java">
+ <locale lang="en">
+ <displayname value="Scripting Framework Debugger" />
+ <description>Script that starts debuggers for JavaScript and BeanShell
+ </description>
+ </locale>
+ <logicalname value="org.libreoffice.example.java_scripts._$DebugRunner.Debug" />
+ <functionname value="DebugRunner.go" />
+ <languagedepprops>
+ <prop name="classpath" value="debugger.jar"/>
+ </languagedepprops>
+ </script>
+</parcel>
+
diff --git a/scripting/examples/java/selector/ScriptSelector.java b/scripting/examples/java/selector/ScriptSelector.java
new file mode 100644
index 000000000..ed3cfd441
--- /dev/null
+++ b/scripting/examples/java/selector/ScriptSelector.java
@@ -0,0 +1,488 @@
+/*
+ * 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 .
+ */
+
+package org.libreoffice.example.java_scripts;
+
+import javax.swing.*;
+import javax.swing.tree.*;
+import javax.swing.table.*;
+import javax.swing.event.*;
+import javax.swing.border.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.beans.*;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.Exception;
+import com.sun.star.uno.Any;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.XComponentContext;
+
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lang.XComponent;
+import com.sun.star.frame.XModel;
+import com.sun.star.frame.FrameSearchFlag;
+import com.sun.star.frame.XDispatchProvider;
+import com.sun.star.frame.XDispatchHelper;
+import com.sun.star.frame.XDispatch;
+import com.sun.star.util.XURLTransformer;
+import com.sun.star.beans.*;
+import com.sun.star.script.XInvocation;
+
+import com.sun.star.lib.uno.helper.PropertySet;
+
+import com.sun.star.script.browse.XBrowseNode;
+import com.sun.star.script.browse.BrowseNodeTypes;
+import com.sun.star.script.browse.XBrowseNodeFactory;
+import com.sun.star.script.browse.BrowseNodeFactoryViewTypes;
+import com.sun.star.script.provider.XScriptContext;
+import com.sun.star.script.provider.XScript;
+import com.sun.star.script.provider.XScriptProvider;
+
+public class ScriptSelector {
+
+ private static final int BIG_GAP = 10;
+ private static final int MED_GAP = 5;
+
+ private ScriptSelectorPanel selectorPanel;
+
+ public ScriptSelector() {
+ }
+
+ public void showOrganizer(final XScriptContext ctxt) {
+ try {
+ XBrowseNode root = getRootNode(ctxt);
+
+ final XScriptProvider msp =
+ (XScriptProvider)UnoRuntime.queryInterface(
+ XScriptProvider.class, root);
+
+ final JFrame client = new JFrame("Script");
+
+ selectorPanel = new ScriptSelectorPanel(root);
+
+ final JButton runButton, closeButton, createButton,
+ editButton, deleteButton;
+
+ runButton = new JButton("Run");
+ runButton.setEnabled(false);
+
+ closeButton = new JButton("Close");
+
+ editButton = new JButton("Edit");
+ editButton.setEnabled(false);
+
+ JPanel northButtons =
+ new JPanel(new GridLayout(2, 1, MED_GAP, MED_GAP));
+
+ northButtons.add(runButton);
+ northButtons.add(closeButton);
+
+ createButton = new JButton("Create");
+ createButton.setEnabled(false);
+
+ deleteButton = new JButton("Delete");
+ deleteButton.setEnabled(false);
+
+ JPanel southButtons =
+ new JPanel(new GridLayout(3, 1, MED_GAP, MED_GAP));
+
+ southButtons.add(editButton);
+ southButtons.add(createButton);
+ southButtons.add(deleteButton);
+
+ selectorPanel.tree.addTreeSelectionListener(
+ new TreeSelectionListener() {
+ public void valueChanged(TreeSelectionEvent e) {
+ XBrowseNode xbn = selectorPanel.getSelection();
+ XPropertySet props = (XPropertySet)
+ UnoRuntime.queryInterface(XPropertySet.class, xbn);
+
+ checkEnabled(props, "Creatable", createButton);
+ checkEnabled(props, "Deletable", deleteButton);
+ checkEnabled(props, "Editable", editButton);
+
+ if (xbn != null &&
+ xbn.getType() == BrowseNodeTypes.SCRIPT) {
+ runButton.setEnabled(true);
+ } else {
+ runButton.setEnabled(false);
+ }
+ }
+ }
+ );
+
+ ActionListener listener = new ActionListener() {
+ public void actionPerformed(ActionEvent event) {
+ if (event.getSource() == runButton) {
+ String uri = selectorPanel.textField.getText();
+
+ try {
+ XScript script = msp.getScript(uri);
+
+ Object[][] out = new Object[1][0];
+ out[0] = new Object[0];
+
+ short[][] num = new short[1][0];
+ num[0] = new short[0];
+
+ script.invoke(new Object[0], num, out);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else if (event.getSource() == closeButton) {
+ client.dispose();
+ } else if (event.getSource() == editButton) {
+ DefaultMutableTreeNode node =
+ (DefaultMutableTreeNode)
+ selectorPanel.tree.getLastSelectedPathComponent();
+
+ if (node == null) return;
+
+ showEditor(ctxt, node);
+ } else if (event.getSource() == createButton) {
+ DefaultMutableTreeNode node =
+ (DefaultMutableTreeNode)
+ selectorPanel.tree.getLastSelectedPathComponent();
+
+ if (node == null) return;
+
+ doCreate(ctxt, node);
+ } else if (event.getSource() == deleteButton) {
+ DefaultMutableTreeNode node =
+ (DefaultMutableTreeNode)
+ selectorPanel.tree.getLastSelectedPathComponent();
+
+ if (node == null) return;
+
+ doDelete(ctxt, node);
+ }
+ }
+ };
+
+ runButton.addActionListener(listener);
+ closeButton.addActionListener(listener);
+ createButton.addActionListener(listener);
+ editButton.addActionListener(listener);
+ deleteButton.addActionListener(listener);
+
+ JPanel buttonPanel = new JPanel(new BorderLayout());
+ buttonPanel.add(northButtons, BorderLayout.NORTH);
+ buttonPanel.add(southButtons, BorderLayout.SOUTH);
+
+ JPanel mainPanel = new JPanel(new BorderLayout(MED_GAP, MED_GAP));
+ mainPanel.setBorder(
+ new EmptyBorder(BIG_GAP, BIG_GAP, BIG_GAP, BIG_GAP));
+ mainPanel.add(selectorPanel, BorderLayout.CENTER);
+ mainPanel.add(buttonPanel, BorderLayout.EAST);
+
+ client.getContentPane().add(mainPanel);
+ client.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+ client.setSize(500, 350);
+
+ // set the x and y locations so that the frame is in the
+ // centre of the screen
+ Dimension d = client.getToolkit().getScreenSize();
+
+ int x = (int)((d.getWidth() - client.getWidth()) / 2);
+ int y = (int)((d.getHeight() - client.getHeight()) / 2);
+
+ client.setLocation(x, y);
+
+ client.show();
+ } catch (com.sun.star.uno.RuntimeException rue) {
+ rue.printStackTrace();
+ } catch (java.lang.Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void showOrganizer(final XScriptContext ctxt,
+ final com.sun.star.awt.MouseEvent e) {
+ showOrganizer(ctxt);
+ }
+
+ public void showOrganizer(final XScriptContext ctxt,
+ final com.sun.star.awt.ActionEvent e) {
+ showOrganizer(ctxt);
+ }
+
+ private void doDelete(
+ XScriptContext ctxt, DefaultMutableTreeNode node) {
+ Object obj = node.getUserObject();
+ XInvocation inv =
+ (XInvocation)UnoRuntime.queryInterface(
+ XInvocation.class, obj);
+ Object[] args = new Object[] { ctxt };
+
+ try {
+ Object result = inv.invoke("Deletable", args,
+ new short[1][0], new Object[1][0]);
+
+ if (result != null && AnyConverter.toBoolean(result) == true) {
+ selectorPanel.removeNode(node);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void doCreate(
+ XScriptContext ctxt, DefaultMutableTreeNode node) {
+ Object obj = node.getUserObject();
+ XInvocation inv =
+ (XInvocation)UnoRuntime.queryInterface(
+ XInvocation.class, obj);
+ Object[] args = new Object[] { ctxt };
+
+ try {
+ Object result = inv.invoke("Creatable", args,
+ new short[1][0], new Object[1][0]);
+
+ if (result != null) {
+ XBrowseNode xbn = (XBrowseNode)
+ AnyConverter.toObject(new Type(XBrowseNode.class), result);
+ selectorPanel.addNode(node, xbn);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void showEditor(
+ XScriptContext ctxt, DefaultMutableTreeNode node) {
+ Object obj = node.getUserObject();
+ XInvocation inv =
+ (XInvocation)UnoRuntime.queryInterface(
+ XInvocation.class, obj);
+ Object[] args = new Object[] { ctxt };
+
+ try {
+ inv.invoke("Editable", args,
+ new short[1][0], new Object[1][0]);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void checkEnabled(XPropertySet props, String name,
+ JButton button) {
+ boolean enable = false;
+
+ try {
+ if (props != null) {
+ Object o = props.getPropertyValue(name);
+ enable = AnyConverter.toBoolean(
+ props.getPropertyValue(name));
+ }
+ } catch (com.sun.star.lang.IllegalArgumentException iae) {
+ // leave enable set to false
+ } catch (com.sun.star.beans.UnknownPropertyException upe) {
+ // leave enable set to false
+ } catch (com.sun.star.lang.WrappedTargetException wte) {
+ // leave enable set to false
+ }
+
+ button.setEnabled(enable);
+ }
+
+ private XBrowseNode getRootNode(XScriptContext ctxt) {
+
+ XBrowseNode result = null;
+
+
+ XComponentContext xcc = ctxt.getComponentContext();
+ XMultiComponentFactory xmcf = xcc.getServiceManager();
+ XBrowseNodeFactory xBrowseFac = (XBrowseNodeFactory)
+ UnoRuntime.queryInterface(XBrowseNodeFactory.class, xcc.getValueByName(
+ "/singletons/com.sun.star.script.browse.theBrowseNodeFactory"));
+
+
+ result = (XBrowseNode)UnoRuntime.queryInterface(
+ XBrowseNode.class, xBrowseFac.createView(
+ BrowseNodeFactoryViewTypes.MACROORGANIZER));
+ return result;
+ }
+}
+
+class ScriptSelectorPanel extends JPanel {
+
+ private XBrowseNode myrootnode = null;
+ public JTextField textField;
+ public JTree tree;
+ public DefaultTreeModel treeModel;
+
+ public ScriptSelectorPanel(XBrowseNode root) {
+ this.myrootnode = root;
+ initUI();
+ }
+
+ public XBrowseNode getSelection() {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode)
+ tree.getLastSelectedPathComponent();
+
+ if (node == null) {
+ return null;
+ }
+
+ return (XBrowseNode)node.getUserObject();
+ }
+
+ private void initUI() {
+ setLayout(new BorderLayout());
+
+ DefaultMutableTreeNode top =
+ new DefaultMutableTreeNode(myrootnode) {
+ public String toString() {
+ return ((XBrowseNode)getUserObject()).getName();
+ }
+ };
+ initNodes(myrootnode, top);
+ treeModel = new DefaultTreeModel(top);
+ tree = new JTree(treeModel);
+
+ tree.setCellRenderer(new ScriptTreeRenderer());
+
+ tree.getSelectionModel().setSelectionMode
+ (TreeSelectionModel.SINGLE_TREE_SELECTION);
+
+ tree.addTreeSelectionListener(new TreeSelectionListener() {
+ public void valueChanged(TreeSelectionEvent e) {
+ XBrowseNode xbn = getSelection();
+ XPropertySet props = (XPropertySet)UnoRuntime.queryInterface(
+ XPropertySet.class, xbn);
+
+ if (xbn == null) {
+ textField.setText("");
+ return;
+ }
+
+ String str = xbn.getName();
+
+ if (xbn.getType() == BrowseNodeTypes.SCRIPT && props != null) {
+ try {
+ str = AnyConverter.toString(
+ props.getPropertyValue("URI"));
+ } catch (Exception ignore) {
+ // default will be used
+ }
+ }
+
+ textField.setText(str);
+ }
+ });
+
+ JScrollPane scroller = new JScrollPane(tree);
+ add(scroller, BorderLayout.CENTER);
+
+ textField = new JTextField();
+ add(textField, BorderLayout.SOUTH);
+ }
+
+ public void removeNode(DefaultMutableTreeNode node) {
+ MutableTreeNode parent = (MutableTreeNode)(node.getParent());
+
+ if (parent != null) {
+ treeModel.removeNodeFromParent(node);
+ }
+ }
+
+ public void addNode(DefaultMutableTreeNode parent, XBrowseNode xbn) {
+ DefaultMutableTreeNode newNode =
+ new DefaultMutableTreeNode(xbn) {
+ public String toString() {
+ return ((XBrowseNode)getUserObject()).getName();
+ }
+ };
+
+ treeModel.insertNodeInto(newNode, parent, parent.getChildCount());
+ tree.scrollPathToVisible(new TreePath(newNode.getPath()));
+ }
+
+ private void initNodes(XBrowseNode parent, DefaultMutableTreeNode top) {
+ if (parent == null || parent.hasChildNodes() == false) {
+ return;
+ }
+
+ XBrowseNode[] children = parent.getChildNodes();
+
+ try {
+ if (children != null) {
+ for (int i = 0; i < children.length; i++) {
+ if (children[i] == null) {
+ continue;
+ }
+
+ DefaultMutableTreeNode newNode =
+ new DefaultMutableTreeNode(children[i]) {
+ public String toString() {
+ return ((XBrowseNode)getUserObject()).getName();
+ }
+ };
+ top.add(newNode);
+ initNodes(children[i], newNode);
+ }
+ }
+ } catch (java.lang.Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
+
+class ScriptTreeRenderer extends DefaultTreeCellRenderer {
+
+ private ImageIcon sofficeIcon;
+ private ImageIcon scriptIcon;
+ private ImageIcon containerIcon;
+
+ public ScriptTreeRenderer() {
+ sofficeIcon = new ImageIcon(getClass().getResource("soffice.gif"));
+ scriptIcon = new ImageIcon(getClass().getResource("script.gif"));
+ containerIcon = new ImageIcon(getClass().getResource("container.gif"));
+ }
+
+ public Component getTreeCellRendererComponent(
+ JTree tree,
+ Object value,
+ boolean sel,
+ boolean expanded,
+ boolean leaf,
+ int row,
+ boolean hasFocus) {
+
+ super.getTreeCellRendererComponent(
+ tree, value, sel,
+ expanded, leaf, row,
+ hasFocus);
+
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
+ XBrowseNode xbn = (XBrowseNode)node.getUserObject();
+
+ if (xbn.getType() == BrowseNodeTypes.SCRIPT) {
+ setIcon(scriptIcon);
+ } else if (xbn.getType() == BrowseNodeTypes.CONTAINER) {
+ setIcon(containerIcon);
+ } else if (xbn.getType() == BrowseNodeTypes.ROOT) {
+ setIcon(sofficeIcon);
+ }
+
+ return this;
+ }
+}
diff --git a/scripting/examples/java/selector/container.gif b/scripting/examples/java/selector/container.gif
new file mode 100644
index 000000000..3a345f9bf
--- /dev/null
+++ b/scripting/examples/java/selector/container.gif
Binary files differ
diff --git a/scripting/examples/java/selector/parcel-descriptor.xml b/scripting/examples/java/selector/parcel-descriptor.xml
new file mode 100644
index 000000000..1f4b8ec38
--- /dev/null
+++ b/scripting/examples/java/selector/parcel-descriptor.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="Java" xmlns:parcel="scripting.dtd">
+ <script language="Java">
+ <locale lang="en">
+ <displayname value="Script Selector"/>
+ <description>
+ Prototype Script Selector GUI for StarOffice
+ </description>
+ </locale>
+ <functionname value="org.libreoffice.example.java_scripts.ScriptSelector.showOrganizer"/>
+ <logicalname value="ScriptSelector.showOrganizer"/>
+ <languagedepprops>
+ <prop name="classpath" value="selector.jar"/>
+ </languagedepprops>
+ </script>
+</parcel>
diff --git a/scripting/examples/java/selector/script.gif b/scripting/examples/java/selector/script.gif
new file mode 100644
index 000000000..d3b3768ca
--- /dev/null
+++ b/scripting/examples/java/selector/script.gif
Binary files differ
diff --git a/scripting/examples/java/selector/soffice.gif b/scripting/examples/java/selector/soffice.gif
new file mode 100644
index 000000000..88124d87d
--- /dev/null
+++ b/scripting/examples/java/selector/soffice.gif
Binary files differ
diff --git a/scripting/examples/javascript/ExportSheetsToHTML/exportsheetstohtml.js b/scripting/examples/javascript/ExportSheetsToHTML/exportsheetstohtml.js
new file mode 100644
index 000000000..37f9e5afb
--- /dev/null
+++ b/scripting/examples/javascript/ExportSheetsToHTML/exportsheetstohtml.js
@@ -0,0 +1,88 @@
+/*
+ * 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 .
+ */
+// When this script is run on an existing, saved, spreadsheet,
+// eg. /home/testuser/myspreadsheet.sxc, the script will export
+// each sheet to a separate html file,
+// eg. /home/testuser/myspreadsheet_sheet1.html,
+// /home/testuser/myspreadsheet_sheet2.html etc
+importClass(Packages.com.sun.star.uno.UnoRuntime);
+importClass(Packages.com.sun.star.sheet.XSpreadsheetDocument);
+importClass(Packages.com.sun.star.container.XIndexAccess);
+importClass(Packages.com.sun.star.beans.XPropertySet);
+importClass(Packages.com.sun.star.beans.PropertyValue);
+importClass(Packages.com.sun.star.util.XModifiable);
+importClass(Packages.com.sun.star.frame.XStorable);
+importClass(Packages.com.sun.star.frame.XModel);
+importClass(Packages.com.sun.star.uno.AnyConverter);
+importClass(Packages.com.sun.star.uno.Type);
+
+importClass(java.lang.System);
+
+//get the document object from the scripting context
+oDoc = XSCRIPTCONTEXT.getDocument();
+//get the XSpreadsheetDocument interface from the document
+xSDoc = UnoRuntime.queryInterface(XSpreadsheetDocument, oDoc);
+//get the XModel interface from the document
+xModel = UnoRuntime.queryInterface(XModel,oDoc);
+//get the XIndexAccess interface used to access each sheet
+xSheetsIndexAccess = UnoRuntime.queryInterface(XIndexAccess, xSDoc.getSheets());
+//get the XStorable interface used to save the document
+xStorable = UnoRuntime.queryInterface(XStorable,xSDoc);
+//get the XModifiable interface used to indicate if the document has been
+//changed
+xModifiable = UnoRuntime.queryInterface(XModifiable,xSDoc);
+
+//set up an array of PropertyValue objects used to save each sheet in the
+//document
+storeProps = new Array;//PropertyValue[1];
+storeProps[0] = new PropertyValue();
+storeProps[0].Name = "FilterName";
+storeProps[0].Value = "HTML (StarCalc)";
+storeUrl = xModel.getURL();
+storeUrl = storeUrl.substring(0,storeUrl.lastIndexOf('.'));
+
+//set only one sheet visible, and store to HTML doc
+for(var i=0;i<xSheetsIndexAccess.getCount();i++)
+{
+ setAllButOneHidden(xSheetsIndexAccess,i);
+ xModifiable.setModified(false);
+ xStorable.storeToURL(storeUrl+"_sheet"+(i+1)+".html", storeProps);
+}
+
+// now set all visible again
+for(var i=0;i<xSheetsIndexAccess.getCount();i++)
+{
+ xPropSet = AnyConverter.toObject( new Type(XPropertySet), xSheetsIndexAccess.getByIndex(i));
+ xPropSet.setPropertyValue("IsVisible", true);
+}
+
+function setAllButOneHidden(xSheetsIndexAccess,vis) {
+ //System.err.println("count="+xSheetsIndexAccess.getCount());
+ //get an XPropertySet interface for the vis-th sheet
+ xPropSet = AnyConverter.toObject( new Type(XPropertySet), xSheetsIndexAccess.getByIndex(vis));
+ //set the vis-th sheet to be visible
+ xPropSet.setPropertyValue("IsVisible", true);
+ // set all other sheets to be invisible
+ for(var i=0;i<xSheetsIndexAccess.getCount();i++)
+ {
+ xPropSet = AnyConverter.toObject( new Type(XPropertySet), xSheetsIndexAccess.getByIndex(i));
+ if(i!=vis) {
+ xPropSet.setPropertyValue("IsVisible", false);
+ }
+ }
+}
diff --git a/scripting/examples/javascript/ExportSheetsToHTML/parcel-descriptor.xml b/scripting/examples/javascript/ExportSheetsToHTML/parcel-descriptor.xml
new file mode 100644
index 000000000..be8880ab0
--- /dev/null
+++ b/scripting/examples/javascript/ExportSheetsToHTML/parcel-descriptor.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="JavaScript" xmlns:parcel="scripting.dtd">
+
+ <script language="JavaScript">
+ <locale lang="en">
+ <displayname value="ExportSheetsToHTML"/>
+ <description>
+ Saves each sheet in the current Calc document as a separate HTML file in the same directory as the original Calc document.
+ </description>
+ </locale>
+ <functionname value="exportsheetstohtml.js"/>
+ <logicalname value="ExportSheetsToHTML.JavaScript"/>
+ </script>
+
+</parcel>
diff --git a/scripting/examples/javascript/HelloWorld/helloworld.js b/scripting/examples/javascript/HelloWorld/helloworld.js
new file mode 100644
index 000000000..f04fdfd8a
--- /dev/null
+++ b/scripting/examples/javascript/HelloWorld/helloworld.js
@@ -0,0 +1,33 @@
+/*
+ * 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 .
+ */
+// Hello World in JavaScript
+importClass(Packages.com.sun.star.uno.UnoRuntime);
+importClass(Packages.com.sun.star.text.XTextDocument);
+importClass(Packages.com.sun.star.text.XText);
+importClass(Packages.com.sun.star.text.XTextRange);
+
+//get the document from the scripting context
+oDoc = XSCRIPTCONTEXT.getDocument();
+//get the XTextDocument interface
+xTextDoc = UnoRuntime.queryInterface(XTextDocument,oDoc);
+//get the XText interface
+xText = xTextDoc.getText();
+//get an (empty) XTextRange interface at the end of the text
+xTextRange = xText.getEnd();
+//set the text in the XTextRange
+xTextRange.setString( "Hello World (in JavaScript)" );
diff --git a/scripting/examples/javascript/HelloWorld/parcel-descriptor.xml b/scripting/examples/javascript/HelloWorld/parcel-descriptor.xml
new file mode 100644
index 000000000..65ea9fd75
--- /dev/null
+++ b/scripting/examples/javascript/HelloWorld/parcel-descriptor.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="JavaScript" xmlns:parcel="scripting.dtd">
+
+ <script language="JavaScript">
+ <locale lang="en">
+ <displayname value="Hello World"/>
+ <description>
+ Adds the string "Hello World" into the current text doc.
+ </description>
+ </locale>
+ <functionname value="helloworld.js"/>
+ <logicalname value="HelloWorld.JavaScript"/>
+ </script>
+
+</parcel>
diff --git a/scripting/examples/javascript/Highlight/ButtonPressHandler.js b/scripting/examples/javascript/Highlight/ButtonPressHandler.js
new file mode 100644
index 000000000..e0fbde240
--- /dev/null
+++ b/scripting/examples/javascript/Highlight/ButtonPressHandler.js
@@ -0,0 +1,122 @@
+/*
+ * 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 .
+ */
+//this script acts as a handler for the buttons in the Highlight dialog
+importClass(Packages.com.sun.star.uno.UnoRuntime);
+importClass(Packages.com.sun.star.uno.Type);
+importClass(Packages.com.sun.star.uno.AnyConverter);
+
+importClass(Packages.com.sun.star.awt.XButton);
+importClass(Packages.com.sun.star.awt.XControl);
+importClass(Packages.com.sun.star.awt.ActionEvent);
+importClass(Packages.com.sun.star.awt.XControlModel);
+importClass(Packages.com.sun.star.awt.XControlContainer);
+importClass(Packages.com.sun.star.awt.XDialog);
+importClass(Packages.com.sun.star.awt.XTextComponent);
+
+importClass(Packages.com.sun.star.util.XReplaceable);
+importClass(Packages.com.sun.star.util.XReplaceDescriptor);
+importClass(Packages.com.sun.star.util.XPropertyReplace);
+
+importClass(Packages.com.sun.star.beans.XPropertySet);
+importClass(Packages.com.sun.star.beans.PropertyValue);
+
+// Scripting Framework DialogFactory class
+importClass(Packages.com.sun.star.script.framework.browse.DialogFactory);
+
+// Get the ActionEvent object from the ARGUMENTS list
+event = ARGUMENTS[0];
+
+// Each argument is of type Any so we must use the AnyConverter class to
+// convert it into the interface or primitive type we expect
+button = AnyConverter.toObject(new Type(XButton), event.Source);
+
+// We can now query for the model of the button and get its properties
+control = UnoRuntime.queryInterface(XControl, button);
+cmodel = control.getModel();
+pset = UnoRuntime.queryInterface(XPropertySet, cmodel);
+
+if (pset.getPropertyValue("Label").equals("Exit"))
+{
+ // We can get the XDialog in which this control appears by calling
+ // getContext() on the XControl interface
+ xDialog = UnoRuntime.queryInterface(
+ XDialog, control.getContext());
+
+ // Close the dialog
+ xDialog.endExecute();
+}
+else
+{
+ // We can get the list of controls for this dialog by calling
+ // getContext() on the XControl interface of the button
+ controls = UnoRuntime.queryInterface(
+ XControlContainer, control.getContext());
+
+ // Now get the text field control from the list
+ textField =
+ UnoRuntime.queryInterface(
+ XTextComponent, controls.getControl("HighlightTextField"));
+
+ searchKey = textField.getText();
+
+ // highlight the text in red
+ red = java.awt.Color.red.getRGB();
+
+ replaceable =
+ UnoRuntime.queryInterface(XReplaceable, XSCRIPTCONTEXT.getDocument());
+
+ descriptor = replaceable.createReplaceDescriptor();
+
+ // Gets a XPropertyReplace object for altering the properties
+ // of the replaced text
+ xPropertyReplace = UnoRuntime.queryInterface(XPropertyReplace, descriptor);
+
+ // Sets the replaced text property fontweight value to Bold
+ wv = new PropertyValue("CharWeight", -1,
+ new java.lang.Float(Packages.com.sun.star.awt.FontWeight.BOLD),
+ Packages.com.sun.star.beans.PropertyState.DIRECT_VALUE);
+
+ // Sets the replaced text property color value to RGB parameter
+ cv = new PropertyValue("CharColor", -1,
+ new java.lang.Integer(red),
+ Packages.com.sun.star.beans.PropertyState.DIRECT_VALUE);
+
+ // Apply the properties
+ props = new Array;
+ props[0] = cv;
+ props[1] = wv;
+
+ try {
+ xPropertyReplace.setReplaceAttributes(props);
+
+ // Only matches whole words and case sensitive
+ descriptor.setPropertyValue(
+ "SearchCaseSensitive", new java.lang.Boolean(true));
+ descriptor.setPropertyValue("SearchWords", new java.lang.Boolean(true));
+
+ // Replaces all instances of searchKey with new Text properties
+ // and gets the number of instances of the searchKey
+ descriptor.setSearchString(searchKey);
+ descriptor.setReplaceString(searchKey);
+ replaceable.replaceAll(descriptor);
+ }
+ catch (e) {
+ java.lang.System.err.println("Error setting up search properties"
+ + e.getMessage());
+ }
+}
diff --git a/scripting/examples/javascript/Highlight/ShowDialog.js b/scripting/examples/javascript/Highlight/ShowDialog.js
new file mode 100644
index 000000000..d659d9622
--- /dev/null
+++ b/scripting/examples/javascript/Highlight/ShowDialog.js
@@ -0,0 +1,131 @@
+/*
+ * 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 .
+ */
+importClass(Packages.com.sun.star.uno.UnoRuntime);
+importClass(Packages.com.sun.star.lang.XMultiComponentFactory);
+importClass(Packages.com.sun.star.awt.XDialogProvider);
+importClass(Packages.com.sun.star.awt.XDialog);
+importClass(Packages.com.sun.star.uno.Exception);
+importClass(Packages.com.sun.star.script.provider.XScriptContext);
+
+importClass(java.lang.Thread);
+importClass(java.lang.System);
+
+function tryLoadingLibrary( xmcf, context, name )
+{
+ try
+ {
+ obj = xmcf.createInstanceWithContext(
+ "com.sun.star.script.Application" + name + "LibraryContainer",
+ context.getComponentContext());
+
+ xLibraryContainer = UnoRuntime.queryInterface(XLibraryContainer, obj);
+
+ System.err.println("Got XLibraryContainer");
+
+ serviceObj = context.getComponentContext().getValueByName(
+ "/singletons/com.sun.star.util.theMacroExpander");
+
+ xme = AnyConverter.toObject(new Type(XMacroExpander), serviceObj);
+
+ bootstrapName = "bootstraprc";
+ if (System.getProperty("os.name").startsWith("Windows"))
+ {
+ bootstrapName = "bootstrap.ini";
+ }
+
+ libURL = xme.expandMacros(
+ "$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR/basic/ScriptBindingLibrary/" +
+ name.toLowerCase() + ".xlb/");
+
+ System.err.println("libURL is: " + libURL);
+
+ xLibraryContainer.createLibraryLink(
+ "ScriptBindingLibrary", libURL, false);
+
+ System.err.println("liblink created");
+
+ }
+ catch (e)
+ {
+ System.err.println("Got an exception loading lib: " + e.getMessage());
+ return false;
+ }
+ return true;
+}
+
+function getDialogProvider()
+{
+ // UNO awt components of the Highlight dialog
+ //get the XMultiServiceFactory
+ xmcf = XSCRIPTCONTEXT.getComponentContext().getServiceManager();
+
+ args = new Array;
+ //get the XDocument from the context
+ args[0] = XSCRIPTCONTEXT.getDocument();
+
+ //try to create the DialogProvider
+ try {
+ obj = xmcf.createInstanceWithArgumentsAndContext(
+ "com.sun.star.awt.DialogProvider", args,
+ XSCRIPTCONTEXT.getComponentContext());
+ }
+ catch (e) {
+ System.err.println("Error getting DialogProvider object");
+ return null;
+ }
+
+ return UnoRuntime.queryInterface(XDialogProvider, obj);
+}
+
+//get the DialogProvider
+xDialogProvider = getDialogProvider();
+
+if (xDialogProvider != null)
+{
+ //try to create the Highlight dialog (found in the ScriptBinding library)
+ try
+ {
+ findDialog = xDialogProvider.createDialog("vnd.sun.star.script:" +
+ "ScriptBindingLibrary.Highlight?location=application");
+ if( findDialog == null )
+ {
+ if (tryLoadingLibrary(xmcf, XSCRIPTCONTEXT, "Dialog") == false ||
+ tryLoadingLibrary(xmcf, XSCRIPTCONTEXT, "Script") == false)
+ {
+ System.err.println("Error loading ScriptBindingLibrary");
+ }
+ else
+ {
+ // try to create the Highlight dialog (found in the
+ // ScriptBindingLibrary)
+ findDialog = xDialogProvider.createDialog("vnd.sun.star.script:" +
+ "ScriptBindingLibrary.Highlight?location=application");
+ }
+ }
+
+ //launch the dialog
+ if ( findDialog != null )
+ {
+ findDialog.execute();
+ }
+ }
+ catch (e) {
+ System.err.println("Got exception on first creating dialog: " +
+ e.getMessage());
+ }
+}
diff --git a/scripting/examples/javascript/Highlight/parcel-descriptor.xml b/scripting/examples/javascript/Highlight/parcel-descriptor.xml
new file mode 100644
index 000000000..e6d6bb7b1
--- /dev/null
+++ b/scripting/examples/javascript/Highlight/parcel-descriptor.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<parcel language="JavaScript" xmlns:parcel="scripting.dtd">
+ <script language="JavaScript">
+ <locale lang="en">
+ <displayname value="ShowDialog" />
+ <description>
+ Example of how to show a dialog from JavaScript
+ </description>
+ </locale>
+ <functionname value="ShowDialog.js" />
+ <logicalname value="ShowDialog.JavaScript" />
+ </script>
+ <script language="JavaScript">
+ <locale lang="en">
+ <displayname value="ButtonPressHandler" />
+ <description>
+ Example of handle button press events for the Dialog
+ </description>
+ </locale>
+ <functionname value="ButtonPressHandler.js" />
+ <logicalname value="ButtonPressHandler.JavaScript" />
+ </script>
+</parcel>
+
diff --git a/scripting/examples/python/Capitalise.py b/scripting/examples/python/Capitalise.py
new file mode 100644
index 000000000..64d29a513
--- /dev/null
+++ b/scripting/examples/python/Capitalise.py
@@ -0,0 +1,96 @@
+#
+# 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 .
+#
+
+def getNewString(theString):
+ """helper function
+ """
+ if (not theString):
+ return ""
+
+ # should we tokenize on "."?
+ if len(theString) >= 2 and theString[:2].isupper():
+ # first two chars are UC => first UC, rest LC
+ newString = theString[0].upper() + theString[1:].lower()
+
+ elif theString[0].isupper():
+ # first char UC => all to LC
+ newString = theString.lower()
+
+ else:
+ # all to UC.
+ newString = theString.upper()
+
+ return newString
+
+
+def capitalisePython():
+ """Change the case of the selected or current word(s).
+ If at least the first two characters are "UPpercase, then it is changed
+ to first char "Uppercase".
+ If the first character is "Uppercase", then it is changed to
+ all "lowercase".
+ Otherwise, all are changed to "UPPERCASE".
+ """
+ # The context variable is of type XScriptContext and is available to
+ # all BeanShell scripts executed by the Script Framework
+ xModel = XSCRIPTCONTEXT.getDocument()
+
+ # the writer controller impl supports the css.view.XSelectionSupplier
+ # interface
+ xSelectionSupplier = xModel.getCurrentController()
+
+ # see section 7.5.1 of developers' guide
+ xIndexAccess = xSelectionSupplier.getSelection()
+ count = xIndexAccess.getCount()
+
+ if(count >= 1): # ie we have a selection
+ i = 0
+
+ while i < count:
+ xTextRange = xIndexAccess.getByIndex(i)
+ theString = xTextRange.getString()
+ # print("theString")
+ if len(theString) == 0:
+ # sadly we can have a selection where nothing is selected
+ # in this case we get the XWordCursor and make a selection!
+ xText = xTextRange.getText()
+ xWordCursor = xText.createTextCursorByRange(xTextRange)
+
+ if not xWordCursor.isStartOfWord():
+ xWordCursor.gotoStartOfWord(False)
+
+ xWordCursor.gotoNextWord(True)
+ theString = xWordCursor.getString()
+ newString = getNewString(theString)
+
+ if newString:
+ xWordCursor.setString(newString)
+ xSelectionSupplier.select(xWordCursor)
+ else:
+ newString = getNewString(theString)
+ if newString:
+ xTextRange.setString(newString)
+ xSelectionSupplier.select(xTextRange)
+ i += 1
+
+
+# lists the scripts, that shall be visible inside OOo. Can be omitted, if
+# all functions shall be visible, however here getNewString shall be suppressed
+g_exportedScripts = capitalisePython,
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/scripting/examples/python/HelloWorld.py b/scripting/examples/python/HelloWorld.py
new file mode 100644
index 000000000..ed21b2008
--- /dev/null
+++ b/scripting/examples/python/HelloWorld.py
@@ -0,0 +1,47 @@
+# HelloWorld python script for the scripting framework
+
+#
+# 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 .
+#
+
+def HelloWorldPython():
+ """Prints the string 'Hello World (in Python)' into the current document.
+ """
+
+ # Get the doc from the scripting context which is made available to all
+ # scripts.
+ desktop = XSCRIPTCONTEXT.getDesktop()
+ model = desktop.getCurrentComponent()
+
+ # Check whether there's already an opened document.
+ # Otherwise, create a new one
+ if not hasattr(model, "Text"):
+ model = desktop.loadComponentFromURL(
+ "private:factory/swriter", "_blank", 0, ())
+
+ # get the XText interface
+ text = model.Text
+
+ # create an XTextRange at the end of the document
+ tRange = text.End
+
+ # and set the string
+ tRange.String = "Hello World (in Python)"
+
+ return None
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/scripting/examples/python/InsertText.py b/scripting/examples/python/InsertText.py
new file mode 100644
index 000000000..801b81908
--- /dev/null
+++ b/scripting/examples/python/InsertText.py
@@ -0,0 +1,65 @@
+# Example python script for the scripting framework
+
+#
+# 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 .
+#
+
+def InsertText(text):
+ """Inserts the argument string into the current document.
+ If there is a selection, the selection is replaced by it.
+ """
+
+ # Get the doc from the scripting context which is made available to
+ # all scripts.
+ desktop = XSCRIPTCONTEXT.getDesktop()
+ model = desktop.getCurrentComponent()
+
+ # Check whether there's already an opened document.
+ if not hasattr(model, "Text"):
+ return
+
+ # The context variable is of type XScriptContext and is available to
+ # all BeanShell scripts executed by the Script Framework
+ xModel = XSCRIPTCONTEXT.getDocument()
+
+ # The writer controller impl supports the css.view.XSelectionSupplier
+ # interface.
+ xSelectionSupplier = xModel.getCurrentController()
+
+ # See section 7.5.1 of developers' guide
+ xIndexAccess = xSelectionSupplier.getSelection()
+ count = xIndexAccess.getCount()
+
+ if count >= 1: # ie we have a selection
+ i = 0
+
+ while i < count:
+ xTextRange = xIndexAccess.getByIndex(i)
+ theString = xTextRange.getString()
+
+ if not len(theString):
+ # Nothing really selected, just insert.
+ xText = xTextRange.getText()
+ xWordCursor = xText.createTextCursorByRange(xTextRange)
+ xWordCursor.setString(text)
+ xSelectionSupplier.select(xWordCursor)
+ else:
+ # Replace the selection.
+ xTextRange.setString(text)
+ xSelectionSupplier.select(xTextRange)
+
+ i += 1
diff --git a/scripting/examples/python/NamedRanges.py b/scripting/examples/python/NamedRanges.py
new file mode 100644
index 000000000..5a28e2b5d
--- /dev/null
+++ b/scripting/examples/python/NamedRanges.py
@@ -0,0 +1,134 @@
+#
+# 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/.
+#
+import uno
+from com.sun.star.container import NoSuchElementException
+
+def DefineNamedRange(doc, SheetName, rangeName, rangeReference):
+ """Defines a new named range. If the named range exists in the document, then
+ update the rangeReference.
+
+ Example: DefineNamedRange(doc, "Sheet1", "test_range", '$A$1:$F$14').
+
+ API Reference:
+ https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1sheet_1_1XNamedRanges.html
+ """
+ aName = rangeName
+ # make sure the sheet name starts with "$"
+ sheetName = "$" + SheetName.replace("$", "")
+ aContent = sheetName + "." + rangeReference
+
+ try:
+ # If the named range exists, then update it
+ doc.NamedRanges.getByName(rangeName)
+ update = True
+ except NoSuchElementException:
+ update = False
+
+ if update:
+ doc.NamedRanges.getByName(rangeName).setContent(aContent)
+ else:
+ aPosition = uno.createUnoStruct('com.sun.star.table.CellAddress')
+ sheet = doc.Sheets.getByName(SheetName)
+ # the index of the sheet in the doc, 0-based
+ aPosition.Sheet = sheet.getRangeAddress().Sheet
+
+ addressObj = sheet.getCellRangeByName(rangeReference)
+ # (com.sun.star.table.CellRangeAddress){ Sheet = (short)0x0, StartColumn = (long)0x0, StartRow = (long)0x0, EndColumn = (long)0x5, EndRow = (long)0xd }
+ address = addressObj.getRangeAddress()
+
+ aPosition.Column = address.StartColumn
+ aPosition.Row = address.StartRow
+
+ doc.NamedRanges.addNewByName(aName, aContent, aPosition, 0)
+
+ return None
+
+def NamedRanges():
+ """The main function to be shown on the user interface."""
+ ctx = uno.getComponentContext()
+ smgr = ctx.ServiceManager
+ desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
+
+ # Create a blank spreadsheet document, instead of damaging the existing document.
+ doc = desktop.loadComponentFromURL("private:factory/scalc", "_blank", 0, ())
+
+ # Create a new sheet to store our output information
+ doc.Sheets.insertNewByName("Information", 1)
+ infoSheet = doc.Sheets.getByName("Information")
+
+ # Set text in the information sheet
+ infoSheet.getCellRangeByName("A1").String = "Operation"
+ infoSheet.getCellRangeByName("B1").String = "Name of Cell Range"
+ infoSheet.getCellRangeByName("C1").String = "Content of Named Cell Range"
+
+ # Format the information header row
+ infoHeaderRange = infoSheet.getCellRangeByName("A1:C1")
+ # 2 = CENTER, see enum CellHoriJustify in https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1table.html
+ infoHeaderRange.HoriJustify = 2
+ infoHeaderRange.CellBackColor = 0xdee6ef
+
+ # Defines the named range test_range1
+ dataSheetName = "data"
+ doc.Sheets[0].Name = dataSheetName
+ DefineNamedRange(doc, dataSheetName, "test_range1", "$A$1:$F$14")
+
+ # Displays the named range information
+ test_range1 = doc.NamedRanges.getByName("test_range1")
+ infoSheet.getCellRangeByName("A2").String = "Defined test_range1"
+ infoSheet.getCellRangeByName("B2").String = test_range1.Name
+ infoSheet.getCellRangeByName("C2").String = test_range1.Content
+
+ # Revise the named ranges.
+ DefineNamedRange(doc, dataSheetName, "test_range1", "$A$1:$A$10")
+ infoSheet.getCellRangeByName("A3").String = "Revised test_range1"
+ infoSheet.getCellRangeByName("B3").String = test_range1.Name
+ infoSheet.getCellRangeByName("C3").String = test_range1.Content
+
+ # Defines the named range test_range2
+ DefineNamedRange(doc, dataSheetName, "test_range2", "$B$1:$B$10")
+ test_range2 = doc.NamedRanges.getByName("test_range2")
+ infoSheet.getCellRangeByName("A4").String = "Defined test_range2"
+ infoSheet.getCellRangeByName("B4").String = test_range2.Name
+ infoSheet.getCellRangeByName("C4").String = test_range2.Content
+
+ # Set data to test_range1 and test_range2
+
+ dataSheet = doc.Sheets.getByName(dataSheetName)
+ # You should use a tuple for setDataArray. For range e.g. A1:E1 it should
+ # be in the form tuple((1,2,3,4,5)), and for range e.g. A1:A5 it should be
+ # in the form tuple((1,), (2,), (3,), (4,), (5,)).
+ data1 = tuple(((1,),(2,),(3,),(4,),(5,),(6,),(7,),(8,),(9,),(10,)))
+ dataSheet.getCellRangeByName(test_range1.Content).setDataArray(data1)
+ infoSheet.getCellRangeByName("A5").String = "Set value to test_range1"
+
+ data2 = tuple(((2,),(4,),(6,),(8,),(10,),(12,),(14,),(16,),(18,),(20,)))
+ dataSheet.getCellRangeByName(test_range2.Content).setDataArray(data2)
+ infoSheet.getCellRangeByName("A6").String = "Set value to test_range2"
+
+ # Calculate sum of test_range1
+ infoSheet.getCellRangeByName("A8").String = "Sum of test_range1:"
+ infoSheet.getCellRangeByName("B8").Formula = "=SUM(test_range1)"
+
+ # Calculate sum of test_range2
+ infoSheet.getCellRangeByName("A9").String = "Sum of test_range2:"
+ infoSheet.getCellRangeByName("B9").Formula = "=SUM(test_range2)"
+
+ # Calculate the difference between the two ranges
+ infoSheet.getCellRangeByName("A10").String = "sum(test_range2) - sum(test_range1):"
+ infoSheet.getCellRangeByName("B10").Formula = "=B9-B8"
+
+ # Format the sum header columns
+ infoSheet.getCellRangeByName("A8:A10").CellBackColor = 0xdee6ef
+
+ # Set column width
+ infoSheet.Columns.getByName("A").Width = 5590
+ infoSheet.Columns.getByName("B").Width = 4610
+ infoSheet.Columns.getByName("C").Width = 4610
+
+g_exportedScripts = (NamedRanges,)
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/scripting/examples/python/SetCellColor.py b/scripting/examples/python/SetCellColor.py
new file mode 100644
index 000000000..7319d621d
--- /dev/null
+++ b/scripting/examples/python/SetCellColor.py
@@ -0,0 +1,53 @@
+#
+# 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 .
+#
+import uno
+
+def _SetCellColor(sheet, cellRange, color):
+ """Sets the background of 'cellRange' in 'sheet', to 'color'."""
+ # https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1table_1_1XCellRange.html#a92c77dc3025ac50d55bf31bc80ab118f
+ cells = sheet.getCellRangeByName(cellRange)
+
+ # https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1table_1_1CellProperties.html
+ cells.CellBackColor = color
+
+def SetCellColor():
+ ctx = uno.getComponentContext()
+ smgr = ctx.ServiceManager
+ desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
+
+ # Create a blank spreadsheet document, instead of operating on the existing one
+ doc = desktop.loadComponentFromURL("private:factory/scalc", "_blank", 0, ())
+
+ # Select the first sheet in the spreadsheet (0-index based).
+ sheet = doc.Sheets[0]
+
+ # Call the above helper function to set color (in hex number).
+ # To get the hex number:
+ # 1. go to Calc, click toolbar dropdown "Background Color" > Custom Color;
+ # 2. Pick a color, copy the hex number and prefix it with "0x".
+ _SetCellColor(sheet, "C3:C21", 0x4021c9)
+ _SetCellColor(sheet, "D18:E21", 0x4021c9)
+ _SetCellColor(sheet, "G3:G21", 0x4021c9)
+ _SetCellColor(sheet, "H3:I5", 0x4021c9)
+ _SetCellColor(sheet, "I6:I21", 0x4021c9)
+ _SetCellColor(sheet, "H19:H21", 0x4021c9)
+
+ # You should get a nice "LO" in the spreadsheet!
+
+# Only the specified function will show in the Tools > Macro > Organize Macro dialog:
+g_exportedScripts = (SetCellColor,)
diff --git a/scripting/examples/python/TableSample.py b/scripting/examples/python/TableSample.py
new file mode 100644
index 000000000..0920bf8ad
--- /dev/null
+++ b/scripting/examples/python/TableSample.py
@@ -0,0 +1,131 @@
+#
+# 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 .
+#
+
+import uno
+
+# a UNO struct later needed to create a document
+from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
+from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
+from com.sun.star.awt import Size
+
+
+def insertTextIntoCell(table, cellName, text, color):
+ tableText = table.getCellByName(cellName)
+ cursor = tableText.createTextCursor()
+
+ cursor.setPropertyValue("CharColor", color)
+ tableText.setString(text)
+
+
+def createTable():
+ """Creates a new writer document and inserts a table with some data
+ (also known as the SWriter sample).
+ """
+ ctx = uno.getComponentContext()
+ smgr = ctx.ServiceManager
+ desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
+
+ # open a writer document
+ doc = desktop.loadComponentFromURL(
+ "private:factory/swriter", "_blank", 0, ())
+
+ text = doc.Text
+ cursor = text.createTextCursor()
+ text.insertString(
+ cursor,
+ "The first line in the newly created text document.\n",
+ 0)
+ text.insertString(
+ cursor,
+ "Now we are in the second line\n",
+ 0)
+
+ # create a text table
+ table = doc.createInstance("com.sun.star.text.TextTable")
+
+ # with 4 rows and 4 columns
+ table.initialize(4, 4)
+
+ text.insertTextContent(cursor, table, 0)
+ rows = table.Rows
+
+ table.setPropertyValue("BackTransparent", uno.Bool(0))
+ table.setPropertyValue("BackColor", 13421823)
+ row = rows.getByIndex(0)
+ row.setPropertyValue("BackTransparent", uno.Bool(0))
+ row.setPropertyValue("BackColor", 6710932)
+
+ textColor = 16777215
+
+ insertTextIntoCell(table, "A1", "FirstColumn", textColor)
+ insertTextIntoCell(table, "B1", "SecondColumn", textColor)
+ insertTextIntoCell(table, "C1", "ThirdColumn", textColor)
+ insertTextIntoCell(table, "D1", "SUM", textColor)
+
+ table.getCellByName("A2").setValue(22.5)
+ table.getCellByName("B2").setValue(5615.3)
+ table.getCellByName("C2").setValue(-2315.7)
+ table.getCellByName("D2").setFormula("sum <A2:C2>")
+
+ table.getCellByName("A3").setValue(21.5)
+ table.getCellByName("B3").setValue(615.3)
+ table.getCellByName("C3").setValue(-315.7)
+ table.getCellByName("D3").setFormula("sum <A3:C3>")
+
+ table.getCellByName("A4").setValue(121.5)
+ table.getCellByName("B4").setValue(-615.3)
+ table.getCellByName("C4").setValue(415.7)
+ table.getCellByName("D4").setFormula("sum <A4:C4>")
+
+ cursor.setPropertyValue("CharColor", 255)
+ cursor.setPropertyValue("CharShadowed", uno.Bool(1))
+
+ text.insertControlCharacter(cursor, PARAGRAPH_BREAK, 0)
+ text.insertString(
+ cursor,
+ "This is a colored Text - blue with shadow\n",
+ 0)
+ text.insertControlCharacter(cursor, PARAGRAPH_BREAK, 0)
+
+ textFrame = doc.createInstance("com.sun.star.text.TextFrame")
+ textFrame.setSize(Size(15000, 400))
+ textFrame.setPropertyValue("AnchorType", AS_CHARACTER)
+
+ text.insertTextContent(cursor, textFrame, 0)
+
+ textInTextFrame = textFrame.getText()
+ cursorInTextFrame = textInTextFrame.createTextCursor()
+ textInTextFrame.insertString(
+ cursorInTextFrame,
+ "The first line in the newly created text frame.",
+ 0)
+ textInTextFrame.insertString(
+ cursorInTextFrame,
+ "\nWith this second line the height of the rame raises.",
+ 0)
+ text.insertControlCharacter(cursor, PARAGRAPH_BREAK, 0)
+
+ cursor.setPropertyValue("CharColor", 65536)
+ cursor.setPropertyValue("CharShadowed", uno.Bool(0))
+
+ text.insertString(cursor, "That's all for now !!", 0)
+
+
+g_exportedScripts = createTable,
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/scripting/java/Framework/MANIFEST.MF b/scripting/java/Framework/MANIFEST.MF
new file mode 100644
index 000000000..4945b96d1
--- /dev/null
+++ b/scripting/java/Framework/MANIFEST.MF
@@ -0,0 +1,2 @@
+RegistrationClassName: com.sun.star.script.framework.security.SecurityDialog
+UNO-Type-Path:
diff --git a/scripting/java/Framework/com/sun/star/script/framework/security/SecurityDialog.java b/scripting/java/Framework/com/sun/star/script/framework/security/SecurityDialog.java
new file mode 100644
index 000000000..078f63395
--- /dev/null
+++ b/scripting/java/Framework/com/sun/star/script/framework/security/SecurityDialog.java
@@ -0,0 +1,583 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.security;
+
+import com.sun.star.awt.ActionEvent;
+import com.sun.star.awt.ItemEvent;
+import com.sun.star.awt.XButton;
+import com.sun.star.awt.XCheckBox;
+import com.sun.star.awt.XControl;
+import com.sun.star.awt.XControlContainer;
+import com.sun.star.awt.XControlModel;
+import com.sun.star.awt.XDialog;
+import com.sun.star.awt.XToolkit;
+import com.sun.star.awt.XWindow;
+
+import com.sun.star.beans.XPropertySet;
+
+import com.sun.star.comp.loader.FactoryHelper;
+
+import com.sun.star.container.XNameContainer;
+
+import com.sun.star.lang.EventObject;
+import com.sun.star.lang.IllegalArgumentException;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XInitialization;
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lang.XSingleServiceFactory;
+
+import com.sun.star.lib.uno.helper.WeakBase;
+
+import com.sun.star.registry.XRegistryKey;
+
+import com.sun.star.script.framework.log.LogUtils;
+
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.RuntimeException;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+public class SecurityDialog extends WeakBase implements
+ XComponent, XServiceInfo, XDialog, XInitialization {
+
+ static final String __serviceName =
+ "com.sun.star.script.framework.security.SecurityDialog";
+
+ private static final String _label1Name = "Label1";
+
+ private static final String _label1String =
+ "This document contains macros. Do you want to allow these macros to be run?";
+
+ private static final String _label2Name = "Label2";
+
+ private static final String _label2String =
+ "This document contains macros. According to the security settings, the";
+
+ private static final String _label3Name = "Label3";
+
+ private static final String _label3String =
+ "macros in this document should not be run. Do you want to run them";
+
+ private static final String _label4Name = "Label4";
+ private static final String _label4String = "anyway?";
+
+ private static final String _checkBoxName = "CheckBox";
+
+ private static final String _checkBoxString =
+ "Add this directory to the list of secure paths: ";
+
+ private static final String _label5Name = "Label5";
+
+ private static final String _title = "Run Macro";
+ private static final String _runMacro = "Run";
+ private static final String _runButtonName = "Run";
+ private static final String _doNotRunMacro = "Do Not Run";
+ private static final String _doNotRunButtonName = "DoNotRun";
+
+ private static final int dialogX = 100;
+ private static final int dialogY = 100;
+ private static final int dialogW = 235;
+ private static final int dialogH = 47;
+
+ private int cbIncrW = -20;
+ private int cbIncrH = 19;
+
+ private static final int runButtonW = 40;
+ private static final int runButtonH = 13;
+ private static final int doNotRunButtonW = 40;
+ private static final int doNotRunButtonH = 13;
+
+ // label for warning dialog
+ private static final int label1X = 20;
+ private static final int label1Y = 9;
+ private static final int label1W = 210;
+ private static final int label1H = 10;
+
+ // labels for confirmation dialog
+ private static final int label2X = 22;
+ private static final int label2Y = 7;
+ private static final int label2W = 210;
+ private static final int label2H = 8;
+ private static final int label3X = 22;
+ private static final int label3Y = 15;
+ private static final int label3W = 210;
+ private static final int label3H = 8;
+ private static final int label4X = 22;
+ private static final int label4Y = 23;
+ private static final int label4W = 210;
+ private static final int label4H = 8;
+
+ // checkbox for confirmation dialog
+ private static final int checkBoxX = 22;
+ private static final int checkBoxY = 40;
+ private static final int checkBoxW = 210;
+ private static final int checkBoxH = 9;
+ // extra label if path longer than 21 chars
+ private static final int label5X = 22;
+ private static final int label5Y = 48;
+ private static final int label5W = 210;
+ private static final int label5H = 9;
+
+ private boolean checkBoxDialog;
+ private short _checkBoxState = 0;
+ private boolean extraPathLine = false;
+ private String checkBoxPath = "";
+ private String checkBoxPath2 = "";
+ private static final int lineWrapLength = 21;
+ private static final int lineWrapH = 12;
+ private String _pushed = _doNotRunButtonName;
+
+ private final XComponentContext _xComponentContext;
+ private XDialog _xDialog;
+
+ public SecurityDialog(XComponentContext xComponentContext) {
+ LogUtils.DEBUG("SecurityDialog ctor");
+ _xComponentContext = xComponentContext;
+ }
+
+ public void initialize(Object[] args) throws RuntimeException {
+ LogUtils.DEBUG("SecurityDialog init");
+
+ // figure out if we need a checkbox
+ if (args.length == 1 && AnyConverter.isString(args[0])) {
+ //check args is a path
+ // set checkBoxPath with the arg
+ LogUtils.DEBUG("checkbox");
+
+ try {
+ checkBoxPath = AnyConverter.toString(args[0]);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ }
+
+ LogUtils.DEBUG("path: " + checkBoxPath);
+ checkBoxDialog = true;
+
+ if (checkBoxPath.length() > lineWrapLength) {
+ extraPathLine = true;
+ cbIncrH += lineWrapH;
+ checkBoxPath2 = checkBoxPath.substring(lineWrapLength);
+ checkBoxPath = checkBoxPath.substring(0, lineWrapLength);
+ }
+
+ } else {
+ LogUtils.DEBUG("no checkbox: # of args=" + args.length);
+ cbIncrW = 0;
+ cbIncrH = 0;
+ checkBoxDialog = false;
+ }
+
+ // now try and create the dialog
+ try {
+ _xDialog = createDialog();
+ } catch (com.sun.star.uno.Exception e) {
+ throw new RuntimeException(e);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ // static component operations
+ public static XSingleServiceFactory __getServiceFactory(String implName,
+ XMultiServiceFactory multiFactory, XRegistryKey regKey) {
+
+ XSingleServiceFactory xSingleServiceFactory = null;
+
+ if (implName.equals(SecurityDialog.class.getName())) {
+
+ xSingleServiceFactory =
+ FactoryHelper.getServiceFactory(SecurityDialog.class,
+ SecurityDialog.__serviceName,
+ multiFactory, regKey);
+
+ }
+
+ return xSingleServiceFactory;
+ }
+
+ // XServiceInfo
+ public String getImplementationName() {
+ return getClass().getName();
+ }
+
+ // XServiceInfo
+ public boolean supportsService(/*IN*/String serviceName) {
+ return serviceName.equals(__serviceName);
+ }
+
+ // XServiceInfo
+ public String[] getSupportedServiceNames() {
+ String[] retValue = new String[1];
+ retValue[0] = __serviceName;
+ return retValue;
+ }
+
+ /** method for creating a dialog at runtime
+ */
+ private XDialog createDialog() throws com.sun.star.uno.Exception {
+
+ // get the service manager from the component context
+ XMultiComponentFactory xMultiComponentFactory =
+ _xComponentContext.getServiceManager();
+
+ // create the dialog model and set the properties
+ Object dialogModel =
+ xMultiComponentFactory.createInstanceWithContext(
+ "com.sun.star.awt.UnoControlDialogModel", _xComponentContext);
+
+ XPropertySet xPSetDialog =
+ UnoRuntime.queryInterface(XPropertySet.class, dialogModel);
+
+ xPSetDialog.setPropertyValue("PositionX", Integer.valueOf(dialogX));
+ xPSetDialog.setPropertyValue("PositionY", Integer.valueOf(dialogY));
+ xPSetDialog.setPropertyValue("Width", Integer.valueOf(dialogW + cbIncrW));
+ xPSetDialog.setPropertyValue("Height", Integer.valueOf(dialogH + cbIncrH));
+ xPSetDialog.setPropertyValue("Title", _title);
+
+ // get the service manager from the dialog model
+ XMultiServiceFactory xMultiServiceFactory =
+ UnoRuntime.queryInterface(XMultiServiceFactory.class, dialogModel);
+
+ // create the Run Macro button model and set the properties
+ Object runButtonModel =
+ xMultiServiceFactory.createInstance(
+ "com.sun.star.awt.UnoControlButtonModel");
+
+ XPropertySet xPSetButton =
+ UnoRuntime.queryInterface(XPropertySet.class, runButtonModel);
+
+ LogUtils.DEBUG("run: x=" + (((dialogW + cbIncrW) / 2) - runButtonW - 1));
+ LogUtils.DEBUG("run: y=" + (dialogH + cbIncrH - runButtonH - 1));
+
+ xPSetButton.setPropertyValue(
+ "PositionX", Integer.valueOf((((dialogW + cbIncrW) / 2) - runButtonW - 1)));
+
+ xPSetButton.setPropertyValue(
+ "PositionY", Integer.valueOf(dialogH + cbIncrH - runButtonH - 1));
+
+ xPSetButton.setPropertyValue("Width", Integer.valueOf(runButtonW));
+ xPSetButton.setPropertyValue("Height", Integer.valueOf(runButtonH));
+ xPSetButton.setPropertyValue("Name", _runButtonName);
+ xPSetButton.setPropertyValue("TabIndex", Short.valueOf((short)1));
+ xPSetButton.setPropertyValue("Label", _runMacro);
+
+ // create the Don't Run Macro button model and set the properties
+ Object doNotRunButtonModel =
+ xMultiServiceFactory.createInstance(
+ "com.sun.star.awt.UnoControlButtonModel");
+
+ xPSetButton =
+ UnoRuntime.queryInterface(XPropertySet.class, doNotRunButtonModel);
+
+ LogUtils.DEBUG("dontrun: x=" + (((dialogW + cbIncrW) / 2) - 1));
+ LogUtils.DEBUG("dontrun: y=" + (dialogH + cbIncrH - doNotRunButtonH - 1));
+
+ xPSetButton.setPropertyValue(
+ "PositionX", Integer.valueOf((((dialogW + cbIncrW) / 2) + 1)));
+
+ xPSetButton.setPropertyValue(
+ "PositionY", Integer.valueOf((dialogH + cbIncrH - doNotRunButtonH - 1)));
+
+ xPSetButton.setPropertyValue("Width", Integer.valueOf(doNotRunButtonW));
+ xPSetButton.setPropertyValue("Height", Integer.valueOf(doNotRunButtonH));
+ xPSetButton.setPropertyValue("Name", _doNotRunButtonName);
+ xPSetButton.setPropertyValue("TabIndex", Short.valueOf((short)0));
+ xPSetButton.setPropertyValue("Label", _doNotRunMacro);
+
+ // insert the control models into the dialog model
+ XNameContainer xNameCont =
+ UnoRuntime.queryInterface(XNameContainer.class, dialogModel);
+
+ xNameCont.insertByName(_runButtonName, runButtonModel);
+ xNameCont.insertByName(_doNotRunButtonName, doNotRunButtonModel);
+
+ if (checkBoxDialog) {
+ LogUtils.DEBUG("creating label & checkbox");
+
+ // create the label model and set the properties
+ Object label2Model =
+ xMultiServiceFactory.createInstance(
+ "com.sun.star.awt.UnoControlFixedTextModel");
+
+ XPropertySet xPSetLabel =
+ UnoRuntime.queryInterface(XPropertySet.class, label2Model);
+
+ xPSetLabel.setPropertyValue("PositionX", Integer.valueOf(label2X));
+ xPSetLabel.setPropertyValue("PositionY", Integer.valueOf(label2Y));
+ xPSetLabel.setPropertyValue("Width", Integer.valueOf(label2W));
+ xPSetLabel.setPropertyValue("Height", Integer.valueOf(label2H));
+ xPSetLabel.setPropertyValue("Name", _label2Name);
+ xPSetLabel.setPropertyValue("TabIndex", Short.valueOf((short)1));
+ xPSetLabel.setPropertyValue("Label", _label2String);
+
+ // create the label model and set the properties
+ Object label3Model =
+ xMultiServiceFactory.createInstance(
+ "com.sun.star.awt.UnoControlFixedTextModel");
+
+ XPropertySet xPSetLabel3 =
+ UnoRuntime.queryInterface(XPropertySet.class, label3Model);
+
+ xPSetLabel3.setPropertyValue("PositionX", Integer.valueOf(label3X));
+ xPSetLabel3.setPropertyValue("PositionY", Integer.valueOf(label3Y));
+ xPSetLabel3.setPropertyValue("Width", Integer.valueOf(label3W));
+ xPSetLabel3.setPropertyValue("Height", Integer.valueOf(label3H));
+ xPSetLabel3.setPropertyValue("Name", _label3Name);
+ xPSetLabel3.setPropertyValue("TabIndex", Short.valueOf((short)1));
+ xPSetLabel3.setPropertyValue("Label", _label3String);
+
+ // create the label model and set the properties
+ Object label4Model =
+ xMultiServiceFactory.createInstance(
+ "com.sun.star.awt.UnoControlFixedTextModel");
+
+ XPropertySet xPSetLabel4 =
+ UnoRuntime.queryInterface(XPropertySet.class, label4Model);
+
+ xPSetLabel4.setPropertyValue("PositionX", Integer.valueOf(label4X));
+ xPSetLabel4.setPropertyValue("PositionY", Integer.valueOf(label4Y));
+ xPSetLabel4.setPropertyValue("Width", Integer.valueOf(label4W));
+ xPSetLabel4.setPropertyValue("Height", Integer.valueOf(label4H));
+ xPSetLabel4.setPropertyValue("Name", _label4Name);
+ xPSetLabel4.setPropertyValue("TabIndex", Short.valueOf((short)1));
+ xPSetLabel4.setPropertyValue("Label", _label4String);
+
+ // create the checkbox model and set the properties
+ Object checkBoxModel =
+ xMultiServiceFactory.createInstance(
+ "com.sun.star.awt.UnoControlCheckBoxModel");
+
+ XPropertySet xPSetCheckBox =
+ UnoRuntime.queryInterface(XPropertySet.class, checkBoxModel);
+
+ xPSetCheckBox.setPropertyValue("PositionX", Integer.valueOf(checkBoxX));
+ xPSetCheckBox.setPropertyValue("PositionY", Integer.valueOf(checkBoxY));
+ xPSetCheckBox.setPropertyValue("Width", Integer.valueOf(checkBoxW));
+ xPSetCheckBox.setPropertyValue("Height", Integer.valueOf(checkBoxH));
+ xPSetCheckBox.setPropertyValue("State", Short.valueOf((short)0));
+ xPSetCheckBox.setPropertyValue("Name", _checkBoxName);
+ xPSetCheckBox.setPropertyValue("TabIndex", Short.valueOf((short)1));
+ xPSetCheckBox.setPropertyValue("Label", _checkBoxString + checkBoxPath);
+
+ // insert the control models into the dialog model
+ xNameCont.insertByName(_label2Name, label2Model);
+ xNameCont.insertByName(_label3Name, label3Model);
+ xNameCont.insertByName(_label4Name, label4Model);
+ xNameCont.insertByName(_checkBoxName, checkBoxModel);
+
+ if (extraPathLine) {
+
+ // create the label model and set the properties
+ Object label5Model =
+ xMultiServiceFactory.createInstance(
+ "com.sun.star.awt.UnoControlFixedTextModel");
+
+ XPropertySet xPSetLabel5 =
+ UnoRuntime.queryInterface(XPropertySet.class, label5Model);
+
+ xPSetLabel5.setPropertyValue("PositionX", Integer.valueOf(label5X));
+ xPSetLabel5.setPropertyValue("PositionY", Integer.valueOf(label5Y));
+ xPSetLabel5.setPropertyValue("Width", Integer.valueOf(label5W));
+ xPSetLabel5.setPropertyValue("Height", Integer.valueOf(label5H));
+ xPSetLabel5.setPropertyValue("Name", _label5Name);
+ xPSetLabel5.setPropertyValue("TabIndex", Short.valueOf((short)1));
+ xPSetLabel5.setPropertyValue("Label", checkBoxPath2);
+ xNameCont.insertByName(_label5Name, label5Model);
+ }
+ } else {
+ // create the label model and set the properties
+ Object labelModel =
+ xMultiServiceFactory.createInstance(
+ "com.sun.star.awt.UnoControlFixedTextModel");
+
+ XPropertySet xPSetLabel =
+ UnoRuntime.queryInterface(XPropertySet.class, labelModel);
+
+ xPSetLabel.setPropertyValue("PositionX", Integer.valueOf(label1X));
+ xPSetLabel.setPropertyValue("PositionY", Integer.valueOf(label1Y));
+ xPSetLabel.setPropertyValue("Width", Integer.valueOf(label1W));
+ xPSetLabel.setPropertyValue("Height", Integer.valueOf(label1H));
+ xPSetLabel.setPropertyValue("Name", _label1Name);
+ xPSetLabel.setPropertyValue("TabIndex", Short.valueOf((short)1));
+ xPSetLabel.setPropertyValue("Label", _label1String);
+
+ // insert the control models into the dialog model
+ xNameCont.insertByName(_label1Name, labelModel);
+ }
+
+ // create the dialog control and set the model
+ Object dialog =
+ xMultiComponentFactory.createInstanceWithContext(
+ "com.sun.star.awt.UnoControlDialog", _xComponentContext);
+
+ XControl xControl =
+ UnoRuntime.queryInterface(XControl.class, dialog);
+
+ XControlModel xControlModel =
+ UnoRuntime.queryInterface(XControlModel.class, dialogModel);
+
+ xControl.setModel(xControlModel);
+
+ // add an action listener to the button control
+ XControlContainer xControlCont =
+ UnoRuntime.queryInterface(XControlContainer.class, dialog);
+
+ // Add to yes button
+ Object objectButton = xControlCont.getControl(_runButtonName);
+
+ XButton xButton =
+ UnoRuntime.queryInterface(XButton.class, objectButton);
+
+ xButton.addActionListener(new ActionListenerImpl(_runButtonName));
+
+ // add to no button
+ objectButton = xControlCont.getControl(_doNotRunButtonName);
+
+ xButton =
+ UnoRuntime.queryInterface(XButton.class, objectButton);
+
+ xButton.addActionListener(new ActionListenerImpl(_doNotRunButtonName));
+
+ if (checkBoxDialog) {
+ // add to checkbox
+ Object objectCheckBox = xControlCont.getControl(_checkBoxName);
+
+ XCheckBox xCheckBox =
+ UnoRuntime.queryInterface(XCheckBox.class, objectCheckBox);
+
+ xCheckBox.addItemListener(new ItemListenerImpl(xControlCont));
+ }
+
+ // create a peer
+ Object toolkit =
+ xMultiComponentFactory.createInstanceWithContext(
+ "com.sun.star.awt.ExtToolkit", _xComponentContext);
+
+ XToolkit xToolkit = UnoRuntime.queryInterface(XToolkit.class, toolkit);
+ XWindow xWindow = UnoRuntime.queryInterface(XWindow.class, xControl);
+ xWindow.setVisible(false);
+ xControl.createPeer(xToolkit, null);
+
+ // return the dialog
+ XDialog xDialog = UnoRuntime.queryInterface(XDialog.class, dialog);
+ return xDialog;
+ }
+
+ public short execute() {
+
+ short result = 0;
+ _pushed = _doNotRunButtonName;
+ LogUtils.DEBUG("*DF* Before execute ");
+ _xDialog.execute();
+ LogUtils.DEBUG("*DF* After execute ");
+
+ if (_pushed.equals(_runButtonName)) {
+ result += 1;
+ }
+
+ if (_checkBoxState == 1) {
+ result += 2;
+ }
+
+ return result;
+ }
+
+ public void endExecute() {
+ _xDialog.endExecute();
+ }
+
+ public String getTitle() {
+ return _xDialog.getTitle();
+ }
+
+ public void setTitle(String Title) {
+ _xDialog.setTitle(Title);
+ }
+
+ public void dispose() {
+
+ XComponent xComponent =
+ UnoRuntime.queryInterface(XComponent.class, _xDialog);
+
+ xComponent.dispose();
+ }
+
+ public void addEventListener(com.sun.star.lang.XEventListener xListener) {
+
+ XComponent xComponent =
+ UnoRuntime.queryInterface(XComponent.class, _xDialog);
+
+ xComponent.addEventListener(xListener);
+ }
+
+ public void removeEventListener(com.sun.star.lang.XEventListener aListener) {
+
+ XComponent xComponent =
+ UnoRuntime.queryInterface(XComponent.class, _xDialog);
+
+ xComponent.removeEventListener(aListener);
+ }
+
+ private class ActionListenerImpl implements com.sun.star.awt.XActionListener {
+
+ private final String _buttonName;
+
+ private ActionListenerImpl(String buttonName) {
+ _buttonName = buttonName;
+ }
+
+ // XEventListener
+ public void disposing(EventObject eventObject) {
+ }
+
+ // XActionListener
+ public void actionPerformed(ActionEvent actionEvent) {
+ _pushed = _buttonName;
+ LogUtils.DEBUG("** Button pushed ->" + _pushed);
+ _xDialog.endExecute();
+ }
+ }
+
+ private class ItemListenerImpl implements com.sun.star.awt.XItemListener {
+
+ private XCheckBox _xCheckBox;
+
+ private ItemListenerImpl(XControlContainer xControlCont) {
+ Object objectCheckBox = xControlCont.getControl(_checkBoxName);
+
+ _xCheckBox =
+ UnoRuntime.queryInterface(XCheckBox.class, objectCheckBox);
+
+ }
+
+ // XEventListener
+ public void disposing(EventObject eventObject) {
+ _xCheckBox = null;
+ }
+
+ // XAdjustmentListener
+ public void itemStateChanged(ItemEvent itemEvent) {
+ _checkBoxState = _xCheckBox.getState();
+ LogUtils.DEBUG("** checkbox state ->" + _checkBoxState);
+ }
+ }
+}
diff --git a/scripting/java/ScriptFramework.component b/scripting/java/ScriptFramework.component
new file mode 100644
index 000000000..3a81f7bd8
--- /dev/null
+++ b/scripting/java/ScriptFramework.component
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.Java2"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.script.framework.security.SecurityDialog">
+ <service name="com.sun.star.script.framework.security.SecurityDialog"/>
+ </implementation>
+</component>
diff --git a/scripting/java/ScriptProviderForBeanShell.component b/scripting/java/ScriptProviderForBeanShell.component
new file mode 100644
index 000000000..c6ea8c404
--- /dev/null
+++ b/scripting/java/ScriptProviderForBeanShell.component
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.Java2"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.script.framework.provider.beanshell.ScriptProviderForBeanShell$ScriptProviderForBeanShell_2">
+ <service name="com.sun.star.script.browse.BrowseNode"/>
+ <service name="com.sun.star.script.provider.LanguageScriptProvider"/>
+ <service name="com.sun.star.script.provider.ScriptProvider"/>
+ <service name="com.sun.star.script.provider.ScriptProviderForBeanShell"/>
+ </implementation>
+</component>
diff --git a/scripting/java/ScriptProviderForJava.component b/scripting/java/ScriptProviderForJava.component
new file mode 100644
index 000000000..1ad936b17
--- /dev/null
+++ b/scripting/java/ScriptProviderForJava.component
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.Java2"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.script.framework.provider.java.ScriptProviderForJava$_ScriptProviderForJava">
+ <service name="com.sun.star.script.browse.BrowseNode"/>
+ <service name="com.sun.star.script.provider.LanguageScriptProvider"/>
+ <service name="com.sun.star.script.provider.ScriptProvider"/>
+ <service name="com.sun.star.script.provider.ScriptProviderForJava"/>
+ </implementation>
+</component>
diff --git a/scripting/java/ScriptProviderForJavaScript.component b/scripting/java/ScriptProviderForJavaScript.component
new file mode 100644
index 000000000..6e6f1f4c1
--- /dev/null
+++ b/scripting/java/ScriptProviderForJavaScript.component
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.Java2"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.script.framework.provider.javascript.ScriptProviderForJavaScript$ScriptProviderForJavaScript_2">
+ <service name="com.sun.star.script.browse.BrowseNode"/>
+ <service name="com.sun.star.script.provider.LanguageScriptProvider"/>
+ <service name="com.sun.star.script.provider.ScriptProvider"/>
+ <service name="com.sun.star.script.provider.ScriptProviderForJavaScript"/>
+ </implementation>
+</component>
diff --git a/scripting/java/com/sun/star/script/framework/browse/DialogFactory.java b/scripting/java/com/sun/star/script/framework/browse/DialogFactory.java
new file mode 100644
index 000000000..08cfba4c8
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/browse/DialogFactory.java
@@ -0,0 +1,255 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.browse;
+
+import com.sun.star.awt.XButton;
+import com.sun.star.awt.XControl;
+import com.sun.star.awt.XControlContainer;
+import com.sun.star.awt.XControlModel;
+import com.sun.star.awt.XDialog;
+import com.sun.star.awt.XTextComponent;
+import com.sun.star.awt.XToolkit;
+import com.sun.star.awt.XWindow;
+
+import com.sun.star.beans.XPropertySet;
+
+import com.sun.star.container.XNameContainer;
+
+import com.sun.star.lang.EventObject;
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lang.XMultiServiceFactory;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+public class DialogFactory {
+
+ private static DialogFactory factory;
+ private final XComponentContext xComponentContext;
+
+ // singleton
+ private DialogFactory(XComponentContext xComponentContext) {
+ this.xComponentContext = xComponentContext;
+ }
+
+ public static void createDialogFactory(XComponentContext xComponentContext) {
+ synchronized (DialogFactory.class) {
+ if (factory == null) {
+ factory = new DialogFactory(xComponentContext);
+ }
+ }
+ }
+
+ public static DialogFactory getDialogFactory() throws java.lang.Exception {
+ if (factory == null) {
+ throw new java.lang.Exception("DialogFactory not initialized");
+ }
+ return factory;
+ }
+
+ public String showInputDialog(String title, String prompt) {
+ final XDialog xDialog;
+
+ try {
+ xDialog = createInputDialog(title, prompt);
+ } catch (com.sun.star.uno.Exception e) {
+ return null;
+ }
+
+ // add an action listener to the button controls
+ XControlContainer controls =
+ UnoRuntime.queryInterface(XControlContainer.class, xDialog);
+
+ XButton okButton =
+ UnoRuntime.queryInterface(XButton.class, controls.getControl("Ok"));
+
+ okButton.setActionCommand("Ok");
+
+ XButton cancelButton =
+ UnoRuntime.queryInterface(XButton.class, controls.getControl("Cancel"));
+
+ cancelButton.setActionCommand("Cancel");
+
+ final XTextComponent textField =
+ UnoRuntime.queryInterface(XTextComponent.class,
+ controls.getControl("NameField"));
+
+ final ResultHolder resultHolder = new ResultHolder();
+
+ com.sun.star.awt.XActionListener listener =
+ new com.sun.star.awt.XActionListener() {
+ public void actionPerformed(com.sun.star.awt.ActionEvent e) {
+ if (e.ActionCommand.equals("Cancel")) {
+ resultHolder.setResult(null);
+ xDialog.endExecute();
+ } else {
+ resultHolder.setResult(textField.getText());
+ xDialog.endExecute();
+ }
+ }
+
+ public void disposing(EventObject o) {
+ // does nothing
+ }
+ };
+
+ okButton.addActionListener(listener);
+ cancelButton.addActionListener(listener);
+
+ xDialog.execute();
+
+ return (String)resultHolder.getResult();
+ }
+
+ private void setDimensions(Object o, int x, int y, int width, int height) throws
+ com.sun.star.uno.Exception {
+
+ XPropertySet props = UnoRuntime.queryInterface(XPropertySet.class, o);
+
+ props.setPropertyValue("PositionX", Integer.valueOf(x));
+ props.setPropertyValue("PositionY", Integer.valueOf(y));
+ props.setPropertyValue("Height", Integer.valueOf(height));
+ props.setPropertyValue("Width", Integer.valueOf(width));
+ }
+
+ private XDialog createInputDialog(String title, String prompt) throws
+ com.sun.star.uno.Exception {
+
+ if (title == null || title.length() == 0) {
+ title = "Scripting Framework";
+ }
+
+ if (prompt == null || prompt.length() == 0) {
+ prompt = "Enter name";
+ }
+
+ // get the service manager from the component context
+ XMultiComponentFactory xMultiComponentFactory =
+ xComponentContext.getServiceManager();
+
+ // create the dialog model and set the properties
+ Object dialogModel = xMultiComponentFactory.createInstanceWithContext(
+ "com.sun.star.awt.UnoControlDialogModel",
+ xComponentContext);
+
+ setDimensions(dialogModel, 100, 100, 157, 58);
+
+ XPropertySet props =
+ UnoRuntime.queryInterface(XPropertySet.class, dialogModel);
+
+ props.setPropertyValue("Title", title);
+
+ // get the service manager from the dialog model
+ XMultiServiceFactory xMultiServiceFactory =
+ UnoRuntime.queryInterface(XMultiServiceFactory.class, dialogModel);
+
+ // create the label model and set the properties
+ Object label = xMultiServiceFactory.createInstance(
+ "com.sun.star.awt.UnoControlFixedTextModel");
+
+ setDimensions(label, 15, 5, 134, 12);
+
+ XPropertySet labelProps =
+ UnoRuntime.queryInterface(XPropertySet.class, label);
+
+ labelProps.setPropertyValue("Name", "PromptLabel");
+ labelProps.setPropertyValue("Label", prompt);
+
+ // create the text field
+ Object edit = xMultiServiceFactory.createInstance(
+ "com.sun.star.awt.UnoControlEditModel");
+
+ setDimensions(edit, 15, 18, 134, 12);
+
+ XPropertySet editProps =
+ UnoRuntime.queryInterface(XPropertySet.class, edit);
+
+ editProps.setPropertyValue("Name", "NameField");
+
+ // create the OK button
+ Object okButtonModel = xMultiServiceFactory.createInstance(
+ "com.sun.star.awt.UnoControlButtonModel");
+
+ setDimensions(okButtonModel, 40, 39, 38, 15);
+
+ XPropertySet buttonProps =
+ UnoRuntime.queryInterface(XPropertySet.class, okButtonModel);
+
+ buttonProps.setPropertyValue("Name", "Ok");
+ buttonProps.setPropertyValue("Label", "Ok");
+
+ // create the Cancel button
+ Object cancelButtonModel = xMultiServiceFactory.createInstance(
+ "com.sun.star.awt.UnoControlButtonModel");
+
+ setDimensions(cancelButtonModel, 83, 39, 38, 15);
+
+ buttonProps =
+ UnoRuntime.queryInterface(XPropertySet.class, cancelButtonModel);
+
+ buttonProps.setPropertyValue("Name", "Cancel");
+ buttonProps.setPropertyValue("Label", "Cancel");
+
+ // insert the control models into the dialog model
+ XNameContainer xNameCont =
+ UnoRuntime.queryInterface(XNameContainer.class, dialogModel);
+
+ xNameCont.insertByName("PromptLabel", label);
+ xNameCont.insertByName("NameField", edit);
+ xNameCont.insertByName("Ok", okButtonModel);
+ xNameCont.insertByName("Cancel", cancelButtonModel);
+
+ // create the dialog control and set the model
+ Object dialog = xMultiComponentFactory.createInstanceWithContext(
+ "com.sun.star.awt.UnoControlDialog",
+ xComponentContext);
+
+ XControl xControl = UnoRuntime.queryInterface(XControl.class, dialog);
+
+ XControlModel xControlModel =
+ UnoRuntime.queryInterface(XControlModel.class, dialogModel);
+
+ xControl.setModel(xControlModel);
+
+ // create a peer
+ Object toolkit = xMultiComponentFactory.createInstanceWithContext(
+ "com.sun.star.awt.ExtToolkit",
+ xComponentContext);
+
+ XToolkit xToolkit = UnoRuntime.queryInterface(XToolkit.class, toolkit);
+ XWindow xWindow = UnoRuntime.queryInterface(XWindow.class, xControl);
+ xWindow.setVisible(false);
+ xControl.createPeer(xToolkit, null);
+
+ return UnoRuntime.queryInterface(XDialog.class, dialog);
+ }
+
+ private static class ResultHolder {
+
+ private Object result = null;
+
+ public Object getResult() {
+ return result;
+ }
+
+ public void setResult(Object result) {
+ this.result = result;
+ }
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/browse/ParcelBrowseNode.java b/scripting/java/com/sun/star/script/framework/browse/ParcelBrowseNode.java
new file mode 100644
index 000000000..cdb8715a5
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/browse/ParcelBrowseNode.java
@@ -0,0 +1,309 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.browse;
+
+import com.sun.star.beans.XIntrospectionAccess;
+
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lib.uno.helper.PropertySet;
+
+import com.sun.star.script.XInvocation;
+import com.sun.star.script.browse.BrowseNodeTypes;
+import com.sun.star.script.browse.XBrowseNode;
+import com.sun.star.script.framework.container.Parcel;
+import com.sun.star.script.framework.container.ParcelContainer;
+import com.sun.star.script.framework.container.ScriptEntry;
+import com.sun.star.script.framework.container.ScriptMetaData;
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.ScriptProvider;
+
+import com.sun.star.ucb.XSimpleFileAccess;
+
+import com.sun.star.uno.Any;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.swing.JOptionPane;
+
+public class ParcelBrowseNode extends PropertySet implements
+ XBrowseNode, XInvocation {
+
+ private final ScriptProvider provider;
+ private Collection<XBrowseNode> browsenodes;
+ private final ParcelContainer container;
+ private Parcel parcel;
+ // these four are properties, they are accessed via reflection
+ public boolean deletable = true;
+ public boolean editable = false;
+ public boolean creatable = false;
+ public boolean renamable = true;
+
+ public ParcelBrowseNode(ScriptProvider provider, ParcelContainer container,
+ String parcelName) throws
+ com.sun.star.container.NoSuchElementException,
+ com.sun.star.lang.WrappedTargetException {
+
+ this.provider = provider;
+ this.container = container;
+
+ this.parcel = (Parcel)this.container.getByName(parcelName);
+
+ registerProperty("Deletable", new Type(boolean.class), (short)0, "deletable");
+ registerProperty("Editable", new Type(boolean.class), (short)0, "editable");
+ registerProperty("Creatable", new Type(boolean.class), (short)0, "creatable");
+ registerProperty("Renamable", new Type(boolean.class), (short)0, "renamable");
+ if (provider.hasScriptEditor())
+ {
+ this.creatable = true;
+ }
+
+ String parcelDirUrl = parcel.getPathToParcel();
+ XComponentContext xCtx = provider.getScriptingContext().getComponentContext();
+ XMultiComponentFactory xFac = xCtx.getServiceManager();
+
+ try {
+ XSimpleFileAccess xSFA = UnoRuntime.queryInterface(XSimpleFileAccess.class,
+ xFac.createInstanceWithContext(
+ "com.sun.star.ucb.SimpleFileAccess",
+ xCtx));
+ if ( xSFA != null && ( xSFA.isReadOnly( parcelDirUrl ) ||
+ container.isUnoPkg() ) )
+ {
+ deletable = false;
+ editable = false;
+ creatable = false;
+ renamable = false;
+ }
+ } catch (com.sun.star.uno.Exception e) {
+ // TODO propagate potential errors
+ LogUtils.DEBUG("Caught exception creating ParcelBrowseNode " + e);
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ }
+
+ }
+
+ public String getName() {
+ return parcel.getName();
+ }
+
+ public XBrowseNode[] getChildNodes() {
+ try {
+
+ if (hasChildNodes()) {
+ String[] names = parcel.getElementNames();
+ browsenodes = new ArrayList<XBrowseNode>(names.length);
+
+ for (String name : names) {
+ browsenodes.add(new ScriptBrowseNode(provider, parcel, name));
+ }
+ } else {
+ LogUtils.DEBUG("ParcelBrowseNode.getChildeNodes no children ");
+ return new XBrowseNode[0];
+ }
+ } catch (Exception e) {
+ LogUtils.DEBUG("Failed to getChildeNodes, exception: " + e);
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ return new XBrowseNode[0];
+ }
+
+ return browsenodes.toArray(new XBrowseNode[browsenodes.size()]);
+ }
+
+ public boolean hasChildNodes() {
+ if (container != null && parcel != null && container.hasByName(getName())) {
+ return parcel.hasElements();
+ }
+
+ return false;
+ }
+
+ public short getType() {
+ return BrowseNodeTypes.CONTAINER;
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ // implementation of XInvocation interface
+ public XIntrospectionAccess getIntrospection() {
+ return null;
+ }
+
+ public Object invoke(String aFunctionName, Object[] aParams,
+ short[][] aOutParamIndex, Object[][] aOutParam) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.script.CannotConvertException,
+ com.sun.star.reflection.InvocationTargetException {
+
+ LogUtils.DEBUG("ParcelBrowseNode invoke for " + aFunctionName);
+
+ // Initialise the out parameters - not used but prevents error in
+ // UNO bridge
+ aOutParamIndex[0] = new short[0];
+ aOutParam[0] = new Object[0];
+
+ Any result = new Any(new Type(Boolean.class), Boolean.TRUE);
+
+ if (aFunctionName.equals("Creatable")) {
+ try {
+ String newName;
+
+ if (aParams == null || aParams.length < 1
+ || !AnyConverter.isString(aParams[0])) {
+
+ String prompt = "Enter name for new Script";
+ String title = "Create Script";
+
+ // try to get a DialogFactory instance, if it fails
+ // just use a Swing JOptionPane to prompt for the name
+ try {
+ DialogFactory dialogFactory = DialogFactory.getDialogFactory();
+ newName = dialogFactory.showInputDialog(title, prompt);
+ } catch (Exception e) {
+
+ newName = JOptionPane.showInputDialog(null, prompt, title,
+ JOptionPane.QUESTION_MESSAGE);
+
+ }
+ } else {
+ newName = AnyConverter.toString(aParams[0]);
+ }
+
+ if (newName == null || newName.length() == 0) {
+ result = new Any(new Type(Boolean.class), Boolean.FALSE);
+ } else {
+ String source = provider.getScriptEditor().getTemplate();
+
+ String languageName =
+ newName + "." + provider.getScriptEditor().getExtension();
+
+ String language = container.getLanguage();
+
+ ScriptEntry entry = new ScriptEntry(language, languageName);
+
+ Parcel parcel = (Parcel)container.getByName(getName());
+ ScriptMetaData data = new ScriptMetaData(parcel, entry, source);
+ parcel.insertByName(languageName, data);
+
+ ScriptBrowseNode sbn =
+ new ScriptBrowseNode(provider, parcel, languageName);
+
+ if (browsenodes == null) {
+ LogUtils.DEBUG("browsenodes null!!");
+ browsenodes = new ArrayList<XBrowseNode>(4);
+ }
+
+ browsenodes.add(sbn);
+ result = new Any(new Type(XBrowseNode.class), sbn);
+ }
+ } catch (Exception e) {
+ LogUtils.DEBUG("ParcelBrowseNode[create] failed with: " + e);
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ result = new Any(new Type(Boolean.class), Boolean.FALSE);
+ }
+ } else if (aFunctionName.equals("Deletable")) {
+ try {
+ if (container.deleteParcel(getName())) {
+ result = new Any(new Type(Boolean.class), Boolean.TRUE);
+ } else {
+ result = new Any(new Type(Boolean.class), Boolean.FALSE);
+ }
+ } catch (Exception e) {
+ result = new Any(new Type(Boolean.class), Boolean.FALSE);
+ }
+ } else if (aFunctionName.equals("Renamable")) {
+
+ String newName = null;
+
+ try {
+
+ if (aParams == null || aParams.length < 1 ||
+ !AnyConverter.isString(aParams[0])) {
+ String prompt = "Enter new name for Library";
+ String title = "Rename Library";
+
+ // try to get a DialogFactory instance, if it fails
+ // just use a Swing JOptionPane to prompt for the name
+ try {
+ DialogFactory dialogFactory = DialogFactory.getDialogFactory();
+ newName = dialogFactory.showInputDialog(title, prompt);
+ } catch (Exception e) {
+
+ newName = JOptionPane.showInputDialog(null, prompt, title,
+ JOptionPane.QUESTION_MESSAGE);
+
+ }
+ } else {
+ newName = AnyConverter.toString(aParams[0]);
+ }
+
+ container.renameParcel(getName(), newName);
+ Parcel p = (Parcel)container.getByName(newName);
+
+ if (browsenodes == null) {
+ getChildNodes();
+ }
+
+ ScriptBrowseNode[] childNodes =
+ browsenodes.toArray(new ScriptBrowseNode[browsenodes.size()]);
+
+ for (int index = 0; index < childNodes.length; index++) {
+ childNodes[ index ].updateURI(p);
+ }
+
+ result = new Any(new Type(XBrowseNode.class), this);
+ } catch (Exception e) {
+ result = new Any(new Type(Boolean.class), Boolean.FALSE);
+ }
+ }
+
+ else {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "Function " + aFunctionName + " not supported.");
+ }
+
+ return result;
+ }
+
+ public void setValue(String aPropertyName, Object aValue) throws
+ com.sun.star.beans.UnknownPropertyException,
+ com.sun.star.script.CannotConvertException,
+ com.sun.star.reflection.InvocationTargetException {
+ }
+
+ public Object getValue(String aPropertyName) throws
+ com.sun.star.beans.UnknownPropertyException {
+ return null;
+ }
+
+ public boolean hasMethod(String aName) {
+ return false;
+ }
+
+ public boolean hasProperty(String aName) {
+ return false;
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/browse/PkgProviderBrowseNode.java b/scripting/java/com/sun/star/script/framework/browse/PkgProviderBrowseNode.java
new file mode 100644
index 000000000..6cdfd2a77
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/browse/PkgProviderBrowseNode.java
@@ -0,0 +1,49 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.browse;
+
+import com.sun.star.script.framework.container.ParcelContainer;
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.ScriptProvider;
+
+import com.sun.star.uno.XComponentContext;
+
+public class PkgProviderBrowseNode extends ProviderBrowseNode {
+
+ public PkgProviderBrowseNode(ScriptProvider provider, ParcelContainer container,
+ XComponentContext xCtx) {
+
+ super(provider, container, xCtx);
+
+ LogUtils.DEBUG("*** PkgProviderBrowseNode ctor container name = " +
+ container.getName());
+ LogUtils.DEBUG("*** PkgProviderBrowseNode ctor container path = " +
+ container.getParcelContainerDir());
+ LogUtils.DEBUG("*** PkgProviderBrowseNode ctor, container has num parcels = " +
+ container.getElementNames().length);
+ deletable = false;
+ editable = false;
+ creatable = false;
+ }
+
+ @Override public String getName() {
+ return (container != null) ? container.getName() : "Unknown";
+ }
+
+}
diff --git a/scripting/java/com/sun/star/script/framework/browse/ProviderBrowseNode.java b/scripting/java/com/sun/star/script/framework/browse/ProviderBrowseNode.java
new file mode 100644
index 000000000..91c2566be
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/browse/ProviderBrowseNode.java
@@ -0,0 +1,264 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.browse;
+
+import com.sun.star.beans.XIntrospectionAccess;
+
+import com.sun.star.lang.XMultiComponentFactory;
+
+import com.sun.star.lib.uno.helper.PropertySet;
+
+import com.sun.star.script.XInvocation;
+import com.sun.star.script.browse.BrowseNodeTypes;
+import com.sun.star.script.browse.XBrowseNode;
+import com.sun.star.script.framework.container.ParcelContainer;
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.ScriptProvider;
+
+import com.sun.star.ucb.XSimpleFileAccess;
+
+import com.sun.star.uno.Any;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.swing.JOptionPane;
+
+public class ProviderBrowseNode extends PropertySet implements
+ XBrowseNode, XInvocation {
+
+ private final ScriptProvider provider;
+ private Collection<XBrowseNode> browsenodes;
+ private final String name;
+ protected ParcelContainer container;
+ private final XComponentContext m_xCtx;
+ // these are properties, they are accessed by reflection
+ public boolean deletable = true;
+ public boolean creatable = true;
+ public boolean editable = false;
+
+ public ProviderBrowseNode(ScriptProvider provider, ParcelContainer container,
+ XComponentContext xCtx) {
+
+ LogUtils.DEBUG("*** ProviderBrowseNode ctor");
+ this.container = container;
+ this.name = this.container.getLanguage();
+ this.provider = provider;
+ this.m_xCtx = xCtx;
+
+ registerProperty("Deletable", new Type(boolean.class), (short)0, "deletable");
+ registerProperty("Creatable", new Type(boolean.class), (short)0, "creatable");
+ registerProperty("Editable", new Type(boolean.class), (short)0, "editable");
+ XMultiComponentFactory xFac = m_xCtx.getServiceManager();
+
+ try {
+ XSimpleFileAccess xSFA = UnoRuntime.queryInterface(XSimpleFileAccess.class,
+ xFac.createInstanceWithContext(
+ "com.sun.star.ucb.SimpleFileAccess",
+ xCtx));
+ if ( container.isUnoPkg() || xSFA.isReadOnly( container.getParcelContainerDir() ) )
+ {
+ deletable = false;
+ creatable = false;
+ }
+ }
+ // TODO propagate errors
+ catch (com.sun.star.uno.Exception e) {
+ LogUtils.DEBUG("Caught exception in creation of ProviderBrowseNode ");
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public XBrowseNode[] getChildNodes() {
+ LogUtils.DEBUG("***** ProviderBrowseNode.getChildNodes()");
+
+ if (hasChildNodes()) {
+
+ // needs initialisation?
+ LogUtils.DEBUG("** ProviderBrowseNode.getChildNodes(), container is " +
+ container);
+
+ String[] parcels = container.getElementNames();
+ browsenodes = new ArrayList<XBrowseNode>(parcels.length);
+
+ for (String parcel : parcels) {
+ try {
+ XBrowseNode node = new ParcelBrowseNode(provider, container, parcel);
+ browsenodes.add(node);
+ } catch (Exception e) {
+ LogUtils.DEBUG("*** Failed to create parcel node for " + parcel);
+ LogUtils.DEBUG(e.toString());
+ }
+ }
+
+ ParcelContainer[] packageContainers = container.getChildContainers();
+
+ LogUtils.DEBUG("**** For container named " + container.getName() +
+ " with root path " + container.getParcelContainerDir() +
+ " has " + packageContainers.length + " child containers ");
+
+ for (ParcelContainer packageContainer : packageContainers) {
+
+ XBrowseNode node =
+ new PkgProviderBrowseNode(provider, packageContainer, m_xCtx);
+
+ browsenodes.add(node);
+ }
+ } else {
+ LogUtils.DEBUG("*** No container available");
+ return new XBrowseNode[0];
+ }
+
+ return browsenodes.toArray(new XBrowseNode[browsenodes.size()]);
+ }
+
+ public boolean hasChildNodes() {
+ boolean result = true;
+
+ if (container == null ||
+ (!container.hasElements() && container.getChildContainers().length == 0)) {
+
+ result = false;
+ }
+
+ if (container == null) {
+ LogUtils.DEBUG("***** ProviderBrowseNode.hasChildNodes(): " + "name=" + name +
+ ", path=<none>, result=" + result);
+ } else {
+ LogUtils.DEBUG("***** ProviderBrowseNode.hasChildNodes(): " + "name=" + name +
+ ", path=" + container.getParcelContainerDir() + ", result=" + result);
+ }
+
+ return result;
+ }
+
+ public short getType() {
+ return BrowseNodeTypes.CONTAINER;
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ // implementation of XInvocation interface
+ public XIntrospectionAccess getIntrospection() {
+ return null;
+ }
+
+ public Object invoke(String aFunctionName, Object[] aParams,
+ short[][] aOutParamIndex, Object[][] aOutParam) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.script.CannotConvertException,
+ com.sun.star.reflection.InvocationTargetException {
+
+ // Initialise the out parameters - not used but prevents error in
+ // UNO bridge
+ aOutParamIndex[0] = new short[0];
+ aOutParam[0] = new Object[0];
+
+ Any result = new Any(new Type(Boolean.class), Boolean.TRUE);
+
+ if (aFunctionName.equals("Creatable")) {
+ try {
+ String name;
+
+ if (aParams == null || aParams.length < 1 ||
+ !AnyConverter.isString(aParams[0])) {
+
+ String prompt = "Enter name for new Parcel";
+ String title = "Create Parcel";
+
+ // try to get a DialogFactory instance, if it fails
+ // just use a Swing JOptionPane to prompt for the name
+ try {
+ DialogFactory dialogFactory = DialogFactory.getDialogFactory();
+ name = dialogFactory.showInputDialog(title, prompt);
+ } catch (Exception e) {
+
+ name = JOptionPane.showInputDialog(null, prompt, title,
+ JOptionPane.QUESTION_MESSAGE);
+
+ }
+ } else {
+ name = AnyConverter.toString(aParams[0]);
+ }
+
+ if (name == null || name.length() == 0) {
+ result = new Any(new Type(Boolean.class), Boolean.FALSE);
+ } else {
+
+ Object newParcel = container.createParcel(name);
+ LogUtils.DEBUG("Parcel created " + name + " " + newParcel);
+
+ if (newParcel == null) {
+ result = new Any(new Type(Boolean.class), Boolean.FALSE);
+ } else {
+ ParcelBrowseNode parcel = new ParcelBrowseNode(provider, container, name);
+ LogUtils.DEBUG("created parcel node ");
+
+ if (browsenodes == null) {
+ browsenodes = new ArrayList<XBrowseNode>(5);
+ }
+
+ browsenodes.add(parcel);
+ result = new Any(new Type(XBrowseNode.class), parcel);
+ }
+ }
+ } catch (Exception e) {
+ LogUtils.DEBUG("ProviderBrowseNode[create] failed with: " + e);
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ result = new Any(new Type(Boolean.class), Boolean.FALSE);
+ }
+ } else {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "Function " + aFunctionName + " not supported.");
+ }
+
+ return result;
+ }
+
+ public void setValue(String aPropertyName, Object aValue) throws
+ com.sun.star.beans.UnknownPropertyException,
+ com.sun.star.script.CannotConvertException,
+ com.sun.star.reflection.InvocationTargetException {
+ }
+
+ public Object getValue(String aPropertyName) throws
+ com.sun.star.beans.UnknownPropertyException {
+
+ return null;
+ }
+
+ public boolean hasMethod(String aName) {
+ return false;
+ }
+
+ public boolean hasProperty(String aName) {
+ return false;
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/browse/ScriptBrowseNode.java b/scripting/java/com/sun/star/script/framework/browse/ScriptBrowseNode.java
new file mode 100644
index 000000000..5f91b1a78
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/browse/ScriptBrowseNode.java
@@ -0,0 +1,300 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.browse;
+
+import com.sun.star.beans.XIntrospectionAccess;
+
+import com.sun.star.container.ElementExistException;
+import com.sun.star.container.NoSuchElementException;
+
+import com.sun.star.lang.NoSupportException;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lang.XMultiComponentFactory;
+
+import com.sun.star.lib.uno.helper.PropertySet;
+
+import com.sun.star.reflection.InvocationTargetException;
+
+import com.sun.star.script.XInvocation;
+import com.sun.star.script.browse.BrowseNodeTypes;
+import com.sun.star.script.browse.XBrowseNode;
+import com.sun.star.script.framework.container.Parcel;
+import com.sun.star.script.framework.container.ScriptEntry;
+import com.sun.star.script.framework.container.ScriptMetaData;
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.ScriptProvider;
+import com.sun.star.script.provider.XScriptContext;
+
+import com.sun.star.ucb.XSimpleFileAccess;
+
+import com.sun.star.uno.Any;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+public class ScriptBrowseNode extends PropertySet implements
+ XBrowseNode, XInvocation {
+
+ private final ScriptProvider provider;
+
+ private Parcel parent;
+ private String name;
+
+ // these are properties, accessed by reflection
+ public String uri;
+ public String description;
+ public boolean editable;
+ public boolean deletable = false;
+ public boolean renamable = false;
+
+ public ScriptBrowseNode(ScriptProvider provider, Parcel parent, String name) {
+
+ this.provider = provider;
+ this.name = name;
+ this.parent = parent;
+ ScriptMetaData data = null;
+ XComponentContext xCtx = provider.getScriptingContext().getComponentContext();
+ XMultiComponentFactory xFac = xCtx.getServiceManager();
+
+ try {
+ data = parent.getByName( name );
+ XSimpleFileAccess xSFA = UnoRuntime.queryInterface(
+ XSimpleFileAccess.class,
+ xFac.createInstanceWithContext(
+ "com.sun.star.ucb.SimpleFileAccess",
+ xCtx));
+
+ uri = data.getShortFormScriptURL();
+ description = data.getDescription();
+ if (provider.hasScriptEditor()) {
+ this.editable = true;
+
+ try {
+ if (!parent.isUnoPkg()
+ && !xSFA.isReadOnly(parent.getPathToParcel())) {
+
+ this.deletable = true;
+ this.renamable = true;
+
+ }
+ }
+ // TODO propagate errors
+ catch (Exception e) {
+ LogUtils.DEBUG("Caught exception in creation of ScriptBrowseNode");
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ }
+
+ }
+
+ }
+ // TODO fix exception types to be caught here, should we rethrow?
+ catch (Exception e) {
+
+ LogUtils.DEBUG("** caught exception getting script data for " + name +
+ " ->" + e.toString());
+
+ }
+
+ registerProperty("Deletable", new Type(boolean.class), (short)0, "deletable");
+ registerProperty("Editable", new Type(boolean.class), (short)0, "editable");
+ registerProperty("Renamable", new Type(boolean.class), (short)0, "renamable");
+ registerProperty("URI", new Type(String.class), (short)0, "uri");
+ registerProperty("Description", new Type(String.class), (short)0,
+ "description");
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public XBrowseNode[] getChildNodes() {
+ return new XBrowseNode[0];
+ }
+
+ public boolean hasChildNodes() {
+ return false;
+ }
+
+ public short getType() {
+ return BrowseNodeTypes.SCRIPT;
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ public void updateURI(Parcel p) {
+ parent = p;
+
+ try {
+ ScriptMetaData data = parent.getByName(name);
+ uri = data.getShortFormScriptURL();
+ }
+ // TODO fix exception types to be caught here, should we rethrow?
+ catch (Exception e) {
+ LogUtils.DEBUG("** caught exception getting script data for " + name +
+ " ->" + e.toString());
+ }
+ }
+
+ // implementation of XInvocation interface
+ public XIntrospectionAccess getIntrospection() {
+ return null;
+ }
+
+ public Object invoke(String aFunctionName, Object[] aParams,
+ short[][] aOutParamIndex, Object[][] aOutParam) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.script.CannotConvertException,
+ com.sun.star.reflection.InvocationTargetException {
+
+ // Initialise the out parameters - not used but prevents error in
+ // UNO bridge
+ aOutParamIndex[0] = new short[0];
+ aOutParam[0] = new Object[0];
+
+ Any result = new Any(new Type(Boolean.class), Boolean.TRUE);
+
+ if (aFunctionName.equals("Editable")) {
+ if (!editable) {
+
+ NoSupportException nse =
+ new NoSupportException(aFunctionName + " is not editable ");
+
+ throw new InvocationTargetException(
+ "Scripting framework error editing script", null, nse);
+
+ }
+
+ XScriptContext ctxt = provider.getScriptingContext();
+ ScriptMetaData data = null;
+
+ try {
+ data = parent.getByName(name);
+ } catch (NoSuchElementException nse) {
+ throw new com.sun.star.lang.IllegalArgumentException(nse,
+ name + " does not exist or can't be found ");
+ } catch (com.sun.star.lang.WrappedTargetException wte) {
+ // rethrow
+ throw new InvocationTargetException(
+ "Scripting framework editing script ", null, wte.TargetException);
+ }
+
+ provider.getScriptEditor().edit(ctxt, data);
+ } else if (aFunctionName.equals("Deletable")) {
+ if (!deletable) {
+
+ NoSupportException nse = new NoSupportException(
+ aFunctionName + " is not supported for this node");
+
+ throw new InvocationTargetException(
+ "Scripting framework error deleting script", null, nse);
+ }
+
+ try {
+ parent.removeByName(name);
+ result = new Any(new Type(Boolean.class), Boolean.TRUE);
+ } catch (NoSuchElementException nse) {
+ throw new com.sun.star.lang.IllegalArgumentException(nse,
+ name + " does not exist or can't be found ");
+ } catch (WrappedTargetException wte) {
+ // rethrow
+ throw new InvocationTargetException(
+ "Scripting framework deleting script ", null, wte.TargetException);
+ }
+
+ } else if (aFunctionName.equals("Renamable")) {
+ result = new Any(new Type(XBrowseNode.class), new XBrowseNode[0]);
+
+ if (!renamable) {
+
+ NoSupportException nse = new NoSupportException(
+ aFunctionName + " is not supported for this node");
+
+ throw new InvocationTargetException(
+ "Scripting framework error renaming script", null, nse);
+ }
+
+ try {
+ String newName = AnyConverter.toString(aParams[0]);
+ ScriptMetaData oldData = parent.getByName(name);
+ oldData.loadSource();
+ String oldSource = oldData.getSource();
+
+ LogUtils.DEBUG("Create renamed script");
+
+ String languageName =
+ newName + "." + provider.getScriptEditor().getExtension();
+
+ String language = provider.getName();
+
+ ScriptEntry entry = new ScriptEntry(language, languageName);
+
+ ScriptMetaData data =
+ new ScriptMetaData(parent, entry, oldSource);
+
+ parent.insertByName(languageName, data);
+
+ LogUtils.DEBUG("Now remove old script");
+ parent.removeByName(name);
+
+ uri = data.getShortFormScriptURL();
+ name = languageName;
+ result = new Any(new Type(XBrowseNode.class), this);
+ } catch (NoSuchElementException nse) {
+ throw new com.sun.star.lang.IllegalArgumentException(nse,
+ name + " does not exist or can't be found ");
+ } catch (ElementExistException eee) {
+ // rethrow
+ throw new InvocationTargetException(
+ "Scripting framework error renaming script ", null, eee);
+ } catch (WrappedTargetException wte) {
+ // rethrow
+ throw new InvocationTargetException(
+ "Scripting framework rename script ", null, wte.TargetException);
+ }
+ } else {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "Function " + aFunctionName + " not supported.");
+ }
+
+ return result;
+ }
+
+ public void setValue(String aPropertyName, Object aValue) throws
+ com.sun.star.beans.UnknownPropertyException,
+ com.sun.star.script.CannotConvertException,
+ com.sun.star.reflection.InvocationTargetException {
+ }
+
+ public Object getValue(String aPropertyName) throws
+ com.sun.star.beans.UnknownPropertyException {
+
+ return null;
+ }
+
+ public boolean hasMethod(String aName) {
+ return false;
+ }
+
+ public boolean hasProperty(String aName) {
+ return false;
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/container/DeployedUnoPackagesDB.java b/scripting/java/com/sun/star/script/framework/container/DeployedUnoPackagesDB.java
new file mode 100644
index 000000000..c187fb0e1
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/container/DeployedUnoPackagesDB.java
@@ -0,0 +1,192 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.container;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.util.ArrayList;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class DeployedUnoPackagesDB {
+
+ // This is the default contents of a parcel descriptor to be used when
+ // creating empty descriptors
+ private static final byte[] EMPTY_DOCUMENT =
+ ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<unopackages xmlns:unopackages=\"unopackages.dtd\">\n" +
+ "</unopackages>").getBytes();
+
+ private Document document = null;
+
+ public DeployedUnoPackagesDB() throws IOException {
+
+ ByteArrayInputStream bis = null;
+
+ try {
+ bis = new ByteArrayInputStream(EMPTY_DOCUMENT);
+ this.document = XMLParserFactory.getParser().parse(bis);
+ } finally {
+ if (bis != null)
+ bis.close();
+ }
+ }
+
+ private DeployedUnoPackagesDB(Document document) {
+ this.document = document;
+ }
+
+ public DeployedUnoPackagesDB(InputStream is) throws IOException {
+ this(XMLParserFactory.getParser().parse(is));
+ }
+
+ public String[] getDeployedPackages(String language) {
+
+ ArrayList<String> packageUrls = new ArrayList<String>(4);
+ Element main = document.getDocumentElement();
+ Element root = null;
+ int len = 0;
+ NodeList langNodes = null;
+
+ if ((langNodes = main.getElementsByTagName("language")) != null &&
+ (len = langNodes.getLength()) != 0) {
+ for (int i = 0; i < len; i++) {
+ Element e = (Element)langNodes.item(i);
+
+ if (e.getAttribute("value").equals(language)) {
+ root = e;
+ break;
+ }
+ }
+ }
+
+ if (root != null) {
+ len = 0;
+ NodeList packages = null;
+
+ if ((packages = root.getElementsByTagName("package")) != null &&
+ (len = packages.getLength()) != 0) {
+
+ for (int i = 0; i < len; i++) {
+ Element e = (Element)packages.item(i);
+ packageUrls.add(e.getAttribute("value"));
+ }
+
+ }
+ }
+
+ if (!packageUrls.isEmpty()) {
+ return packageUrls.toArray(new String[packageUrls.size()]);
+ }
+
+ return new String[0];
+ }
+
+ public void write(OutputStream out) throws IOException {
+ XMLParserFactory.getParser().write(document, out);
+ }
+
+ public Document getDocument() {
+ return document;
+ }
+
+
+ public boolean removePackage(String language, String url) {
+
+ Element main = document.getDocumentElement();
+ Element langNode = null;
+ int len = 0;
+ NodeList langNodes = null;
+
+ if ((langNodes = main.getElementsByTagName("language")) != null &&
+ (len = langNodes.getLength()) != 0) {
+ for (int i = 0; i < len; i++) {
+ Element e = (Element)langNodes.item(i);
+
+ if (e.getAttribute("value").equals(language)) {
+ langNode = e;
+ break;
+ }
+ }
+ }
+
+ if (langNode == null) {
+ return false;
+ }
+ len = 0;
+ NodeList packages = null;
+ boolean result = false;
+
+ if ((packages = langNode.getElementsByTagName("package")) != null &&
+ (len = packages.getLength()) != 0) {
+ for (int i = 0; i < len; i++) {
+
+ Element e = (Element)packages.item(i);
+ String value = e.getAttribute("value");
+
+ if (value.equals(url)) {
+ langNode.removeChild(e);
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public void addPackage(String language, String url) {
+
+ Element main = document.getDocumentElement();
+ Element langNode = null;
+ Element pkgNode = null;
+
+ int len = 0;
+ NodeList langNodes = null;
+
+ if ((langNodes = document.getElementsByTagName("language")) != null &&
+ (len = langNodes.getLength()) != 0) {
+ for (int i = 0; i < len; i++) {
+ Element e = (Element)langNodes.item(i);
+
+ if (e.getAttribute("value").equals(language)) {
+ langNode = e;
+ break;
+ }
+ }
+ }
+
+ if (langNode == null) {
+ langNode = document.createElement("language");
+ langNode.setAttribute("value", language);
+ }
+
+ pkgNode = document.createElement("package");
+ pkgNode.setAttribute("value", url);
+
+ langNode.appendChild(pkgNode);
+ //add to the Top Element
+ main.appendChild(langNode);
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/container/Parcel.java b/scripting/java/com/sun/star/script/framework/container/Parcel.java
new file mode 100644
index 000000000..6be4cad99
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/container/Parcel.java
@@ -0,0 +1,302 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.container;
+
+import com.sun.star.container.ElementExistException;
+import com.sun.star.container.XNameContainer;
+
+import com.sun.star.script.framework.io.XInputStreamImpl;
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.PathUtils;
+
+import com.sun.star.ucb.XSimpleFileAccess;
+import com.sun.star.ucb.XSimpleFileAccess2;
+
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+public class Parcel implements XNameContainer {
+
+ private ParcelDescriptor m_descriptor;
+ private String name;
+ protected ParcelContainer parent;
+ protected XSimpleFileAccess m_xSFA;
+
+ public Parcel(XSimpleFileAccess xSFA, ParcelContainer parent,
+ ParcelDescriptor desc, String parcelName) {
+
+ this(parent, desc, parcelName);
+ this.m_xSFA = xSFA;
+ }
+
+ private Parcel(ParcelContainer parent, ParcelDescriptor desc,
+ String parcelName) {
+
+ this.parent = parent;
+ this.m_descriptor = desc;
+ this.name = parcelName;
+ }
+
+ /**
+ * Tests if this <tt>Parcel</tt> is in a UNO package
+ * or within a sub package within a UNO package
+ *
+ * @return <tt>true</tt> if has parent <tt>false</tt> otherwise
+ */
+ public boolean isUnoPkg() {
+ return parent.isUnoPkg();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public ScriptMetaData getByName(String aName) throws
+ com.sun.star.container.NoSuchElementException,
+ com.sun.star.lang.WrappedTargetException {
+
+ LogUtils.DEBUG("** Parcel.getByName for " + aName);
+ ScriptEntry thescript = null;
+
+ try {
+ if (m_descriptor != null && hasElements()) {
+ ScriptEntry[] scripts = m_descriptor.getScriptEntries();
+
+ if (scripts.length != 0) {
+ for (ScriptEntry script : scripts) {
+ if (script.getLanguageName().equals(aName)) {
+ thescript = script;
+ break;
+ }
+ }
+ }
+ }
+ }
+ // catch unknown or un-checked exceptions
+ catch (Exception e) {
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ }
+
+ if (thescript == null) {
+ LogUtils.DEBUG("No script for " + aName);
+ throw new com.sun.star.container.NoSuchElementException("No script named " +
+ aName);
+ }
+
+ ScriptMetaData data = new ScriptMetaData(this, thescript, null);
+
+ LogUtils.DEBUG("returning date for " + aName);
+ return data;
+ }
+
+ public String[] getElementNames() {
+
+ String[] results = new String[0];
+
+ if (m_descriptor != null) {
+ ScriptEntry[] scripts = m_descriptor.getScriptEntries();
+ results = new String[ scripts.length ];
+
+ for (int index = 0; index < scripts.length; index++) {
+ results[ index ] = scripts[ index ].getLanguageName();
+ }
+ }
+
+ return results;
+ }
+
+ public boolean hasByName(String aName) {
+
+ boolean result = true;
+ ScriptMetaData containee = null;
+
+ try {
+ containee = getByName(aName);
+
+ if (containee != null) {
+ result = true;
+ }
+ } catch (Exception e) {
+ result = false;
+ }
+
+ return result;
+ }
+
+ public com.sun.star.uno.Type getElementType() {
+ // TODO at the moment this returns void indicating
+ // type is unknown ( from UNO point of view this is correct )
+ // but, maybe we want to have a private UNO interface
+
+ return new Type();
+ }
+
+ public boolean hasElements() {
+ return m_descriptor != null && m_descriptor.getScriptEntries().length > 0;
+ }
+
+ public void replaceByName(String aName, java.lang.Object aElement) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.container.NoSuchElementException,
+ com.sun.star.lang.WrappedTargetException {
+
+ // TODO check type of aElement
+ // if not ok, throw IllegalArgument
+ if (m_descriptor != null) {
+ try {
+ ScriptMetaData script = getByName(aName);
+
+ if (script != null) {
+ //m_descriptor.removeScriptEntry( script );
+ // TODO needs to create source file ( if there is one )
+ //m_descriptor.write();
+ } else {
+ throw new com.sun.star.container.NoSuchElementException(
+ "No script named " + aName);
+ }
+
+ }
+ // TO DO should catch specified exceptions
+ catch (Exception ex) {
+ throw new com.sun.star.lang.WrappedTargetException(ex);
+ }
+
+ }
+ }
+
+ // create
+ public void insertByName(String aName, java.lang.Object aElement) throws
+ com.sun.star.lang.IllegalArgumentException, ElementExistException,
+ com.sun.star.lang.WrappedTargetException {
+
+ // TODO check the type of aElement and throw#
+ // if not appropriate
+ try {
+ if (hasByName(aName)) {
+ throw new ElementExistException(aName);
+ }
+
+ ScriptMetaData script = (ScriptMetaData)aElement;
+
+ if (script.hasSource()) {
+ LogUtils.DEBUG("Inserting source: " + script.getSource());
+
+ if (!script.writeSourceFile()) {
+ throw new com.sun.star.lang.WrappedTargetException(
+ "Failed to create source file " + script.getLanguageName());
+ }
+ }
+
+ m_descriptor.addScriptEntry(script);
+ writeParcelDescriptor();
+ } catch (Exception e) {
+ LogUtils.DEBUG("Failed to insert entry " + aName + ": " + e.getMessage());
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ }
+ }
+
+ private void writeParcelDescriptor()
+ throws com.sun.star.ucb.CommandAbortedException,
+ com.sun.star.io.IOException,
+ com.sun.star.uno.Exception, java.io.IOException {
+
+ String pathToDescriptor =
+ PathUtils.make_url(getPathToParcel(), ParcelDescriptor.PARCEL_DESCRIPTOR_NAME);
+
+ XSimpleFileAccess2 xSFA2 =
+ UnoRuntime.queryInterface(XSimpleFileAccess2.class, m_xSFA);
+
+ if (xSFA2 != null) {
+
+ ByteArrayOutputStream bos = null;
+ ByteArrayInputStream bis = null;
+ XInputStreamImpl xis = null;
+
+ try {
+ bos = new ByteArrayOutputStream(1024);
+ m_descriptor.write(bos);
+ bis = new ByteArrayInputStream(bos.toByteArray());
+
+ xis = new XInputStreamImpl(bis);
+ xSFA2.writeFile(pathToDescriptor, xis);
+ } finally {
+ if (bos != null) bos.close();
+
+ if (bis != null) bis.close();
+
+ if (xis != null) xis.closeInput();
+ }
+ }
+ }
+
+ // delete
+ public void removeByName(String Name) throws
+ com.sun.star.container.NoSuchElementException,
+ com.sun.star.lang.WrappedTargetException {
+
+ try {
+ ScriptMetaData script = getByName(Name);
+
+ if (script != null) {
+ if (!script.removeSourceFile()) {
+ LogUtils.DEBUG("** Parcel.removeByName Failed to remove script "
+ + Name);
+ throw new com.sun.star.lang.WrappedTargetException(
+ "Failed to remove script " + Name);
+ }
+
+ LogUtils.DEBUG("** Parcel.removeByName have removed script source file "
+ + Name);
+
+ m_descriptor.removeScriptEntry(script);
+ writeParcelDescriptor();
+ } else {
+ throw new com.sun.star.container.NoSuchElementException(
+ "No script named " + Name);
+ }
+
+ } catch (Exception e) {
+ LogUtils.DEBUG("** Parcel.removeByName Exception: " + e);
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ }
+
+ }
+
+ // rename parcel
+ public void rename(String name) {
+ this.name = name;
+ }
+
+ public ParcelContainer getParent() {
+ return parent;
+ }
+
+ /**
+ * Returns the path of this <tt>Parcel</tt>
+ *
+ * @return <tt>String</tt> path to parcel
+ */
+ public String getPathToParcel() {
+ String path = parent.getParcelContainerDir() + "/" + name;
+ return path;
+ }
+
+}
diff --git a/scripting/java/com/sun/star/script/framework/container/ParcelContainer.java b/scripting/java/com/sun/star/script/framework/container/ParcelContainer.java
new file mode 100644
index 000000000..4a2bece39
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/container/ParcelContainer.java
@@ -0,0 +1,725 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.container;
+
+import com.sun.star.container.ElementExistException;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.container.XNameContainer;
+
+import com.sun.star.io.XInputStream;
+
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lang.XMultiComponentFactory;
+
+import com.sun.star.script.framework.io.XInputStreamImpl;
+import com.sun.star.script.framework.io.XInputStreamWrapper;
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.PathUtils;
+
+import com.sun.star.ucb.XSimpleFileAccess;
+import com.sun.star.ucb.XSimpleFileAccess2;
+
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+import com.sun.star.uri.XUriReference;
+import com.sun.star.uri.XUriReferenceFactory;
+import com.sun.star.uri.XVndSunStarScriptUrl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.StringTokenizer;
+
+/**
+ * The <code>ParcelContainer</code> object is used to store the
+ * ScriptingFramework specific Libraries.
+ */
+public class ParcelContainer implements XNameAccess {
+
+ protected static XSimpleFileAccess m_xSFA;
+
+ protected String language;
+ protected String containerUrl;
+ private Collection<Parcel> parcels = new ArrayList<Parcel>(10);
+ protected XComponentContext m_xCtx;
+ private ParcelContainer parent = null;
+ private final Collection<ParcelContainer> childContainers = new ArrayList<ParcelContainer>(10);
+ private boolean isPkgContainer = false;
+
+ /**
+ * Tests if this <tt>ParcelContainer</tt> represents a UNO package
+ * or sub package within a UNO package
+ *
+ * @return <tt>true</tt> if has parent <tt>false</tt> otherwise
+ */
+ public boolean isUnoPkg() {
+ return isPkgContainer;
+ }
+
+ /**
+ * Returns this <tt>ParcelContainer</tt>'s parent
+ *
+ * @return <tt>ParcelContainer</tt> if has parent null otherwise
+ */
+ public ParcelContainer parent() {
+ return parent;
+ }
+
+ /**
+ * Returns all child <tt>ParcelContainer</tt>
+ * this instance of <tt>ParcelContainer</tt>
+ *
+ * @return a new array of ParcelContainers. A zero
+ * length array is returned if no child ParcelContainers.
+ */
+ public ParcelContainer[] getChildContainers() {
+ if (childContainers.isEmpty()) {
+ return new ParcelContainer[0];
+ }
+
+ return childContainers.toArray(new ParcelContainer[childContainers.size()]);
+ }
+
+ /**
+ * Removes a child <tt>ParcelContainer</tt>
+ * from this instance.
+ * @param child <tt>ParcelContainer</tt> to be added.
+ *
+ * @return <tt>true</tt> if child successfully removed
+ */
+ public boolean removeChildContainer(ParcelContainer child) {
+ return childContainers.remove(child);
+ }
+
+ /**
+ * Adds a new child <tt>ParcelContainer</tt>
+ * to this instance.
+ * @param child <tt>ParcelContainer</tt> to be added.
+ *
+ */
+ public void addChildContainer(ParcelContainer child) {
+ childContainers.add(child);
+ }
+
+ /**
+ * Returns a child <tt>ParcelContainer</tt> whose location
+ * matches the <tt>location</tt> argument passed to this method.
+ * @param key the <tt>location</tt> which is to
+ * be matched.
+ *
+ * @return child <tt>ParcelContainer</tt> or {@code null} if none
+ * found.
+ */
+ public ParcelContainer getChildContainer(String key) {
+ ParcelContainer result = null;
+
+ for (ParcelContainer c : childContainers) {
+
+ String name = c.getName();
+ if (name == null)
+ {
+ continue;
+ }
+
+ String location =
+ ScriptMetaData.getLocationPlaceHolder(c.containerUrl, name);
+
+ if (key.equals(location)) {
+ result = c;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a child <tt>ParcelContainer</tt> whose member
+ * <tt>containerUrl</tt> matches the <tt>containerUrl</tt>
+ * argument passed to this method.
+ * @param containerUrl the <tt>containerUrl</tt> which is to
+ * be matched.
+ *
+ * @return child <tt>ParcelContainer</tt> or {@code null} if none
+ * found.
+ */
+ public ParcelContainer getChildContainerForURL(String containerUrl) {
+ ParcelContainer result = null;
+
+ for (ParcelContainer c : childContainers) {
+ if (containerUrl.equals(c.containerUrl)) {
+ result = c;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns Name of this container. Name of this <tt>ParcelContainer</tt>
+ * is determined from the <tt>containerUrl</tt> as the last portion
+ * of the URL after the last forward slash.
+ * @return name of <tt>ParcelContainer</tt>
+ * found.
+ */
+ public String getName() {
+ String name = null;
+
+ // TODO handler package ParcelContainer?
+ if (!containerUrl.startsWith("vnd.sun.star.tdoc:")) {
+ try {
+ // return name
+ String decodedUrl = java.net.URLDecoder.decode(containerUrl, "UTF-8");
+ int indexOfSlash = decodedUrl.lastIndexOf('/');
+
+ if (indexOfSlash != -1) {
+ name = decodedUrl.substring(indexOfSlash + 1);
+ }
+ } catch (UnsupportedEncodingException e) {
+ throw new com.sun.star.uno.RuntimeException(e);
+ }
+ } else {
+ name = "document";
+ }
+
+ return name;
+ }
+
+ /**
+ * Initializes a newly created <code>ParcelContainer</code> object.
+ * @param xCtx UNO component context
+ * @param containerUrl location of this container.
+ * @param language language for which entries are stored
+ */
+ public ParcelContainer(XComponentContext xCtx, String containerUrl,
+ String language) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.lang.WrappedTargetException {
+
+ this(null, xCtx, containerUrl, language, true);
+ }
+
+ /**
+ * Initializes a newly created <code>ParcelContainer</code> object.
+ * @param xCtx UNO component context
+ * @param containerUrl location of this container.
+ * @param language language for which entries are stored
+ * @param loadParcels set to <tt>true</tt> if parcels are to be loaded
+ * on construction.
+ */
+ public ParcelContainer(XComponentContext xCtx, String containerUrl,
+ String language, boolean loadParcels) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.lang.WrappedTargetException {
+
+ this(null, xCtx, containerUrl, language, loadParcels);
+ }
+
+ /**
+ * Initializes a newly created <code>ParcelContainer</code> object.
+ * @param parent parent ParcelContainer
+ * @param xCtx UNO component context
+ * @param containerUrl location of this container.
+ * @param language language for which entries are stored
+ * @param loadParcels set to <tt>true</tt> if parcels are to be loaded
+ * on construction.
+ */
+ public ParcelContainer(ParcelContainer parent, XComponentContext xCtx,
+ String containerUrl, String language,
+ boolean loadParcels) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.lang.WrappedTargetException {
+
+ LogUtils.DEBUG("Creating ParcelContainer for " + containerUrl +
+ " loadParcels = " + loadParcels + " language = " + language);
+
+ this.m_xCtx = xCtx;
+ this.language = language;
+ this.parent = parent;
+ this.containerUrl = containerUrl;
+
+ initSimpleFileAccess();
+ boolean parentIsPkgContainer = false;
+
+ if (parent != null) {
+ parentIsPkgContainer = parent.isUnoPkg();
+ }
+
+ if (containerUrl.endsWith("uno_packages") || parentIsPkgContainer) {
+ isPkgContainer = true;
+ }
+
+ if (loadParcels) {
+ loadParcels();
+ }
+ }
+
+
+ public String getContainerURL() {
+ return this.containerUrl;
+ }
+
+ private void initSimpleFileAccess() {
+ synchronized (ParcelContainer.class) {
+ if (m_xSFA != null) {
+ return;
+ }
+
+ try {
+
+ m_xSFA = UnoRuntime.queryInterface(
+ XSimpleFileAccess.class,
+ m_xCtx.getServiceManager().createInstanceWithContext(
+ "com.sun.star.ucb.SimpleFileAccess", m_xCtx));
+
+ } catch (Exception e) {
+ // TODO should throw
+ LogUtils.DEBUG("Error instantiating simplefile access ");
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ }
+ }
+ }
+
+ public String getParcelContainerDir() {
+ // If this container does not represent a uno-package
+ // then it is a document, user or share
+ // in each case the convention is to have a Scripts/[language]
+ // dir where scripts reside
+ if (!isUnoPkg()) {
+ return PathUtils.make_url(containerUrl , "Scripts/" + language.toLowerCase());
+ }
+
+ return containerUrl;
+ }
+
+ public Object getByName(String aName) throws
+ com.sun.star.container.NoSuchElementException, WrappedTargetException {
+
+ Parcel parcel = null;
+
+ try {
+ if (hasElements()) {
+ for (Parcel parcelToCheck : parcels) {
+ if (parcelToCheck.getName().equals(aName)) {
+ parcel = parcelToCheck;
+ break;
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new WrappedTargetException(e);
+ }
+
+ if (parcel == null) {
+ throw new com.sun.star.container.NoSuchElementException("Macro Library " + aName
+ + " not found");
+ }
+
+ return parcel;
+ }
+
+ public String[] getElementNames() {
+
+ if (hasElements()) {
+
+ Parcel[] theParcels = parcels.toArray(new Parcel[parcels.size()]);
+ String[] names = new String[ theParcels.length ];
+
+ for (int count = 0; count < names.length; count++) {
+ names[count] = theParcels[ count ].getName();
+ }
+
+ return names;
+ }
+
+ return new String[0];
+ }
+
+ public boolean hasByName(String aName) {
+
+ boolean isFound = false;
+
+ try {
+ if (getByName(aName) != null) {
+ isFound = true;
+ }
+
+ } catch (Exception e) {
+ //TODO - handle trace
+ }
+
+ return isFound;
+ }
+
+ public Type getElementType() {
+ return new Type();
+ }
+
+ public boolean hasElements() {
+ return !(parcels == null || parcels.isEmpty());
+ }
+
+ private void loadParcels() throws com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.lang.WrappedTargetException {
+
+ try {
+ LogUtils.DEBUG("About to load parcels from " + containerUrl);
+
+ if (m_xSFA.isFolder(getParcelContainerDir())) {
+ LogUtils.DEBUG(getParcelContainerDir() + " is a folder ");
+ String[] children = m_xSFA.getFolderContents(getParcelContainerDir(), true);
+ parcels = new ArrayList<Parcel>(children.length);
+
+ for (String child : children) {
+ LogUtils.DEBUG("Processing " + child);
+
+ try {
+ loadParcel(child);
+ } catch (java.lang.Exception e) {
+ // print an error message and move on to
+ // the next parcel
+ LogUtils.DEBUG("ParcelContainer.loadParcels caught " + e.getClass().getName() +
+ " exception loading parcel " + child + ": " + e.getMessage());
+ }
+ }
+ } else {
+ LogUtils.DEBUG(" ParcelCOntainer.loadParcels " + getParcelContainerDir() +
+ " is not a folder ");
+ }
+
+ } catch (com.sun.star.ucb.CommandAbortedException e) {
+ LogUtils.DEBUG("ParcelContainer.loadParcels caught exception processing folders for "
+ + getParcelContainerDir());
+ LogUtils.DEBUG("TRACE: " + LogUtils.getTrace(e));
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ } catch (com.sun.star.uno.Exception e) {
+ LogUtils.DEBUG("ParcelContainer.loadParcels caught exception processing folders for "
+ + getParcelContainerDir());
+ LogUtils.DEBUG("TRACE: " + LogUtils.getTrace(e));
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ }
+ }
+
+ public XNameContainer createParcel(String name) throws
+ ElementExistException, com.sun.star.lang.WrappedTargetException {
+
+ Parcel p = null;
+
+ if (hasByName(name)) {
+ throw new ElementExistException("Parcel " + name + " already exists");
+ }
+
+ String pathToParcel = PathUtils.make_url(getParcelContainerDir(), name);
+
+ try {
+ LogUtils.DEBUG("ParcelContainer.createParcel, creating folder "
+ + pathToParcel);
+
+ m_xSFA.createFolder(pathToParcel);
+
+ LogUtils.DEBUG("ParcelContainer.createParcel, folder " + pathToParcel +
+ " created ");
+
+ ParcelDescriptor pd = new ParcelDescriptor();
+ pd.setLanguage(language);
+
+ String parcelDesc =
+ PathUtils.make_url(pathToParcel, ParcelDescriptor.PARCEL_DESCRIPTOR_NAME);
+
+ XSimpleFileAccess2 xSFA2 =
+ UnoRuntime.queryInterface(XSimpleFileAccess2.class, m_xSFA);
+
+ if (xSFA2 != null) {
+ LogUtils.DEBUG("createParcel() Using XSIMPLEFILEACCESS2 " + parcelDesc);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
+ pd.write(bos);
+ bos.close();
+ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+ XInputStreamImpl xis = new XInputStreamImpl(bis);
+ xSFA2.writeFile(parcelDesc, xis);
+ xis.closeInput();
+ p = loadParcel(pathToParcel);
+ }
+ } catch (Exception e) {
+ LogUtils.DEBUG("createParcel() Exception while attempting to create = "
+ + name);
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ }
+
+ return p;
+ }
+
+ public Parcel loadParcel(String parcelUrl) throws
+ com.sun.star.lang.WrappedTargetException,
+ com.sun.star.lang.IllegalArgumentException {
+
+ String parcelDescUrl =
+ PathUtils.make_url(parcelUrl, ParcelDescriptor.PARCEL_DESCRIPTOR_NAME);
+
+ Parcel parcel = null;
+ XInputStream xis = null;
+ InputStream is = null;
+
+ try {
+ if (m_xSFA.exists(parcelDescUrl)) {
+
+ LogUtils.DEBUG("ParcelContainer.loadParcel opening " + parcelDescUrl);
+
+ xis = m_xSFA.openFileRead(parcelDescUrl);
+ is = new XInputStreamWrapper(xis);
+ ParcelDescriptor pd = new ParcelDescriptor(is) ;
+
+ try {
+ is.close();
+ is = null;
+ } catch (Exception e) {
+ LogUtils.DEBUG(
+ "ParcelContainer.loadParcel Exception when closing stream for "
+ + parcelDescUrl + " :" + e);
+ }
+
+ LogUtils.DEBUG("ParcelContainer.loadParcel closed " + parcelDescUrl);
+
+ if (!pd.getLanguage().equals(language)) {
+ LogUtils.DEBUG("ParcelContainer.loadParcel Language of Parcel does not match this container ");
+ return null;
+ }
+
+ LogUtils.DEBUG("Processing " + parcelDescUrl + " closed ");
+
+ int indexOfSlash = parcelUrl.lastIndexOf('/');
+ String name = parcelUrl.substring(indexOfSlash + 1);
+
+ parcel = new Parcel(m_xSFA, this, pd, name);
+
+ LogUtils.DEBUG(" ParcelContainer.loadParcel created parcel for "
+ + parcelDescUrl + " for language " + language);
+
+ parcels.add(parcel);
+ } else {
+ throw new java.io.IOException(parcelDescUrl + " does NOT exist!");
+ }
+ } catch (com.sun.star.ucb.CommandAbortedException e) {
+ LogUtils.DEBUG("loadParcel() Exception while accessing filesystem url = "
+ + parcelDescUrl + e);
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ } catch (java.io.IOException e) {
+ LogUtils.DEBUG("ParcelContainer.loadParcel() caught IOException while accessing "
+ + parcelDescUrl + ": " + e);
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ } catch (com.sun.star.uno.Exception e) {
+ LogUtils.DEBUG("loadParcel() Exception while accessing filesystem url = "
+ + parcelDescUrl + e);
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ }
+
+ finally {
+ if (is != null) {
+ try {
+ is.close(); // is will close xis
+ } catch (Exception ignore) {
+ }
+ } else if (xis != null) {
+ try {
+ xis.closeInput();
+ } catch (Exception ignore) {
+ }
+ }
+ }
+
+ return parcel;
+ }
+ public void renameParcel(String oldName, String newName) throws
+ com.sun.star.container.NoSuchElementException,
+ com.sun.star.lang.WrappedTargetException {
+
+ LogUtils.DEBUG(" ** ParcelContainer Renaming parcel " + oldName + " to " +
+ newName);
+ LogUtils.DEBUG(" ** ParcelContainer is " + this);
+
+ Parcel p = (Parcel)getByName(oldName);
+
+ if (p == null) {
+ throw new com.sun.star.container.NoSuchElementException(
+ "No parcel named " + oldName);
+ }
+
+ String oldParcelDirUrl =
+ PathUtils.make_url(getParcelContainerDir(), oldName);
+
+ String newParcelDirUrl =
+ PathUtils.make_url(getParcelContainerDir(), newName);
+
+ try {
+ if (!m_xSFA.isFolder(oldParcelDirUrl)) {
+ Exception e = new com.sun.star.io.IOException(
+ "Invalid Parcel directory: " + oldName);
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ }
+
+ LogUtils.DEBUG(" ** ParcelContainer Renaming folder " + oldParcelDirUrl
+ + " to " + newParcelDirUrl);
+
+ m_xSFA.move(oldParcelDirUrl, newParcelDirUrl);
+
+ } catch (com.sun.star.ucb.CommandAbortedException ce) {
+ LogUtils.DEBUG(" ** ParcelContainer Renaming failed with " + ce);
+ throw new com.sun.star.lang.WrappedTargetException(ce);
+ } catch (com.sun.star.uno.Exception e) {
+ LogUtils.DEBUG(" ** ParcelContainer Renaming failed with " + e);
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ }
+
+ p.rename(newName);
+ }
+ // removes but doesn't physically delete parcel from container
+ public boolean removeParcel(String name) throws
+ com.sun.star.container.NoSuchElementException,
+ com.sun.star.lang.WrappedTargetException {
+
+ Parcel p = (Parcel)getByName(name);
+
+ if (p == null) {
+ throw new com.sun.star.container.NoSuchElementException(
+ "No parcel named " + name);
+ }
+
+ return parcels.remove(p);
+ }
+
+ public boolean deleteParcel(String name) throws
+ com.sun.star.container.NoSuchElementException,
+ com.sun.star.lang.WrappedTargetException {
+
+ LogUtils.DEBUG("deleteParcel for containerURL " + containerUrl
+ + " name = " + name + " Language = " + language);
+
+ Parcel p = (Parcel)getByName(name);
+
+ if (p == null) {
+ throw new com.sun.star.container.NoSuchElementException(
+ "No parcel named " + name);
+ }
+
+ try {
+ String pathToParcel = PathUtils.make_url(getParcelContainerDir(), name);
+ m_xSFA.kill(pathToParcel);
+ } catch (Exception e) {
+ LogUtils.DEBUG("Error deleting parcel " + name);
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ }
+
+ return parcels.remove(p);
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public ScriptMetaData findScript(ParsedScriptUri parsedUri) throws
+ com.sun.star.container.NoSuchElementException,
+ com.sun.star.lang.WrappedTargetException {
+
+ Parcel p = (Parcel)getByName(parsedUri.parcel);
+ ScriptMetaData scriptData = p.getByName(parsedUri.function);
+
+ LogUtils.DEBUG("** found script data for " + parsedUri.function + " script is "
+ + scriptData);
+
+ return scriptData;
+ }
+
+ public ParsedScriptUri parseScriptUri(String scriptURI) throws
+ com.sun.star.lang.IllegalArgumentException {
+
+ XMultiComponentFactory xMcFac = null;
+ XUriReferenceFactory xFac = null;
+
+ try {
+ xMcFac = m_xCtx.getServiceManager();
+
+ xFac = UnoRuntime.queryInterface(
+ XUriReferenceFactory.class, xMcFac.createInstanceWithContext(
+ "com.sun.star.uri.UriReferenceFactory", m_xCtx));
+
+ } catch (com.sun.star.uno.Exception e) {
+ LogUtils.DEBUG("Problems parsing URL:" + e.toString());
+ throw new com.sun.star.lang.IllegalArgumentException(
+ e, "Problems parsing URL");
+ }
+
+ if (xFac == null) {
+ LogUtils.DEBUG("Failed to create UrlReference factory");
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "Failed to create UrlReference factory for url " + scriptURI);
+ }
+
+ XUriReference uriRef = xFac.parse(scriptURI);
+
+ XVndSunStarScriptUrl sfUri =
+ UnoRuntime.queryInterface(XVndSunStarScriptUrl.class, uriRef);
+
+ if (sfUri == null) {
+ LogUtils.DEBUG("Failed to parse url");
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "Failed to parse url " + scriptURI);
+ }
+
+ ParsedScriptUri parsedUri = new ParsedScriptUri();
+ parsedUri.function = sfUri.getName();
+ parsedUri.parcel = "";
+
+ // parse parcel name;
+ StringTokenizer tokenizer = new StringTokenizer(parsedUri.function, ".");
+
+ if (tokenizer.hasMoreElements()) {
+ parsedUri.parcel = (String)tokenizer.nextElement();
+ LogUtils.DEBUG("** parcelName = " + parsedUri.parcel);
+ }
+
+ if (parsedUri.function.length() > 0) {
+
+ // strip out parcel name
+ parsedUri.function =
+ parsedUri.function.substring(parsedUri.parcel.length() + 1);
+
+ }
+
+ // parse location
+ parsedUri.location = sfUri.getParameter("location");
+
+ // TODO basic sanity check on language, location, function name, parcel
+ // should be correct e.g. verified by MSP and LangProvider by the
+ // time it's got to here
+
+ LogUtils.DEBUG("** location = " + parsedUri.location +
+ "\nfunction = " + parsedUri.function +
+ "\nparcel = " + parsedUri.parcel +
+ "\nlocation = " + parsedUri.location);
+
+ return parsedUri;
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/container/ParcelDescriptor.java b/scripting/java/com/sun/star/script/framework/container/ParcelDescriptor.java
new file mode 100644
index 000000000..eeb8f9ef2
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/container/ParcelDescriptor.java
@@ -0,0 +1,354 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.container;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.w3c.dom.CharacterData;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class ParcelDescriptor {
+
+ // File name to be used for parcel descriptor files
+ public static final String
+ PARCEL_DESCRIPTOR_NAME = "parcel-descriptor.xml";
+
+ // This is the default contents of a parcel descriptor to be used when
+ // creating empty descriptors
+ private static final byte[] EMPTY_DOCUMENT =
+ ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<parcel xmlns:parcel=\"scripting.dtd\" language=\"Java\">\n" +
+ "</parcel>").getBytes();
+
+ private Document document = null;
+ private String language = null;
+ private final Map<String, String> languagedepprops = new HashMap<String, String>(3);
+
+ public ParcelDescriptor() throws IOException {
+ ByteArrayInputStream bis = null;
+
+ try {
+ bis = new ByteArrayInputStream(EMPTY_DOCUMENT);
+ this.document = XMLParserFactory.getParser().parse(bis);
+ } finally {
+ if (bis != null)
+ bis.close();
+ }
+ }
+
+ private ParcelDescriptor(Document document) {
+ this.document = document;
+ initLanguageProperties();
+ }
+
+ public ParcelDescriptor(InputStream is) throws IOException {
+ this(XMLParserFactory.getParser().parse(is));
+ }
+
+ public ParcelDescriptor(File file) throws IOException {
+ this(file, "Java");
+ }
+
+ private ParcelDescriptor(File file, String language) throws IOException {
+ if (file.exists()) {
+ FileInputStream fis = null;
+
+ try {
+ fis = new FileInputStream(file);
+ this.document = XMLParserFactory.getParser().parse(fis);
+ } finally {
+ if (fis != null)
+ fis.close();
+ }
+ } else {
+ ByteArrayInputStream bis = null;
+
+ try {
+ bis = new ByteArrayInputStream(EMPTY_DOCUMENT);
+ this.document = XMLParserFactory.getParser().parse(bis);
+ } finally {
+ if (bis != null)
+ bis.close();
+ }
+
+ setLanguage(language);
+ }
+
+ initLanguageProperties();
+ }
+
+ public void write(OutputStream out) throws IOException {
+ XMLParserFactory.getParser().write(document, out);
+ }
+
+ public Document getDocument() {
+ return document;
+ }
+
+ public String getLanguage() {
+ if (language == null && document != null) {
+ Element e = document.getDocumentElement();
+ language = e.getAttribute("language");
+ }
+
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+
+ if (document != null) {
+ try {
+ Element e = document.getDocumentElement();
+ e.setAttribute("language", language);
+ } catch (DOMException de) {
+ }
+ }
+ }
+
+ public ScriptEntry[] getScriptEntries() {
+
+ ArrayList<ScriptEntry> scripts = new ArrayList<ScriptEntry>();
+ NodeList scriptNodes;
+ int len;
+
+ if (document == null ||
+ (scriptNodes = document.getElementsByTagName("script")) == null ||
+ (len = scriptNodes.getLength()) == 0)
+ return new ScriptEntry[0];
+
+ for (int i = 0; i < len; i++) {
+ String language, languagename, description = "";
+ Map<String, String> langProps = new HashMap<String, String>();
+ NodeList nl;
+
+ Element scriptElement = (Element)scriptNodes.item(i);
+ language = scriptElement.getAttribute("language");
+
+ // get the text of the description element
+ nl = scriptElement.getElementsByTagName("locale");
+
+ if (nl != null) {
+ nl = nl.item(0).getChildNodes();
+
+ if (nl != null) {
+ for (int j = 0 ; j < nl.getLength(); j++) {
+ if (nl.item(j).getNodeName().equals("description")) {
+ CharacterData cd =
+ (CharacterData)nl.item(j).getFirstChild();
+ description = cd.getData().trim();
+ }
+ }
+ }
+ }
+
+ nl = scriptElement.getElementsByTagName("functionname");
+
+ if (nl == null) {
+ languagename = "";
+ } else {
+ Element tmp = (Element)nl.item(0);
+ languagename = tmp.getAttribute("value");
+ }
+
+ nl = scriptElement.getElementsByTagName("languagedepprops");
+
+ if (nl != null && nl.getLength() > 0) {
+
+ NodeList props = ((Element)nl.item(0)).getElementsByTagName("prop");
+
+ if (props != null) {
+ for (int j = 0; j < props.getLength(); j++) {
+ Element tmp = (Element)props.item(j);
+ String key = tmp.getAttribute("name");
+ String val = tmp.getAttribute("value");
+ langProps.put(key, val);
+ }
+ }
+ }
+
+ ScriptEntry entry =
+ new ScriptEntry(language, languagename, langProps, description);
+ scripts.add(entry);
+ }
+
+ return scripts.toArray(new ScriptEntry[scripts.size()]);
+ }
+
+ public void setScriptEntries(ScriptEntry[] scripts) {
+ clearEntries();
+
+ for (ScriptEntry script : scripts) {
+ addScriptEntry(script);
+ }
+ }
+
+ public void setScriptEntries(Iterator<ScriptEntry> scripts) {
+ clearEntries();
+
+ while (scripts.hasNext()) {
+ addScriptEntry(scripts.next());
+ }
+ }
+
+ private String getLanguageProperty(String name) {
+ return languagedepprops.get(name);
+ }
+
+
+
+ private void initLanguageProperties() {
+ NodeList nl = document.getElementsByTagName("languagedepprops");
+ int len;
+
+ if (nl != null && (len = nl.getLength()) != 0) {
+
+ for (int i = 0; i < len; i++) {
+ Element e = (Element)nl.item(i);
+ NodeList nl2 = e.getElementsByTagName("prop");
+ int len2;
+
+ if (nl2 != null && (len2 = nl2.getLength()) != 0) {
+ for (int j = 0; j < len2; j++) {
+ Element e2 = (Element)nl2.item(j);
+
+ String name = e2.getAttribute("name");
+ String value = e2.getAttribute("value");
+
+ if (getLanguageProperty(name) == null) {
+ languagedepprops.put(name, value);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void clearEntries() {
+ NodeList scriptNodes;
+ Element main = document.getDocumentElement();
+ int len;
+
+ if ((scriptNodes = document.getElementsByTagName("script")) != null &&
+ (len = scriptNodes.getLength()) != 0) {
+ for (int i = len - 1; i >= 0; i--) {
+ try {
+ main.removeChild(scriptNodes.item(i));
+ } catch (DOMException de) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ public void removeScriptEntry(ScriptEntry script) {
+ NodeList scriptNodes;
+ Element main = document.getDocumentElement();
+ int len;
+
+ if ((scriptNodes = document.getElementsByTagName("script")) != null &&
+ (len = scriptNodes.getLength()) != 0) {
+ for (int i = len - 1; i >= 0; i--) {
+ try {
+ Element scriptElement = (Element)scriptNodes.item(i);
+ String languagename = "";
+
+ NodeList nl =
+ scriptElement.getElementsByTagName("functionname");
+
+ if (nl == null) {
+ continue;
+ } else {
+ Element tmp = (Element)nl.item(0);
+ languagename = tmp.getAttribute("value");
+ }
+
+ if (languagename.equals(script.getLanguageName())) {
+ main.removeChild(scriptElement);
+ }
+ } catch (DOMException de) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ public void addScriptEntry(ScriptEntry script) {
+ Element main = document.getDocumentElement();
+ Element root, item, tempitem;
+
+ root = document.createElement("script");
+ root.setAttribute("language", script.getLanguage());
+
+ item = document.createElement("locale");
+ item.setAttribute("lang", "en");
+ tempitem = document.createElement("displayname");
+ tempitem.setAttribute("value", script.getLogicalName());
+ item.appendChild(tempitem);
+
+ tempitem = document.createElement("description");
+ String description = script.getDescription();
+
+ if (description == null || description.length() == 0) {
+ description = script.getLogicalName();
+ }
+
+ tempitem.appendChild(document.createTextNode(description));
+ item.appendChild(tempitem);
+
+ root.appendChild(item);
+
+ item = document.createElement("logicalname");
+ item.setAttribute("value", script.getLogicalName());
+ root.appendChild(item);
+
+ item = document.createElement("functionname");
+ item.setAttribute("value", script.getLanguageName());
+ root.appendChild(item);
+
+ if (languagedepprops != null && !languagedepprops.isEmpty()) {
+ String key;
+ item = document.createElement("languagedepprops");
+
+ for (Map.Entry<String, String> entry : languagedepprops.entrySet()) {
+ tempitem = document.createElement("prop");
+ tempitem.setAttribute("name", entry.getKey());
+ tempitem.setAttribute("value", entry.getValue());
+ item.appendChild(tempitem);
+ }
+
+ root.appendChild(item);
+ }
+
+ //add to the Top Element
+ main.appendChild(root);
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/container/ParsedScriptUri.java b/scripting/java/com/sun/star/script/framework/container/ParsedScriptUri.java
new file mode 100644
index 000000000..796314f00
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/container/ParsedScriptUri.java
@@ -0,0 +1,25 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.container;
+
+public class ParsedScriptUri {
+
+ public String location;
+ public String function;
+ public String parcel;
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/container/ScriptEntry.java b/scripting/java/com/sun/star/script/framework/container/ScriptEntry.java
new file mode 100644
index 000000000..92870c680
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/container/ScriptEntry.java
@@ -0,0 +1,85 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.container;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ScriptEntry {
+
+ private final String language;
+ private final String languagename;
+ private final String logicalname;
+ private final String description;
+
+ private final Map<String, String> languagedepprops;
+
+ protected ScriptEntry(ScriptEntry entry) {
+ this.language = entry.language;
+ this.languagename = entry.languagename;
+ this.logicalname = entry.languagename;
+ this.languagedepprops = entry.languagedepprops;
+ this.description = entry.description;
+ }
+
+ public ScriptEntry(String language, String languagename) {
+ this(language, languagename, new HashMap<String, String>(), "");
+ }
+
+ public ScriptEntry(String language, String languagename,
+ Map<String, String> languagedepprops,
+ String description) {
+ this.language = language;
+ this.languagename = languagename;
+ // logical name/ function name concept
+ // needs to be reworked, in meantime
+ // function name ( from xml ) will be used
+ // as logical name also
+ this.logicalname = languagename;
+ this.languagedepprops = languagedepprops;
+ this.description = description;
+ }
+
+ public Map<String, String> getLanguageProperties() {
+ return languagedepprops;
+ }
+
+ public String getLanguageName() {
+ return languagename;
+ }
+
+ public String getLogicalName() {
+ return logicalname;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public String toString() {
+ return "\nLogicalName = " + logicalname +
+ "\nLanguageName = " + languagename +
+ "\nLanguaguageProperties = " + languagedepprops;
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/container/ScriptMetaData.java b/scripting/java/com/sun/star/script/framework/container/ScriptMetaData.java
new file mode 100644
index 000000000..de51b1247
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/container/ScriptMetaData.java
@@ -0,0 +1,328 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.container;
+
+import com.sun.star.script.framework.io.UCBStreamHandler;
+import com.sun.star.script.framework.io.XInputStreamImpl;
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.PathUtils;
+
+import com.sun.star.ucb.XSimpleFileAccess2;
+
+import com.sun.star.uno.UnoRuntime;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import java.net.URL;
+
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+public class ScriptMetaData extends ScriptEntry {
+
+ private boolean hasSource = false;
+ private static final String locationPlaceHolder = "";
+ private String source;
+ private final Parcel parent;
+
+
+ public ScriptMetaData(Parcel parent, ScriptEntry entry,
+ String source) {
+ super(entry);
+ this.parent = parent;
+
+ if (source != null) {
+ this.hasSource = true;
+ this.source = source;
+ }
+ }
+
+ public boolean hasSource() {
+ return hasSource;
+ }
+
+ public String getSource() {
+ return (source != null && hasSource) ? source : null;
+ }
+
+ public byte[] getSourceBytes() {
+ return (source != null && hasSource) ? source.getBytes() : null;
+ }
+
+ public String getScriptFullURL() {
+ String url = "vnd.sun.star.script:" + parent.getName() + "."
+ + getLanguageName() + "?" + "language=" + getLanguage()
+ + "&location=" + getParcelLocation();
+
+ return url;
+ }
+
+ public String getShortFormScriptURL() {
+ String url = "vnd.sun.star.script:" + parent.getName() + "."
+ + getLanguageName() + "?" + "language=" + getLanguage()
+ + "&location=" + getLocationPlaceHolder();
+
+ return url;
+ }
+
+ // TODO probably should be private should not be necessary
+ // to be exposed at all
+
+ private static final String SHARE =
+ "vnd.sun.star.expand:$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR";
+
+ private static final String USER =
+ "vnd.sun.star.expand:${$BRAND_INI_DIR/" + PathUtils.BOOTSTRAP_NAME
+ + "::UserInstallation}/user";
+
+ private static final String UNO_USER_PACKAGES1 =
+ "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE";
+
+ private static final String UNO_USER_PACKAGES2 = USER + "/uno_packages";
+
+ private static final String UNO_SHARED_PACKAGES1 =
+ "$UNO_SHARED_PACKAGES_CACHE";
+
+ private static final String UNO_SHARED_PACKAGES2 = SHARE + "/uno_packages";
+
+ public static String getFileName(URL url) {
+ String fileName = url.toExternalForm();
+ if (fileName.lastIndexOf(UCBStreamHandler.separator) != -1) {
+ fileName = fileName.substring(0, fileName.lastIndexOf(UCBStreamHandler.separator));
+ fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
+ }
+ return fileName;
+ }
+
+ public static String getLocationPlaceHolder(String url, String pkgname) {
+ String result = "Unknown";
+
+ if (url.contains(UNO_USER_PACKAGES1) ||
+ url.contains(UNO_USER_PACKAGES2)) {
+ result = PathUtils.make_url("user:uno_packages", pkgname);
+ } else if (url.contains(UNO_SHARED_PACKAGES1) ||
+ url.contains(UNO_SHARED_PACKAGES2)) {
+ result = PathUtils.make_url("share:uno_packages", pkgname);
+ } else if (url.indexOf(SHARE) == 0) {
+ result = "share";
+ } else if (url.indexOf(USER) == 0) {
+ result = "user";
+ } else if (url.indexOf("vnd.sun.star.tdoc:") == 0) {
+ result = "document";
+ }
+
+ return result;
+ }
+
+ public String getLocationPlaceHolder() {
+ String placeHolder = "Unknown";
+ String pathToParcel = parent.getPathToParcel();
+
+ if (pathToParcel.contains(UNO_USER_PACKAGES1) ||
+ pathToParcel.contains(UNO_USER_PACKAGES2)) {
+ // it's a package
+ placeHolder = "user:uno_packages";
+ String unoPkg = parent.parent.getName();
+
+ if (unoPkg != null) {
+ placeHolder = PathUtils.make_url(placeHolder, unoPkg);
+ }
+ } else if (pathToParcel.contains(UNO_SHARED_PACKAGES1) ||
+ pathToParcel.contains(UNO_SHARED_PACKAGES2)) {
+ //it's a package
+ placeHolder = "share:uno_packages";
+ String unoPkg = parent.parent.getName();
+
+ if (unoPkg != null) {
+ placeHolder = PathUtils.make_url(placeHolder, unoPkg);
+ }
+ } else if (pathToParcel.indexOf(SHARE) == 0) {
+ placeHolder = "share";
+ } else if (pathToParcel.indexOf(USER) == 0) {
+ placeHolder = "user";
+ } else if (pathToParcel.indexOf("vnd.sun.star.tdoc:") == 0) {
+ placeHolder = "document";
+ }
+
+ // TODO handling document packages ??? not really sure of package url
+ /* else
+ {
+ } */
+ return placeHolder;
+ }
+
+ // TODO probably should be private should not be necessary
+ // to be exposed at all only used in lang providers at the moment
+ // to generate URL for script, editors should use a model of script
+ // source and not interact with the URL
+ // Also if it is to remain needs to be renamed to getParcelLocationURL
+
+ // return URL string to parcel
+ public String getParcelLocation() {
+ return parent.getPathToParcel();
+ }
+
+ @Override
+ public String toString() {
+ return "\nParcelLocation = " + getParcelLocation() + "\nLocationPlaceHolder = "
+ + locationPlaceHolder + super.toString();
+ }
+
+ public URL[] getClassPath() {
+ try {
+ String classpath = getLanguageProperties().get("classpath");
+
+ if (classpath == null) {
+ classpath = "";
+ }
+
+ String parcelPath = getParcelLocation();
+
+ // make sure path ends with /
+ if (!parcelPath.endsWith("/")) {
+ parcelPath += "/";
+ }
+
+ // replace \ with /
+ parcelPath = parcelPath.replace('\\', '/');
+
+ ArrayList<URL> classPathVec = new ArrayList<URL>();
+ StringTokenizer stk = new StringTokenizer(classpath, ":");
+
+ while (stk.hasMoreElements()) {
+ String relativeClasspath = stk.nextToken();
+ String pathToProcess = PathUtils.make_url(parcelPath, relativeClasspath);
+ URL url = createURL(pathToProcess);
+
+ if (url != null) {
+ classPathVec.add(url);
+ }
+
+ }
+
+ if (classPathVec.isEmpty()) {
+ URL url = createURL(parcelPath);
+
+ if (url != null) {
+ classPathVec.add(url);
+ }
+ }
+
+ return classPathVec.toArray(new URL[classPathVec.size()]);
+ } catch (Exception e) {
+ LogUtils.DEBUG("Failed to build class path " + e.toString());
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ return new URL[0];
+ }
+ }
+
+ private URL createURL(String path) throws java.net.MalformedURLException {
+ int indexOfColon = path.indexOf(':');
+ String scheme = path.substring(0, indexOfColon);
+ UCBStreamHandler handler = new UCBStreamHandler(scheme, parent.m_xSFA);
+
+ path += UCBStreamHandler.separator;
+ return new URL(null, path, handler);
+ }
+
+ // TODO should decide whether this should throw or not
+ // decide whether it should be public or protected ( final ? )
+ public void loadSource() {
+ try {
+ URL sourceUrl = getSourceURL();
+
+ LogUtils.DEBUG("** In load source BUT not loading yet for "
+ + sourceUrl);
+
+ if (sourceUrl != null) {
+ StringBuilder buf = new StringBuilder();
+ InputStream in = sourceUrl.openStream();
+
+ byte[] contents = new byte[1024];
+ int len;
+
+ while ((len = in.read(contents, 0, 1024)) != -1) {
+ buf.append(new String(contents, 0, len));
+ }
+
+ try {
+ in.close();
+ } catch (java.io.IOException ignore) {
+ LogUtils.DEBUG("** Failed to read scriot from url "
+ + ignore.toString());
+ }
+
+ source = buf.toString();
+ hasSource = true;
+ }
+ } catch (java.io.IOException e) {
+ LogUtils.DEBUG("** Failed to read scriot from url " + e.toString());
+ }
+
+ }
+
+ protected boolean writeSourceFile() {
+ String sourceFilePath = parent.getPathToParcel() + "/" + getLanguageName();
+ boolean result = false;
+
+ try {
+
+ XSimpleFileAccess2 xSFA2 =
+ UnoRuntime.queryInterface(XSimpleFileAccess2.class, parent.m_xSFA);
+
+ if (xSFA2 != null) {
+ ByteArrayInputStream bis = new ByteArrayInputStream(getSourceBytes());
+ XInputStreamImpl xis = new XInputStreamImpl(bis);
+ xSFA2.writeFile(sourceFilePath, xis);
+ xis.closeInput();
+ result = true;
+ }
+ }
+ // TODO re-examine exception processing should probably throw
+ // exceptions back to caller
+ catch (Exception ignore) {
+ }
+
+ return result;
+ }
+
+ protected boolean removeSourceFile() {
+ String parcelLocation = parent.getPathToParcel();
+ String sourceFilePath = parcelLocation + "/" + getLanguageName();
+ boolean result = false;
+
+ try {
+ parent.m_xSFA.kill(sourceFilePath);
+ result = true;
+ }
+ // TODO reexamine exception handling
+ catch (Exception e) {
+ }
+
+ return result;
+ }
+
+ public URL getSourceURL() throws java.net.MalformedURLException {
+ String sUrl = getParcelLocation();
+ sUrl = PathUtils.make_url(sUrl, getLanguageName());
+ LogUtils.DEBUG("Creating script url for " + sUrl);
+ return createURL(sUrl);
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/container/UnoPkgContainer.java b/scripting/java/com/sun/star/script/framework/container/UnoPkgContainer.java
new file mode 100644
index 000000000..4b6a75520
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/container/UnoPkgContainer.java
@@ -0,0 +1,401 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.container;
+
+import com.sun.star.deployment.XPackage;
+
+import com.sun.star.io.XOutputStream;
+import com.sun.star.io.XTruncate;
+
+import com.sun.star.script.framework.io.XInputStreamWrapper;
+import com.sun.star.script.framework.io.XOutputStreamWrapper;
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.PathUtils;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class UnoPkgContainer extends ParcelContainer {
+
+ private final Map<String, ParcelContainer> registeredPackages = new HashMap<String, ParcelContainer>();
+ private final String extensionDb;
+ private final String extensionRepository;
+
+ public UnoPkgContainer(XComponentContext xCtx, String locationURL,
+ String _extensionDb, String _extensionRepository,
+ String language) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.lang.WrappedTargetException {
+
+ super(xCtx, locationURL, language, false);
+ extensionDb = _extensionDb;
+ extensionRepository = _extensionRepository;
+ init();
+ }
+
+ // gets the ParcelContainer for persisted uno packages
+ public ParcelContainer getRegisteredUnoPkgContainer(String url) {
+
+ if (!url.endsWith("/")) {
+ url += "/";
+ }
+
+ LogUtils.DEBUG("** getRegisterPackage ctx = " + containerUrl);
+ LogUtils.DEBUG("** getRegisterPackage for uri " + url);
+ LogUtils.DEBUG("** getRegisterPackage for language " + language);
+
+ ParcelContainer result = registeredPackages.get(url);
+ LogUtils.DEBUG("getRegisterPackage result is " + result);
+ return result;
+ }
+
+ public boolean hasRegisteredUnoPkgContainer(String url) {
+ return getRegisteredUnoPkgContainer(url) != null;
+ }
+
+ private void registerPackageContainer(String url, ParcelContainer c) {
+
+ if (!url.endsWith("/")) {
+ url += "/";
+ }
+
+ LogUtils.DEBUG("RegisterPackage ctx = " + containerUrl);
+ LogUtils.DEBUG("RegisterPackage language = " + language);
+ LogUtils.DEBUG("RegisterPackage " + c + " for url " + url);
+ registeredPackages.put(url, c);
+ }
+
+ public void deRegisterPackageContainer(String url) {
+
+ if (!url.endsWith("/")) {
+ url += "/";
+ }
+
+ LogUtils.DEBUG("In deRegisterPackageContainer for " + url);
+
+ if (hasRegisteredUnoPkgContainer(url)) {
+ try {
+ DeployedUnoPackagesDB db = getUnoPackagesDB();
+
+ if (db != null && db.removePackage(language, url)) {
+ writeUnoPackageDB(db);
+ ParcelContainer container = registeredPackages.get(url);
+
+ if (!container.hasElements()) {
+ // When all libraries within a package bundle
+ // ( for this language ) are removed also
+ // remove the container from its parent
+ // Otherwise, a container ( with no containers )
+ // representing the uno package bundle will
+ // still exist and so will get displayed
+ if (container.parent() != null) {
+ container.parent().removeChildContainer(container);
+ }
+ }
+
+ registeredPackages.remove(url);
+ }
+ } catch (Exception e) {
+ //TODO revisit exception handling and exception here
+ //means something very wrong
+ LogUtils.DEBUG("***** deRegisterPackageContainer() got exception " + e);
+ }
+ }
+
+ LogUtils.DEBUG("Leaving deRegisterPackageContainer for " + url);
+ }
+
+ private void init() throws com.sun.star.lang.IllegalArgumentException {
+ LogUtils.DEBUG("getting container for " + containerUrl);
+
+ try {
+ DeployedUnoPackagesDB db = getUnoPackagesDB();
+
+ if (db != null) {
+ String[] packages = db.getDeployedPackages(language);
+
+ for (String thepackage : packages) {
+ try {
+ processUnoPackage(thepackage, language);
+ } catch (com.sun.star.lang.IllegalArgumentException ila) {
+ LogUtils.DEBUG("Failed to process " + thepackage
+ + " for " + language);
+ LogUtils.DEBUG(" Reason: " + ila);
+ } catch (Exception e) {
+ // TODO proper exception or do we wish
+ // to ignore errors here
+ LogUtils.DEBUG("Something very wrong!!!!!");
+ LogUtils.DEBUG("Failed to process " + thepackage
+ + " for " + language);
+ LogUtils.DEBUG(" Reason: " + e);
+ }
+ }
+ }
+ } catch (com.sun.star.lang.WrappedTargetException e) {
+ // no deployed packages
+ LogUtils.DEBUG("No deployed uno-packages for " + containerUrl);
+ }
+ }
+
+ @Override
+ public ScriptMetaData findScript(ParsedScriptUri psu) throws
+ com.sun.star.container.NoSuchElementException,
+ com.sun.star.lang.WrappedTargetException {
+
+ String functionName = psu.function;
+ String parcelName = psu.parcel;
+ String location = psu.location;
+
+ LogUtils.DEBUG("*** UnoPkgContainer.findScript() ***" +
+ "\ncontainerUrl = " + containerUrl +
+ "\nfunction = " + functionName +
+ "\nlocation = " + location +
+ "\nparcel = " + parcelName);
+
+ ParcelContainer pc = getChildContainer(location);
+
+ if (pc == null) {
+ throw new com.sun.star.lang.WrappedTargetException(
+ "Failed to resolve script " , null,
+ new com.sun.star.lang.IllegalArgumentException(
+ "Cannot resolve script location for script = " + functionName));
+ }
+
+ return pc.findScript(psu);
+ }
+
+ private DeployedUnoPackagesDB getUnoPackagesDB() throws
+ com.sun.star.lang.WrappedTargetException {
+
+ InputStream is = null;
+ DeployedUnoPackagesDB dp = null;
+
+ try {
+
+ String packagesUrl =
+ PathUtils.make_url(extensionDb,
+ "/Scripts/" + extensionRepository + "-extension-desc.xml");
+
+ LogUtils.DEBUG("getUnoPackagesDB() looking for existing db in "
+ + packagesUrl);
+
+ if (m_xSFA.exists(packagesUrl)) {
+ if (packagesUrl.startsWith("vnd.sun.star.tdoc")) {
+ // handles using XStorage directly
+ throw new com.sun.star.lang.WrappedTargetException(
+ "Can't handle documents yet");
+ }
+
+ is = new XInputStreamWrapper(m_xSFA.openFileRead(packagesUrl));
+ dp = new DeployedUnoPackagesDB(is);
+
+ try {
+ is.close();
+ is = null;
+ } catch (Exception ignore) {
+ }
+ } else {
+ LogUtils.DEBUG("getUnoPackagesDB() " + packagesUrl
+ + " does not exist");
+ }
+ } catch (Exception e) {
+ LogUtils.DEBUG("getUnoPackagesDB() caught Exception: " + e);
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ is = null;
+ } catch (Exception ignore) {
+ }
+ }
+ }
+
+ return dp;
+ }
+
+ private void writeUnoPackageDB(DeployedUnoPackagesDB dp) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.lang.WrappedTargetException {
+
+ LogUtils.DEBUG("In writeUnoPackageDB() ");
+
+ XOutputStream xos = null;
+ OutputStream os = null;
+
+ try {
+
+ String packagesUrl =
+ PathUtils.make_url(extensionDb, "/Scripts/" + extensionRepository
+ + "-extension-desc.xml");
+
+ xos = m_xSFA.openFileWrite(packagesUrl);
+ XTruncate xTrc = UnoRuntime.queryInterface(XTruncate.class, xos);
+
+ if (xTrc != null) {
+ LogUtils.DEBUG("In writeUnoPackageDB() Truncating...");
+ xTrc.truncate();
+ } else {
+ LogUtils.DEBUG("In writeUnoPackageDB() CAN'T Truncate...");
+ }
+
+ os = new XOutputStreamWrapper(xos);
+ dp.write(os);
+
+ try {
+ os.close(); // will close xos
+ os = null;
+ } catch (Exception ignore) {
+ }
+ } catch (Exception e) {
+ LogUtils.DEBUG("In writeUnoPackageDB() Exception: " + e);
+ throw new com.sun.star.lang.WrappedTargetException(e);
+ } finally {
+ if (os != null) {
+ try {
+ os.close(); // will close xos
+ os = null;
+ } catch (Exception ignore) {
+ }
+ }
+ }
+ }
+
+ public void processUnoPackage(XPackage dPackage,
+ String language) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.lang.WrappedTargetException,
+ com.sun.star.container.ElementExistException {
+
+ LogUtils.DEBUG("** in processUnoPackage ");
+
+ String uri = dPackage.getURL();
+
+ if (!uri.endsWith("/")) {
+ uri += "/";
+ }
+
+ LogUtils.DEBUG("** processUnoPackage getURL() -> " + uri);
+ LogUtils.DEBUG("** processUnoPackage getName() -> " + dPackage.getName());
+ LogUtils.DEBUG("** processUnoPackage getMediaType() -> "
+ + dPackage.getPackageType().getMediaType());
+
+ try {
+ LogUtils.DEBUG("** processUnoPackage getDisplayName() -> "
+ + dPackage.getDisplayName());
+ } catch (com.sun.star.deployment.ExtensionRemovedException e) {
+ throw new com.sun.star.lang.WrappedTargetException(e.getMessage(), this, e);
+ }
+
+ processUnoPackage(uri, language);
+
+ DeployedUnoPackagesDB db = getUnoPackagesDB();
+
+ if (db == null) {
+ try {
+ db = new DeployedUnoPackagesDB();
+ } catch (java.io.IOException ioe) {
+ throw new com.sun.star.lang.WrappedTargetException(ioe);
+ }
+ }
+
+ db.addPackage(language, uri);
+ writeUnoPackageDB(db);
+ }
+
+ private void processUnoPackage(String uri,
+ String language) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.lang.WrappedTargetException,
+ com.sun.star.container.ElementExistException {
+
+ if (hasRegisteredUnoPkgContainer(uri)) {
+ throw new com.sun.star.container.ElementExistException(
+ "Already a registered uno package " + uri + " for language "
+ + language);
+ }
+
+ LogUtils.DEBUG("processUnoPackage - URL = " + uri);
+ LogUtils.DEBUG("processUnoPackage - script library package");
+ String parentUrl = uri;
+
+ if (uri.contains("%2Funo_packages%2F") ||
+ uri.contains("/uno_packages/") ||
+ uri.contains("$UNO_USER_PACKAGES_CACHE/") ||
+ uri.contains("$UNO_SHARED_PACKAGES_CACHE/") ||
+ uri.contains("$BUNDLED_EXTENSIONS/")) {
+
+ //its in a bundle need to determine the uno-package file its in
+ LogUtils.DEBUG("processUnoPackage - is part of a UNO bundle");
+
+ int index = uri.lastIndexOf('/');
+
+ if (uri.endsWith("/")) {
+ uri = uri.substring(0, index);
+ index = uri.lastIndexOf('/');
+ }
+
+ if (index > -1) {
+ parentUrl = uri.substring(0, index);
+ LogUtils.DEBUG("processUnoPackage - composition is contained in "
+ + parentUrl);
+ }
+
+ ParcelContainer pkgContainer = getChildContainerForURL(parentUrl);
+
+ if (pkgContainer == null) {
+ pkgContainer =
+ new ParcelContainer(this, m_xCtx, parentUrl, language, false);
+
+ if (pkgContainer.loadParcel(uri) == null) {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "Couldn't load script library from composition package "
+ + uri + " for language " + language);
+ }
+
+ addChildContainer(pkgContainer);
+ } else {
+ if (pkgContainer.loadParcel(uri) == null) {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "Couldn't load script library from composition package "
+ + uri + " for language " + language);
+ }
+
+ }
+
+ registerPackageContainer(uri, pkgContainer);
+ } else {
+ // stand-alone library package, e.g. not contained in
+ // a uno package
+ if (loadParcel(uri) == null) {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "Couldn't load script library package " + uri
+ + " for language " + language);
+ }
+
+ registerPackageContainer(uri, this);
+ }
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/container/XMLParser.java b/scripting/java/com/sun/star/script/framework/container/XMLParser.java
new file mode 100644
index 000000000..38e504ff4
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/container/XMLParser.java
@@ -0,0 +1,30 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.container;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.w3c.dom.Document;
+
+public interface XMLParser {
+ Document parse(InputStream inputStream) throws IOException;
+ void write(Document doc, OutputStream out) throws IOException;
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/container/XMLParserFactory.java b/scripting/java/com/sun/star/script/framework/container/XMLParserFactory.java
new file mode 100644
index 000000000..02c9e6c34
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/container/XMLParserFactory.java
@@ -0,0 +1,106 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.container;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+public class XMLParserFactory {
+
+ private static XMLParser parser = null;
+ private static String officedtdurl = null;
+
+ private XMLParserFactory() {}
+
+ public static synchronized XMLParser getParser() {
+ if (parser == null)
+ parser = new DefaultParser();
+
+ return parser;
+ }
+
+ public static void setOfficeDTDURL(String url) {
+ officedtdurl = url;
+ }
+
+ private static class DefaultParser implements XMLParser {
+
+ private final DocumentBuilderFactory factory;
+
+ public DefaultParser() {
+ factory = DocumentBuilderFactory.newInstance();
+ }
+
+ public Document parse(InputStream inputStream) throws IOException {
+
+ Document result = null;
+
+ try {
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ InputSource is = new InputSource(inputStream);
+
+ if (officedtdurl != null) {
+ is.setSystemId(officedtdurl);
+ }
+
+ result = builder.parse(is);
+ } catch (SAXParseException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ } catch (SAXException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ } catch (ParserConfigurationException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+
+ return result;
+ }
+
+ public void write(Document doc, OutputStream out) throws IOException {
+ try {
+ TransformerFactory.newInstance().newTransformer().transform(
+ new DOMSource(doc), new StreamResult(out));
+ } catch (TransformerException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/io/UCBStreamHandler.java b/scripting/java/com/sun/star/script/framework/io/UCBStreamHandler.java
new file mode 100644
index 000000000..6413745d3
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/io/UCBStreamHandler.java
@@ -0,0 +1,275 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.io;
+
+import com.sun.star.io.XInputStream;
+import com.sun.star.io.XOutputStream;
+import com.sun.star.io.XTruncate;
+
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.PathUtils;
+
+import com.sun.star.ucb.XSimpleFileAccess;
+
+import com.sun.star.uno.UnoRuntime;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+import java.util.HashMap;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+public class UCBStreamHandler extends URLStreamHandler {
+
+ public static final String separator = "/ucb/";
+
+ private final XSimpleFileAccess m_xSimpleFileAccess;
+ private final HashMap<String, InputStream> m_jarStreamMap = new HashMap<String, InputStream>(12);
+ private static String m_ucbscheme;
+
+ public UCBStreamHandler(String scheme, XSimpleFileAccess xSFA) {
+ LogUtils.DEBUG("UCBStreamHandler ctor, scheme = " + scheme);
+ UCBStreamHandler.m_ucbscheme = scheme;
+ this.m_xSimpleFileAccess = xSFA;
+ }
+
+ @Override
+ public void parseURL(URL url, String spec, int start, int limit) {
+
+ LogUtils.DEBUG("**XUCBStreamHandler, parseURL: " + url + " spec: "
+ + spec + " start: " + start + " limit: " + limit);
+
+ String file = url.getFile();
+
+ if (file == null)
+ file = spec.substring(start, limit);
+ else
+ file += spec.substring(start, limit);
+
+ LogUtils.DEBUG("**For scheme = " + m_ucbscheme);
+ LogUtils.DEBUG("**Setting path = " + file);
+ setURL(url, m_ucbscheme, null, -1, null, null, file, null, null);
+ }
+
+ @Override
+ public URLConnection openConnection(URL u) throws IOException {
+ return new UCBConnection(u);
+ }
+
+ private class UCBConnection extends URLConnection {
+
+ public UCBConnection(URL url) {
+ super(url);
+ }
+
+ @Override
+ public void connect() {
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ LogUtils.DEBUG("UCBConnectionHandler GetInputStream on " + url);
+ String sUrl = url.toString();
+
+ if (sUrl.lastIndexOf(separator) == -1) {
+ LogUtils.DEBUG("getInputStream straight file load");
+ return getFileStreamFromUCB(sUrl);
+ } else {
+ String path = sUrl.substring(0, sUrl.lastIndexOf(separator));
+
+ String file =
+ sUrl.substring(sUrl.lastIndexOf(separator) + separator.length());
+
+ LogUtils.DEBUG("getInputStream, load of file from another file eg. "
+ + file + " from " + path);
+
+ return getUCBStream(file, path);
+ }
+ }
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ LogUtils.DEBUG("UCBConnectionHandler getOutputStream on " + url);
+ OutputStream os = null;
+
+ try {
+ String sUrl = url.toString();
+
+ if (sUrl.lastIndexOf(separator) != -1) {
+ String path = sUrl.substring(0, sUrl.lastIndexOf(separator));
+
+ if (m_xSimpleFileAccess.isReadOnly(path)) {
+ throw new java.io.IOException("File is read only");
+ }
+
+ LogUtils.DEBUG("getOutputStream, create o/p stream for file eg. "
+ + path);
+
+ // we will only deal with simple file write
+ XOutputStream xos = m_xSimpleFileAccess.openFileWrite(path);
+
+ XTruncate xtrunc =
+ UnoRuntime.queryInterface(XTruncate.class, xos);
+
+ if (xtrunc != null) {
+ xtrunc.truncate();
+ }
+
+ os = new XOutputStreamWrapper(xos);
+ }
+
+ if (os == null) {
+ throw new IOException("Failed to get OutputStream for "
+ + sUrl);
+ }
+ } catch (com.sun.star.ucb.CommandAbortedException cae) {
+ LogUtils.DEBUG("caught exception: " + cae.toString() +
+ " getting writable stream from " + url);
+ IOException newEx = new IOException(cae.getMessage());
+ newEx.initCause(cae);
+ throw newEx;
+ } catch (com.sun.star.uno.Exception e) {
+ LogUtils.DEBUG("caught unknown exception: " + e.toString() +
+ " getting writable stream from " + url);
+ IOException newEx = new IOException(e.getMessage());
+ newEx.initCause(e);
+ throw newEx;
+ }
+
+ return os;
+ }
+ }
+
+ private InputStream getUCBStream(String file, String path) throws IOException {
+
+ InputStream is = null;
+ InputStream result = null;
+
+ try {
+ if (path.endsWith(".jar")) {
+ is = m_jarStreamMap.get(path);
+
+ if (is == null) {
+ is = getFileStreamFromUCB(path);
+ m_jarStreamMap.put(path, is);
+ } else {
+ try {
+ is.reset();
+ } catch (IOException e) {
+ is.close();
+ is = getFileStreamFromUCB(path);
+ m_jarStreamMap.put(path, is);
+ }
+ }
+
+ result = getFileStreamFromJarStream(file, is);
+ } else {
+ String fileUrl = PathUtils.make_url(path, file);
+ result = getFileStreamFromUCB(fileUrl);
+ }
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException ioe) {
+ LogUtils.DEBUG("Caught exception closing stream: " +
+ ioe.getMessage());
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private InputStream getFileStreamFromJarStream(String file,
+ InputStream is) throws
+ IOException {
+
+ ZipInputStream zis = new ZipInputStream(is);
+
+ while (zis.available() != 0) {
+ ZipEntry entry = zis.getNextEntry();
+
+ if (entry != null && entry.getName().equals(file)) {
+ return zis;
+ }
+ }
+
+ return null;
+ }
+
+ private InputStream getFileStreamFromUCB(String path) throws IOException {
+
+ InputStream result = null;
+ XInputStream xInputStream = null;
+
+ try {
+ LogUtils.DEBUG("Trying to read from " + path);
+ xInputStream = m_xSimpleFileAccess.openFileRead(path);
+ LogUtils.DEBUG("sfa appeared to read file ");
+ byte[][] inputBytes = new byte[1][];
+
+ int sz = m_xSimpleFileAccess.getSize(path);
+
+ // TODO don't depend on result of available() or size()
+ // just read stream 'till complete
+ if (sz == 0 && xInputStream.available() > 0) {
+ sz = xInputStream.available();
+ }
+
+ LogUtils.DEBUG("size of file " + path + " is " + sz);
+ LogUtils.DEBUG("available = " + xInputStream.available());
+ inputBytes[0] = new byte[sz];
+
+ int ln = xInputStream.readBytes(inputBytes, sz);
+
+ if (ln != sz) {
+ throw new IOException(
+ "Failed to read " + sz + " bytes from XInputStream");
+ }
+
+ result = new ByteArrayInputStream(inputBytes[0]);
+ } catch (com.sun.star.io.IOException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ } catch (com.sun.star.uno.Exception ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ } finally {
+ if (xInputStream != null) {
+ try {
+ xInputStream.closeInput();
+ } catch (Exception e2) {
+ LogUtils.DEBUG("Error closing XInputStream: "
+ + e2.getMessage());
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/io/XInputStreamImpl.java b/scripting/java/com/sun/star/script/framework/io/XInputStreamImpl.java
new file mode 100644
index 000000000..8320b6227
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/io/XInputStreamImpl.java
@@ -0,0 +1,109 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.io;
+
+import com.sun.star.io.XInputStream;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class XInputStreamImpl implements XInputStream {
+
+ private final InputStream is;
+
+ public XInputStreamImpl(InputStream is) {
+ this.is = is;
+ }
+
+ public int readBytes(/*OUT*/byte[][] aData, /*IN*/int nBytesToRead) throws
+ com.sun.star.io.NotConnectedException,
+ com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException {
+
+ aData[ 0 ] = new byte[ nBytesToRead ];
+ int totalBytesRead = 0;
+
+ try {
+ int bytesRead;
+
+ while ((bytesRead = is.read(aData[ 0 ], totalBytesRead, nBytesToRead)) > 0
+ && (totalBytesRead < nBytesToRead)) {
+ totalBytesRead += bytesRead;
+ nBytesToRead -= bytesRead;
+ }
+ } catch (IOException e) {
+ throw new com.sun.star.io.IOException(e);
+ } catch (IndexOutOfBoundsException aie) {
+ throw new com.sun.star.io.BufferSizeExceededException(aie);
+ }
+
+ return totalBytesRead;
+ }
+
+ public int readSomeBytes(/*OUT*/byte[][] aData, /*IN*/int nMaxBytesToRead)
+ throws com.sun.star.io.NotConnectedException,
+ com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException {
+
+ int bytesToRead = nMaxBytesToRead;
+ int availableBytes = available();
+
+ if (availableBytes < nMaxBytesToRead) {
+ bytesToRead = availableBytes;
+ }
+
+ int read = readBytes(aData, bytesToRead);
+ return read;
+ }
+
+ public void skipBytes(/*IN*/int nBytesToSkip) throws
+ com.sun.star.io.NotConnectedException,
+ com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException {
+
+ try {
+ do {
+ nBytesToSkip -= is.skip(nBytesToSkip);
+ } while (nBytesToSkip > 0);
+ } catch (IOException e) {
+ throw new com.sun.star.io.IOException(e);
+ }
+ }
+
+ public int available() throws
+ com.sun.star.io.NotConnectedException, com.sun.star.io.IOException {
+
+ int bytesAvail = 0;
+
+ try {
+ bytesAvail = is.available();
+ } catch (IOException e) {
+ throw new com.sun.star.io.IOException(e);
+ }
+
+ return bytesAvail;
+ }
+
+ public void closeInput() throws
+ com.sun.star.io.NotConnectedException, com.sun.star.io.IOException {
+
+ try {
+ is.close();
+ } catch (IOException e) {
+ throw new com.sun.star.io.IOException(e);
+ }
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/io/XInputStreamWrapper.java b/scripting/java/com/sun/star/script/framework/io/XInputStreamWrapper.java
new file mode 100644
index 000000000..654f0e24c
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/io/XInputStreamWrapper.java
@@ -0,0 +1,100 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * 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 .
+ */
+package com.sun.star.script.framework.io;
+
+import com.sun.star.io.XInputStream;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class XInputStreamWrapper extends InputStream {
+
+ private final XInputStream m_xInputStream;
+
+ public XInputStreamWrapper(XInputStream xInputStream) {
+ m_xInputStream = xInputStream;
+ }
+
+ @Override
+ public int read() throws java.io.IOException {
+ byte[][] byteRet = new byte[1][0];
+ long numRead;
+
+ try {
+ numRead = m_xInputStream.readBytes(byteRet, 1);
+ } catch (com.sun.star.io.IOException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+
+ if (numRead != 1) {
+ return -1;
+ }
+
+ return byteRet[0][0];
+ }
+
+ @Override
+ public int read(byte[] b) throws java.io.IOException {
+ byte[][] byteRet = new byte[1][];
+ byteRet[0] = b;
+
+ try {
+ return m_xInputStream.readBytes(byteRet, b.length);
+ } catch (com.sun.star.io.IOException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+
+ @Override
+ public long skip(long n) throws java.io.IOException {
+ try {
+ m_xInputStream.skipBytes((int)n);
+ return n;
+ } catch (com.sun.star.io.IOException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+
+ @Override
+ public int available() throws java.io.IOException {
+ try {
+ return m_xInputStream.available();
+ } catch (com.sun.star.io.IOException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+
+ @Override
+ public void close() throws java.io.IOException {
+ try {
+ m_xInputStream.closeInput();
+ } catch (com.sun.star.io.IOException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/io/XOutputStreamWrapper.java b/scripting/java/com/sun/star/script/framework/io/XOutputStreamWrapper.java
new file mode 100644
index 000000000..16357fd17
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/io/XOutputStreamWrapper.java
@@ -0,0 +1,113 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.io;
+
+import com.sun.star.io.XOutputStream;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class XOutputStreamWrapper extends OutputStream {
+
+ private final XOutputStream m_xOutputStream;
+
+ public XOutputStreamWrapper(XOutputStream xOs) {
+ this.m_xOutputStream = xOs;
+ }
+
+ @Override
+ public void write(int b) throws java.io.IOException {
+ if (m_xOutputStream == null) {
+ throw new java.io.IOException("Stream is null");
+ }
+
+ byte[] bytes = new byte[1];
+ bytes[0] = (byte) b;
+
+ try {
+ m_xOutputStream.writeBytes(bytes);
+ } catch (com.sun.star.io.IOException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+
+ @Override
+ public void write(byte[] b) throws java.io.IOException {
+
+ if (m_xOutputStream == null) {
+ throw new java.io.IOException("Stream is null");
+ }
+
+ try {
+ m_xOutputStream.writeBytes(b);
+ } catch (com.sun.star.io.IOException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+ @Override
+ public void write(byte[] b, int off, int len) throws java.io.IOException {
+ if (m_xOutputStream == null) {
+ throw new java.io.IOException("Stream is null");
+ }
+
+ byte[] bytes = new byte[len];
+ System.arraycopy(b, off, bytes, 0, len);
+
+ try {
+ m_xOutputStream.writeBytes(bytes);
+ } catch (com.sun.star.io.IOException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+
+ @Override
+ public void flush() throws java.io.IOException {
+ if (m_xOutputStream == null) {
+ throw new java.io.IOException("Stream is null");
+ }
+
+ try {
+ m_xOutputStream.flush();
+ } catch (com.sun.star.io.IOException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+
+ @Override
+ public void close() throws java.io.IOException {
+ if (m_xOutputStream == null) {
+ throw new java.io.IOException("Stream is null");
+ }
+
+ try {
+ m_xOutputStream.closeOutput();
+ } catch (com.sun.star.io.IOException ex1) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/io/XStorageHelper.java b/scripting/java/com/sun/star/script/framework/io/XStorageHelper.java
new file mode 100644
index 000000000..79c5f10bc
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/io/XStorageHelper.java
@@ -0,0 +1,249 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.io;
+
+import com.sun.star.beans.XPropertySet;
+
+import com.sun.star.container.XNameAccess;
+
+import com.sun.star.document.XDocumentSubStorageSupplier;
+
+import com.sun.star.embed.XStorage;
+import com.sun.star.embed.XTransactedObject;
+
+import com.sun.star.frame.XModel;
+
+import com.sun.star.lang.EventObject;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XEventListener;
+
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.PathUtils;
+
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XInterface;
+
+import java.io.IOException;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+public class XStorageHelper implements XEventListener {
+
+ XStorage[] xStorages;
+ static Map<String, XModel> modelMap = new HashMap<String, XModel>();
+ XModel xModel = null;
+ private static XStorageHelper listener = new XStorageHelper();
+
+ private XStorageHelper() {}
+
+ public XStorageHelper(String path, int mode,
+ boolean create) throws IOException {
+
+ String modelUrl = null;
+ int indexOfScriptsDir = path.lastIndexOf("Scripts");
+
+ if (indexOfScriptsDir > -1) {
+ modelUrl = path.substring(0, indexOfScriptsDir - 1);
+ path = path.substring(indexOfScriptsDir, path.length());
+ }
+
+ LogUtils.DEBUG("XStorageHelper ctor, path: " + path);
+ this.xModel = getModelForURL(modelUrl);
+
+ try {
+ StringTokenizer tokens = new StringTokenizer(path, "/");
+
+ if (tokens.countTokens() == 0) {
+ throw new IOException("Invalid path");
+ }
+
+ XDocumentSubStorageSupplier xDocumentSubStorageSupplier =
+ UnoRuntime.queryInterface(XDocumentSubStorageSupplier.class,
+ xModel);
+
+ xStorages = new XStorage[tokens.countTokens()];
+
+ LogUtils.DEBUG("XStorageHelper ctor, path chunks length: "
+ + xStorages.length);
+
+ for (int i = 0; i < xStorages.length; i++) {
+ LogUtils.DEBUG("XStorageHelper, processing index " + i);
+ String name = tokens.nextToken();
+ LogUtils.DEBUG("XStorageHelper, getting: " + name);
+ XStorage storage = null;
+
+ if (i == 0) {
+ storage = xDocumentSubStorageSupplier.getDocumentSubStorage(name, mode);
+
+ if (storage == null) {
+ LogUtils.DEBUG("** boo hoo Storage is null ");
+ }
+
+ XPropertySet xProps =
+ UnoRuntime.queryInterface(XPropertySet.class, storage);
+
+ if (xProps != null) {
+
+ String mediaType =
+ AnyConverter.toString(xProps.getPropertyValue("MediaType"));
+
+ LogUtils.DEBUG("***** media type is " + mediaType);
+
+ if (!mediaType.equals("scripts")) {
+ xProps.setPropertyValue("MediaType", "scripts");
+ }
+ }
+ } else {
+
+ XNameAccess xNameAccess =
+ UnoRuntime.queryInterface(XNameAccess.class, xStorages[i - 1]);
+
+ if (xNameAccess == null) {
+ disposeObject();
+ throw new IOException("No name access " + name);
+ } else if (!xNameAccess.hasByName(name)
+ || !xStorages[i - 1].isStorageElement(name)) {
+ if (!create) {
+ disposeObject();
+ throw new IOException("No subdir: " + name);
+ } else {
+ // attempt to create new storage
+ LogUtils.DEBUG("Attempt to create new storage for "
+ + name);
+ }
+ }
+
+ storage = xStorages[i - 1].openStorageElement(
+ name, mode);
+ }
+
+ if (storage == null) {
+ disposeObject();
+ throw new IOException("storage not found: " + name);
+ }
+
+ xStorages[i] = storage;
+
+ }
+ } catch (com.sun.star.io.IOException ioe) {
+ disposeObject();
+ } catch (com.sun.star.uno.Exception ex1) {
+ disposeObject();
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+
+ public synchronized static void addNewModel(XModel model) {
+ // TODO needs to cater for model for untitled document
+ modelMap.put(PathUtils.getOidForModel(model), model);
+ XComponent xComp = UnoRuntime.queryInterface(XComponent.class, model);
+
+ if (xComp != null) {
+ try {
+ xComp.addEventListener(listener);
+ } catch (Exception e) {
+ // What TODO here ?
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ }
+ }
+ }
+
+ public void disposing(EventObject Source) {
+ XModel model = UnoRuntime.queryInterface(XModel.class, Source.Source);
+
+ if (model != null) {
+ LogUtils.DEBUG(" Disposing doc " + model.getURL());
+ modelMap.remove(PathUtils.getOidForModel(model));
+ }
+ }
+
+ public XStorage getStorage() {
+ return xStorages[ xStorages.length - 1 ];
+ }
+
+ public XModel getModel() {
+ return xModel;
+ }
+
+ public void disposeObject() {
+ disposeObject(false);
+ }
+
+ public void disposeObject(boolean shouldCommit) {
+ LogUtils.DEBUG("In disposeObject");
+
+ for (int i = xStorages.length - 1 ; i > -1; i--) {
+ LogUtils.DEBUG("In disposeObject disposing storage " + i);
+
+ try {
+ XStorage xStorage = xStorages[i];
+
+ if (shouldCommit) {
+ commit(xStorage);
+ }
+
+ disposeObject(xStorage);
+ LogUtils.DEBUG("In disposeObject disposed storage " + i);
+ } catch (Exception ignore) {
+ LogUtils.DEBUG("Exception disposing storage " + i);
+ }
+
+ }
+
+ }
+
+ public static void disposeObject(XInterface xInterface) {
+ if (xInterface == null) {
+ return;
+ }
+
+ XComponent xComponent =
+ UnoRuntime.queryInterface(XComponent.class, xInterface);
+
+ if (xComponent == null) {
+ return;
+ }
+
+ xComponent.dispose();
+ }
+
+ public static void commit(XInterface xInterface) {
+
+ XTransactedObject xTrans =
+ UnoRuntime.queryInterface(XTransactedObject.class, xInterface);
+
+ if (xTrans != null) {
+ try {
+ xTrans.commit();
+ } catch (Exception e) {
+ LogUtils.DEBUG("Something went belly up exception: " + e);
+ }
+ }
+ }
+
+ public XModel getModelForURL(String url) {
+ //TODO does not cater for untitled documents
+ return modelMap.get(url);
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/log/LogUtils.java b/scripting/java/com/sun/star/script/framework/log/LogUtils.java
new file mode 100644
index 000000000..cd42b9d1e
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/log/LogUtils.java
@@ -0,0 +1,57 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.log;
+
+import java.io.StringWriter;
+import java.io.PrintWriter;
+
+public class LogUtils {
+
+ private static boolean m_bDebugEnabled = false;
+
+ static {
+ String debugFlag =
+ System.getProperties().getProperty("ScriptJavaRuntimeDebug");
+
+ if (debugFlag != null && debugFlag.length() > 0) {
+ m_bDebugEnabled = debugFlag.equalsIgnoreCase("true");
+ }
+ }
+
+ // Ensure that instances of this class cannot be created
+ private LogUtils() {
+ }
+
+ /**
+ * Print Debug Output
+ *
+ * @param msg message to be displayed
+ */
+ public static void DEBUG(String msg) {
+ if (m_bDebugEnabled) {
+ System.out.println(msg);
+ }
+ }
+
+ public static String getTrace(Exception e) {
+ StringWriter w = new StringWriter();
+ e.printStackTrace(new PrintWriter(w));
+ return w.toString();
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/provider/ClassLoaderFactory.java b/scripting/java/com/sun/star/script/framework/provider/ClassLoaderFactory.java
new file mode 100644
index 000000000..b5e6e3085
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/ClassLoaderFactory.java
@@ -0,0 +1,55 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.provider;
+
+import com.sun.star.script.framework.container.ScriptMetaData;
+import com.sun.star.script.framework.log.LogUtils;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Class Loader Factory
+ */
+public class ClassLoaderFactory {
+
+ private ClassLoaderFactory() {}
+
+ public static ClassLoader getURLClassLoader(ScriptMetaData scriptData) {
+ ClassLoader parent = scriptData.getClass().getClassLoader();
+ URL[] classPath = scriptData.getClassPath();
+ LogUtils.DEBUG("Classpath has length " + classPath.length);
+
+ for (int i = 0; i < classPath.length; i++) {
+ LogUtils.DEBUG("ClassPath " + i + "} is " + classPath[ i ].toString());
+ }
+
+ return getURLClassLoader(parent, classPath);
+ }
+
+ public static ClassLoader getURLClassLoader(final ClassLoader parent,
+ final URL[] classpath) {
+ return AccessController.doPrivileged(
+ new PrivilegedAction<URLClassLoader>() {
+ public URLClassLoader run() { return new URLClassLoader(classpath, parent); }
+ });
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/provider/EditorScriptContext.java b/scripting/java/com/sun/star/script/framework/provider/EditorScriptContext.java
new file mode 100644
index 000000000..d107edcc7
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/EditorScriptContext.java
@@ -0,0 +1,79 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.provider;
+
+import com.sun.star.document.XScriptInvocationContext;
+
+import com.sun.star.frame.XDesktop;
+import com.sun.star.frame.XModel;
+
+import com.sun.star.script.provider.XScriptContext;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+public class EditorScriptContext implements XScriptContext {
+
+ private final XDesktop m_xDeskTop;
+ private final XComponentContext m_xComponentContext;
+
+ public EditorScriptContext(XComponentContext xmComponentContext,
+ XDesktop xDesktop) {
+ this.m_xComponentContext = xmComponentContext;
+ this.m_xDeskTop = xDesktop;
+ }
+
+ /**
+ Obtain the document reference on which the script can operate
+
+ @return XModel interface
+ */
+ public XModel getDocument() {
+
+ XModel xModel =
+ UnoRuntime.queryInterface(XModel.class, m_xDeskTop.getCurrentComponent());
+
+ return xModel;
+ }
+
+ public XScriptInvocationContext getInvocationContext() {
+
+ XScriptInvocationContext xContext =
+ UnoRuntime.queryInterface(XScriptInvocationContext.class, getDocument());
+
+ return xContext;
+ }
+
+ /**
+ Obtain the desktop reference on which the script can operate
+
+ @return XDesktop interface
+ */
+ public XDesktop getDesktop() {
+ return m_xDeskTop;
+ }
+
+ /**
+ Obtain the component context which the script can use to create other uno components
+
+ @return XComponentContext interface
+ */
+ public XComponentContext getComponentContext() {
+ return m_xComponentContext;
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/provider/PathUtils.java b/scripting/java/com/sun/star/script/framework/provider/PathUtils.java
new file mode 100644
index 000000000..08b859f4e
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/PathUtils.java
@@ -0,0 +1,83 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.provider;
+
+import com.sun.star.frame.XModel;
+import com.sun.star.uno.IQueryInterface;
+
+import java.lang.reflect.Method;
+
+import java.util.StringTokenizer;
+
+public class PathUtils {
+
+ public static String BOOTSTRAP_NAME;
+ private static boolean m_windows = false;
+
+ static {
+ // detect if windows platform
+ if (System.getProperty("os.name").startsWith("Windows"))
+ m_windows = true;
+
+ BOOTSTRAP_NAME = m_windows ? "bootstrap.ini" : "bootstraprc";
+ }
+
+ public static String getOidForModel(XModel xModel) {
+ String oid = "";
+
+ if (xModel != null) {
+ try {
+
+ Method getOid =
+ IQueryInterface.class.getMethod("getOid", (java.lang.Class[])null);
+
+ if (getOid != null) {
+ oid = (String)getOid.invoke(xModel, new Object[0]);
+ }
+
+ } catch (Exception ignore) {
+ }
+ }
+
+ return oid;
+ }
+
+ static public String make_url(String baseUrl, String url) {
+ StringBuilder buff = new StringBuilder(baseUrl.length() + url.length());
+ buff.append(baseUrl);
+ StringTokenizer t = new StringTokenizer(url, "/");
+
+ while (t.hasMoreElements()) {
+ if (buff.charAt(buff.length() - 1) != '/') {
+ buff.append('/');
+ }
+
+ try {
+ buff.append(java.net.URLEncoder.encode((String)t.nextElement(), "UTF-8"));
+ } catch (java.io.UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return buff.toString();
+ }
+
+ private PathUtils() {
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/provider/ScriptContext.java b/scripting/java/com/sun/star/script/framework/provider/ScriptContext.java
new file mode 100644
index 000000000..1f73ffbd4
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/ScriptContext.java
@@ -0,0 +1,143 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.provider;
+
+import com.sun.star.beans.PropertyAttribute;
+
+import com.sun.star.document.XScriptInvocationContext;
+
+import com.sun.star.frame.XDesktop;
+import com.sun.star.frame.XModel;
+
+import com.sun.star.lang.XMultiComponentFactory;
+
+import com.sun.star.lib.uno.helper.PropertySet;
+
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.provider.XScriptContext;
+
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+public class ScriptContext extends PropertySet implements XScriptContext {
+
+ private static final String HM_DOC_REF = "DocumentReference";
+ private static final String HM_DESKTOP = "Desktop";
+ private static final String HM_COMPONENT_CONTEXT = "ComponentContext";
+
+ private static final String DOC_URI = "SCRIPTING_DOC_URI";
+
+ public final XModel m_xModel;
+ private final XScriptInvocationContext m_xInvocationContext;
+
+ private final XDesktop m_xDeskTop;
+
+ private final XComponentContext m_xComponentContext;
+
+ // property, accessed via reflection
+ public String m_sDocURI = null;
+
+ private ScriptContext(XComponentContext xmComponentContext, XDesktop xDesktop,
+ XModel xModel, XScriptInvocationContext xInvocContext) {
+
+ this.m_xDeskTop = xDesktop;
+ this.m_xComponentContext = xmComponentContext;
+ this.m_xModel = xModel;
+ this.m_xInvocationContext = xInvocContext;
+
+ if (m_xModel != null) {
+
+ registerProperty(DOC_URI, new Type(String.class),
+ (short)(PropertyAttribute.MAYBEVOID | PropertyAttribute.TRANSIENT),
+ "m_sDocURI");
+
+ }
+
+ registerProperty(HM_DOC_REF, new Type(XModel.class),
+ (short)(PropertyAttribute.MAYBEVOID | PropertyAttribute.TRANSIENT),
+ "m_xModel");
+
+ registerProperty(HM_DESKTOP, new Type(XDesktop.class),
+ (short)(PropertyAttribute.MAYBEVOID | PropertyAttribute.TRANSIENT),
+ "m_xDeskTop");
+
+ registerProperty(HM_COMPONENT_CONTEXT, new Type(XDesktop.class),
+ (short)(PropertyAttribute.MAYBEVOID | PropertyAttribute.TRANSIENT),
+ "m_xComponentContext");
+ }
+
+ public static XScriptContext createContext(XModel xModel,
+ XScriptInvocationContext xInvocContext,
+ XComponentContext xCtxt, XMultiComponentFactory xMCF) {
+
+ XScriptContext sc = null;
+
+ try {
+
+ Object xInterface =
+ xMCF.createInstanceWithContext("com.sun.star.frame.Desktop", xCtxt);
+
+ XDesktop xDesktop = UnoRuntime.queryInterface(XDesktop.class, xInterface);
+
+ if (xModel != null) {
+ sc = new ScriptContext(xCtxt, xDesktop, xModel, xInvocContext);
+ } else {
+ sc = new EditorScriptContext(xCtxt, xDesktop);
+ }
+
+ } catch (Exception e) {
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ }
+
+ return sc;
+ }
+
+
+ /**
+ Obtain the document reference on which the script can operate
+
+ @return XModel interface
+ */
+ public XModel getDocument() {
+ return m_xModel;
+ }
+
+ public XScriptInvocationContext getInvocationContext() {
+ return m_xInvocationContext;
+ }
+
+ /**
+ Obtain the desktop reference on which the script can operate
+
+ @return XDesktop interface
+ */
+ public XDesktop getDesktop() {
+ return m_xDeskTop;
+ }
+
+ /**
+ Obtain the component context which the script can use to create other uno components
+
+ @return XComponentContext interface
+ */
+ public XComponentContext getComponentContext() {
+ return m_xComponentContext;
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/provider/ScriptEditor.java b/scripting/java/com/sun/star/script/framework/provider/ScriptEditor.java
new file mode 100644
index 000000000..32ebd2fef
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/ScriptEditor.java
@@ -0,0 +1,30 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.provider;
+
+import com.sun.star.script.framework.container.ScriptMetaData;
+import com.sun.star.script.provider.XScriptContext;
+
+public interface ScriptEditor {
+ Object execute() throws Exception;
+ void indicateErrorLine(int lineNum);
+ void edit(XScriptContext context, ScriptMetaData entry);
+ String getTemplate();
+ String getExtension();
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/provider/ScriptEditorBase.java b/scripting/java/com/sun/star/script/framework/provider/ScriptEditorBase.java
new file mode 100644
index 000000000..1a8bf33a5
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/ScriptEditorBase.java
@@ -0,0 +1,73 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.provider;
+
+import com.sun.star.beans.NamedValue;
+import com.sun.star.configuration.theDefaultProvider;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.script.framework.container.ScriptMetaData;
+import com.sun.star.script.provider.XScriptContext;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.UnoRuntime;
+
+import javax.swing.JOptionPane;
+import javax.swing.JDialog;
+
+public abstract class ScriptEditorBase implements ScriptEditor {
+ public XScriptContext context;
+
+ public void setContext(XScriptContext context) {
+ this.context = context;
+ }
+
+ public boolean isMacroExecutionEnabled() {
+ XNameAccess xNameAccess = null;
+ try {
+ String sAccess = "com.sun.star.configuration.ConfigurationAccess";
+ XMultiServiceFactory xMSFCfg = theDefaultProvider.get(context.getComponentContext());
+ Object oAccess = xMSFCfg.createInstanceWithArguments(sAccess,
+ new Object[] { new NamedValue("nodepath", "org.openoffice.Office.Common/Security/Scripting") });
+ xNameAccess = UnoRuntime.queryInterface(XNameAccess.class, oAccess);
+ Object result = xNameAccess.getByName("DisableMacrosExecution");
+ boolean bMacrosDisabled = AnyConverter.toBoolean(result);
+ if (bMacrosDisabled)
+ return false;
+ } catch (com.sun.star.uno.Exception e) {
+ return false;
+ }
+ return true;
+ }
+
+ // Wraps long error messages
+ private static class NarrowOptionPane extends JOptionPane {
+ private static final long serialVersionUID = 1L;
+ public int getMaxCharactersPerLineCount() {
+ return 100;
+ }
+ }
+
+ public void showErrorMessage(String message) {
+ JOptionPane optionPane = new NarrowOptionPane();
+ optionPane.setMessage(message);
+ optionPane.setMessageType(JOptionPane.ERROR_MESSAGE);
+ JDialog dialog = optionPane.createDialog(null, "Error");
+ dialog.setVisible(true);
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/provider/ScriptProvider.java b/scripting/java/com/sun/star/script/framework/provider/ScriptProvider.java
new file mode 100644
index 000000000..e48bc48fb
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/ScriptProvider.java
@@ -0,0 +1,673 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.provider;
+
+import com.sun.star.beans.Property;
+import com.sun.star.beans.XIntrospectionAccess;
+import com.sun.star.beans.XPropertyChangeListener;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.beans.XPropertySetInfo;
+import com.sun.star.beans.XVetoableChangeListener;
+
+import com.sun.star.container.XNameContainer;
+
+import com.sun.star.deployment.XPackage;
+
+import com.sun.star.document.XScriptInvocationContext;
+
+import com.sun.star.frame.XModel;
+import com.sun.star.frame.XTransientDocumentsDocumentContentFactory;
+
+import com.sun.star.lang.XInitialization;
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lang.XTypeProvider;
+
+import com.sun.star.script.XInvocation;
+import com.sun.star.script.browse.BrowseNodeTypes;
+import com.sun.star.script.browse.XBrowseNode;
+import com.sun.star.script.framework.browse.DialogFactory;
+import com.sun.star.script.framework.browse.ProviderBrowseNode;
+import com.sun.star.script.framework.container.ParcelContainer;
+import com.sun.star.script.framework.container.ParsedScriptUri;
+import com.sun.star.script.framework.container.ScriptMetaData;
+import com.sun.star.script.framework.container.UnoPkgContainer;
+import com.sun.star.script.framework.container.XMLParserFactory;
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.provider.ScriptFrameworkErrorException;
+import com.sun.star.script.provider.ScriptFrameworkErrorType;
+import com.sun.star.script.provider.XScript;
+import com.sun.star.script.provider.XScriptContext;
+import com.sun.star.script.provider.XScriptProvider;
+
+import com.sun.star.sdbc.XRow;
+
+import com.sun.star.ucb.Command;
+import com.sun.star.ucb.UniversalContentBroker;
+import com.sun.star.ucb.XCommandProcessor;
+import com.sun.star.ucb.XContent;
+import com.sun.star.ucb.XContentIdentifier;
+import com.sun.star.ucb.XUniversalContentBroker;
+
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.Exception;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.TypeClass;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+import com.sun.star.util.XMacroExpander;
+
+public abstract class ScriptProvider implements
+ XScriptProvider, XBrowseNode, XPropertySet, XInvocation, XInitialization,
+ XTypeProvider, XServiceInfo, XNameContainer {
+
+ private final String[] __serviceNames = {
+ "com.sun.star.script.provider.ScriptProviderFor",
+ "com.sun.star.script.provider.LanguageScriptProvider",
+ "com.sun.star.script.browse.BrowseNode",
+ "com.sun.star.script.provider.ScriptProvider"
+ };
+
+ protected String language;
+
+ protected XComponentContext m_xContext;
+ private XMultiComponentFactory m_xMultiComponentFactory;
+ protected XModel m_xModel;
+ protected XScriptInvocationContext m_xInvocContext;
+ private ParcelContainer m_container;
+
+ // proxies to helper objects which implement interfaces
+ private XPropertySet m_xPropertySetProxy;
+ private XInvocation m_xInvocationProxy;
+
+ // TODO should this be implemented in this class
+ private XBrowseNode m_xBrowseNodeProxy;
+ private XScriptContext m_xScriptContext;
+
+ public ScriptProvider(XComponentContext ctx, String language) {
+ this.language = language;
+ __serviceNames[0] += language;
+
+ LogUtils.DEBUG("ScriptProvider: constructor - start. " + language);
+
+ m_xContext = ctx;
+
+ // Initialize DialogFactory class in case dialogs are required
+ DialogFactory.createDialogFactory(m_xContext);
+
+ try {
+ m_xMultiComponentFactory = m_xContext.getServiceManager();
+
+ if (m_xMultiComponentFactory == null) {
+ throw new Exception("Error could not obtain a " +
+ "multicomponent factory - rethrowing Exception.");
+ }
+
+ Object serviceObj =
+ m_xContext.getValueByName(
+ "/singletons/com.sun.star.util.theMacroExpander");
+
+ XMacroExpander me =
+ (XMacroExpander) AnyConverter.toObject(
+ new Type(XMacroExpander.class), serviceObj);
+
+ XMLParserFactory.setOfficeDTDURL(
+ me.expandMacros(
+ "$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR/dtd/officedocument/1_0/"));
+
+ } catch (Exception e) {
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ throw new com.sun.star.uno.RuntimeException(
+ e, "Error constructing ScriptProvider: " + e);
+ }
+
+ LogUtils.DEBUG("ScriptProvider: constructor - finished.");
+ }
+
+ synchronized public XScriptContext getScriptingContext() {
+ if (m_xScriptContext == null) {
+ m_xScriptContext = ScriptContext.createContext(m_xModel, m_xInvocContext,
+ m_xContext, m_xMultiComponentFactory);
+ }
+
+ return m_xScriptContext;
+ }
+
+ public void initialize(Object[] aArguments)
+ throws com.sun.star.uno.Exception {
+ LogUtils.DEBUG("entering XInit for language " + language);
+ boolean isPkgProvider = false;
+
+ if (aArguments.length == 1) {
+ String contextUrl = null;
+
+ if (AnyConverter.getType(aArguments[0]).getTypeClass().equals(
+ TypeClass.INTERFACE)) {
+ // try whether it denotes a XScriptInvocationContext
+ m_xInvocContext =
+ UnoRuntime.queryInterface(XScriptInvocationContext.class, aArguments[0]);
+
+ if (m_xInvocContext != null) {
+ // if so, obtain the document - by definition, this must be
+ // the ScriptContainer
+ m_xModel =
+ UnoRuntime.queryInterface(XModel.class, m_xInvocContext.getScriptContainer());
+ } else {
+ // otherwise, check whether it's an XModel
+ m_xModel =
+ UnoRuntime.queryInterface(XModel.class, aArguments[0]);
+ }
+
+ if (m_xModel == null) {
+ throw new com.sun.star.uno.Exception(
+ "ScriptProvider argument must be either a string, a valid XScriptInvocationContext, "
+ + "or an XModel", this);
+ }
+
+ contextUrl = getDocUrlFromModel(m_xModel);
+ m_container = new ParcelContainer(m_xContext, contextUrl, language);
+
+ } else if (AnyConverter.isString(aArguments[0])) {
+
+ String originalContextURL = AnyConverter.toString(aArguments[0]);
+ LogUtils.DEBUG("creating Application, path: " + originalContextURL);
+ contextUrl = originalContextURL;
+
+ // TODO no support for packages in documents yet
+ if (originalContextURL.startsWith("vnd.sun.star.tdoc")) {
+ m_container = new ParcelContainer(m_xContext, contextUrl, language);
+ m_xModel = getModelFromDocUrl(originalContextURL);
+ } else {
+ String extensionDb = "vnd.sun.star.expand:${$BRAND_INI_DIR/"
+ + PathUtils.BOOTSTRAP_NAME + "::UserInstallation}/user";
+
+ String extensionRepository = null;
+
+ if (originalContextURL.startsWith("bundled")) {
+ contextUrl = "vnd.sun.star.expand:$BUNDLED_EXTENSIONS";
+ extensionRepository = "bundled";
+ } else if (originalContextURL.startsWith("share")) {
+ contextUrl = "vnd.sun.star.expand:$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR";
+ extensionRepository = "shared";
+ } else if (originalContextURL.startsWith("user")) {
+ contextUrl = "vnd.sun.star.expand:${$BRAND_INI_DIR/"
+ + PathUtils.BOOTSTRAP_NAME + "::UserInstallation}/user";
+ extensionRepository = "user";
+ }
+
+ if (originalContextURL.endsWith("uno_packages")) {
+ isPkgProvider = true;
+
+ if (!originalContextURL.equals(contextUrl)
+ && extensionRepository != null
+ && !extensionRepository.equals("bundled")) {
+
+ contextUrl = PathUtils.make_url(contextUrl, "uno_packages");
+ }
+ }
+
+ if (isPkgProvider) {
+ m_container =
+ new UnoPkgContainer(m_xContext, contextUrl, extensionDb, extensionRepository,
+ language);
+ } else {
+ m_container =
+ new ParcelContainer(m_xContext, contextUrl, language);
+ }
+ }
+ } else {
+ throw new com.sun.star.uno.RuntimeException(
+ "ScriptProvider created with invalid argument");
+ }
+
+ LogUtils.DEBUG("Modified Application path is: " + contextUrl);
+ LogUtils.DEBUG("isPkgProvider is: " + isPkgProvider);
+
+ // TODO should all be done in this class instead of
+ // delegation????
+ m_xBrowseNodeProxy =
+ new ProviderBrowseNode(this, m_container, m_xContext);
+
+ m_xInvocationProxy =
+ UnoRuntime.queryInterface(XInvocation.class, m_xBrowseNodeProxy);
+ m_xPropertySetProxy =
+ UnoRuntime.queryInterface(XPropertySet.class, m_xBrowseNodeProxy);
+ } else {
+ // this is ok, for example when executing a script from the
+ // command line
+ LogUtils.DEBUG("ScriptProviderFor" + language +
+ " initialized without a context");
+ }
+
+ LogUtils.DEBUG("leaving XInit");
+ }
+
+ /**
+ * Gets the types attribute of the ScriptProvider object
+ *
+ * @return The types value
+ */
+ public com.sun.star.uno.Type[] getTypes() {
+ Type[] retValue = new Type[ 8 ];
+ retValue[ 0 ] = new Type(XScriptProvider.class);
+ retValue[ 1 ] = new Type(XBrowseNode.class);
+ retValue[ 2 ] = new Type(XInitialization.class);
+ retValue[ 3 ] = new Type(XTypeProvider.class);
+ retValue[ 4 ] = new Type(XServiceInfo.class);
+ retValue[ 5 ] = new Type(XPropertySet.class);
+ retValue[ 6 ] = new Type(XInvocation.class);
+ retValue[ 7 ] = new Type(com.sun.star.container.XNameContainer.class);
+
+ return retValue;
+ }
+
+ /**
+ * Gets the implementationId attribute of the ScriptProvider object
+ *
+ * @return The implementationId value
+ */
+ public byte[] getImplementationId() {
+ return new byte[0];
+ }
+
+ /**
+ * Gets the implementationName attribute of the ScriptProvider object
+ *
+ * @return The implementationName value
+ */
+ public String getImplementationName() {
+ return getClass().getName();
+ }
+
+ /**
+ * Description of the Method
+ *
+ * @param serviceName Description of the Parameter
+ * @return Description of the Return Value
+ */
+ public boolean supportsService(String serviceName) {
+ for (int index = __serviceNames.length; index-- > 0;) {
+ if (serviceName.equals(__serviceNames[ index ])) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Gets the supportedServiceNames attribute of the ScriptProvider object
+ *
+ * @return The supportedServiceNames value
+ */
+ public String[] getSupportedServiceNames() {
+ return __serviceNames;
+ }
+
+ public abstract XScript getScript(/*IN*/String scriptURI) throws
+ com.sun.star.uno.RuntimeException, ScriptFrameworkErrorException;
+
+ // TODO need to encapsulate this better,
+ // Some factory concept for creating/accessing Editor
+ // How this is passed down or how it is accessible by BrowseNode
+ // implementations needs thinking about
+ // This method is used to determine whether the ScriptProvider
+ // has a ScriptEditor
+ public abstract boolean hasScriptEditor();
+
+ // TODO see above
+ // This method is used to get the ScriptEditor for this ScriptProvider
+ public abstract ScriptEditor getScriptEditor();
+
+ public ScriptMetaData getScriptData(/*IN*/String scriptURI) throws
+ ScriptFrameworkErrorException {
+
+ try {
+ ParsedScriptUri details = m_container.parseScriptUri(scriptURI);
+
+ try {
+ ScriptMetaData scriptData = m_container.findScript(details);
+
+ if (scriptData == null) {
+ throw new ScriptFrameworkErrorException(
+ details.function + " does not exist", null, details.function, language,
+ ScriptFrameworkErrorType.NO_SUCH_SCRIPT);
+ }
+
+ return scriptData;
+ } catch (com.sun.star.container.NoSuchElementException nse) {
+ ScriptFrameworkErrorException e2 =
+ new ScriptFrameworkErrorException(nse.getMessage(), null, details.function,
+ language, ScriptFrameworkErrorType.NO_SUCH_SCRIPT);
+ e2.initCause(nse);
+ throw e2;
+ } catch (com.sun.star.lang.WrappedTargetException wta) {
+ // TODO specify the correct error Type
+ java.lang.Exception wrapped = (java.lang.Exception) wta.TargetException;
+ String message = wta.getMessage();
+
+ if (wrapped != null) {
+ message = wrapped.getMessage();
+ }
+
+ ScriptFrameworkErrorException e2 =
+ new ScriptFrameworkErrorException(message, null, details.function, language,
+ ScriptFrameworkErrorType.UNKNOWN);
+ e2.initCause(wta);
+ throw e2;
+ }
+ } catch (com.sun.star.lang.IllegalArgumentException ila) {
+ // TODO specify the correct error Type
+ ScriptFrameworkErrorException e2
+ = new ScriptFrameworkErrorException(
+ ila.getMessage(), null, scriptURI, language,
+ ScriptFrameworkErrorType.UNKNOWN);
+ e2.initCause(ila);
+ throw e2;
+ }
+ }
+
+ // Implementation of XBrowseNode interface
+ public String getName() {
+ return language;
+ }
+
+ public XBrowseNode[] getChildNodes() {
+ if (m_xBrowseNodeProxy == null) {
+ LogUtils.DEBUG("No Nodes available ");
+ return new XBrowseNode[0];
+ }
+
+ return m_xBrowseNodeProxy .getChildNodes();
+ }
+
+ public boolean hasChildNodes() {
+ if (m_xBrowseNodeProxy == null) {
+ LogUtils.DEBUG("No Nodes available ");
+ return false;
+ }
+
+ return m_xBrowseNodeProxy.hasChildNodes();
+ }
+
+ public short getType() {
+ return BrowseNodeTypes.CONTAINER;
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ // implementation of XInvocation interface
+ public XIntrospectionAccess getIntrospection() {
+ return m_xInvocationProxy.getIntrospection();
+ }
+
+ public Object invoke(String aFunctionName, Object[] aParams,
+ short[][] aOutParamIndex, Object[][] aOutParam) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.script.CannotConvertException,
+ com.sun.star.reflection.InvocationTargetException {
+
+ return m_xInvocationProxy.invoke(
+ aFunctionName, aParams, aOutParamIndex, aOutParam);
+ }
+
+ public void setValue(String aPropertyName, Object aValue) throws
+ com.sun.star.beans.UnknownPropertyException,
+ com.sun.star.script.CannotConvertException,
+ com.sun.star.reflection.InvocationTargetException {
+
+ m_xInvocationProxy.setValue(aPropertyName, aValue);
+ }
+
+ public Object getValue(String aPropertyName) throws
+ com.sun.star.beans.UnknownPropertyException {
+ return m_xInvocationProxy.getValue(aPropertyName);
+ }
+
+ public boolean hasMethod(String aName) {
+ return m_xInvocationProxy.hasMethod(aName);
+ }
+
+ public boolean hasProperty(String aName) {
+ return m_xInvocationProxy.hasProperty(aName);
+ }
+
+ public XPropertySetInfo getPropertySetInfo() {
+ return m_xPropertySetProxy.getPropertySetInfo();
+ }
+
+ public void setPropertyValue(String aPropertyName, Object aValue) throws
+ com.sun.star.beans.UnknownPropertyException,
+ com.sun.star.beans.PropertyVetoException,
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.lang.WrappedTargetException {
+
+ m_xPropertySetProxy.setPropertyValue(aPropertyName, aValue);
+ }
+
+ public Object getPropertyValue(String PropertyName) throws
+ com.sun.star.beans.UnknownPropertyException,
+ com.sun.star.lang.WrappedTargetException {
+
+ return m_xPropertySetProxy.getPropertyValue(PropertyName);
+ }
+
+ public void addPropertyChangeListener(String aPropertyName,
+ XPropertyChangeListener xListener) throws
+ com.sun.star.beans.UnknownPropertyException,
+ com.sun.star.lang.WrappedTargetException {
+
+ m_xPropertySetProxy.addPropertyChangeListener(aPropertyName, xListener);
+ }
+
+ public void removePropertyChangeListener(
+ String aPropertyName, XPropertyChangeListener aListener) throws
+ com.sun.star.beans.UnknownPropertyException,
+ com.sun.star.lang.WrappedTargetException {
+
+ m_xPropertySetProxy.removePropertyChangeListener(
+ aPropertyName, aListener);
+ }
+
+ public void addVetoableChangeListener(
+ String PropertyName, XVetoableChangeListener aListener) throws
+ com.sun.star.beans.UnknownPropertyException,
+ com.sun.star.lang.WrappedTargetException {
+
+ m_xPropertySetProxy.addVetoableChangeListener(PropertyName, aListener);
+ }
+
+ public void removeVetoableChangeListener(String PropertyName,
+ XVetoableChangeListener aListener) throws
+ com.sun.star.beans.UnknownPropertyException,
+ com.sun.star.lang.WrappedTargetException {
+
+ m_xPropertySetProxy.removeVetoableChangeListener(
+ PropertyName, aListener);
+
+ }
+ public java.lang.Object getByName(String aName) throws
+ com.sun.star.container.NoSuchElementException,
+ com.sun.star.lang.WrappedTargetException {
+
+ // TODO needs implementing?
+ throw new com.sun.star.uno.RuntimeException("getByName not implemented");
+ }
+
+ public String[] getElementNames() {
+ // TODO needs implementing?
+ throw new com.sun.star.uno.RuntimeException("getElementNames not implemented");
+ }
+
+ // Performs the getRegStatus functionality for the PkgMgr
+ public boolean hasByName(String aName) {
+ return ((UnoPkgContainer)m_container).hasRegisteredUnoPkgContainer(aName);
+ }
+
+ public com.sun.star.uno.Type getElementType() {
+ // TODO at the moment this returns void indicating
+ // type is unknown should indicate XPackage ? do we implement XPackage
+ return new Type();
+ }
+
+ public boolean hasElements() {
+ // TODO needs implementing?
+ throw new com.sun.star.uno.RuntimeException("hasElements not implemented");
+ }
+ public void replaceByName(String aName, java.lang.Object aElement) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.container.NoSuchElementException,
+ com.sun.star.lang.WrappedTargetException {
+
+ // TODO needs implementing
+ throw new com.sun.star.uno.RuntimeException("replaceByName not implemented");
+ }
+
+ public void insertByName(String aName, java.lang.Object aElement) throws
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.container.ElementExistException,
+ com.sun.star.lang.WrappedTargetException {
+
+ LogUtils.DEBUG("Provider for " + language + " received register for package "
+ + aName);
+
+ XPackage newPackage = UnoRuntime.queryInterface(XPackage.class, aElement);
+
+ if (aName == null || aName.length() == 0) {
+ throw new com.sun.star.lang.IllegalArgumentException("Empty name");
+ }
+
+ if (newPackage == null) {
+ throw new com.sun.star.lang.IllegalArgumentException("No package supplied");
+ }
+
+ ((UnoPkgContainer)m_container).processUnoPackage(newPackage, language);
+ }
+
+ // de-register for library only !!
+ public void removeByName(String Name) throws
+ com.sun.star.container.NoSuchElementException,
+ com.sun.star.lang.WrappedTargetException {
+
+ LogUtils.DEBUG("In ScriptProvider.removeByName() for " + Name
+ + " this provider = " + language);
+
+ ParcelContainer c =
+ ((UnoPkgContainer)m_container).getRegisteredUnoPkgContainer(
+ Name);
+
+ if (c != null) {
+ String libName;
+
+ if (Name.endsWith("/")) {
+ String tmp = Name.substring(0, Name.lastIndexOf('/'));
+ libName = tmp.substring(tmp.lastIndexOf('/') + 1);
+ } else {
+ libName = Name.substring(Name.lastIndexOf('/') + 1);
+ }
+
+ LogUtils.DEBUG("Deregistering library " + libName);
+
+ if (c.removeParcel(libName)) {
+ ((UnoPkgContainer)m_container).deRegisterPackageContainer(Name);
+ } else {
+ throw new com.sun.star.container.NoSuchElementException(
+ libName + " cannot be removed from container.");
+ }
+ } else {
+ throw new com.sun.star.container.NoSuchElementException(
+ Name + " doesn't exist for " + language);
+ }
+
+ // TODO see if we want to remove the ParcelContainer is no Parcels/Libraries left
+ }
+
+ private String getDocUrlFromModel(XModel document) {
+ XTransientDocumentsDocumentContentFactory factory = null;
+
+ try {
+
+ factory = UnoRuntime.queryInterface(
+ XTransientDocumentsDocumentContentFactory.class,
+ m_xMultiComponentFactory.createInstanceWithContext(
+ "com.sun.star.frame.TransientDocumentsDocumentContentFactory",
+ m_xContext));
+
+ } catch (Exception ex) {
+ }
+
+ if (factory == null)
+ throw new com.sun.star.uno.RuntimeException(
+ "ScriptProvider: unable to create a TDOC context factory.", this);
+
+ try {
+ XContent content = factory.createDocumentContent(document);
+ return content.getIdentifier().getContentIdentifier();
+ } catch (com.sun.star.lang.IllegalArgumentException ex) {
+ }
+
+ LogUtils.DEBUG("unable to determine the model's TDOC URL");
+ return "";
+ }
+
+ private XModel getModelFromDocUrl(String docUrl) {
+
+ LogUtils.DEBUG("getModelFromDocUrl - searching for match for ->"
+ + docUrl + "<-");
+
+ XModel xModel = null;
+
+ try {
+ XUniversalContentBroker ucb = UniversalContentBroker.create(m_xContext);
+
+ XContentIdentifier xCntId = ucb.createContentIdentifier(docUrl);
+
+ XContent xCnt = ucb.queryContent(xCntId);
+
+ XCommandProcessor xCmd =
+ UnoRuntime.queryInterface(XCommandProcessor.class, xCnt);
+
+ Property[] pArgs = new Property[ ] { new Property() };
+ pArgs[ 0 ].Name = "DocumentModel";
+ pArgs[ 0 ].Handle = -1;
+
+ Command command = new Command();
+
+ command.Handle = -1;
+ command.Name = "getPropertyValues";
+ command.Argument = pArgs;
+
+ com.sun.star.ucb.XCommandEnvironment env = null ;
+ Object result = xCmd.execute(command, 0, env) ;
+
+ XRow values = UnoRuntime.queryInterface(XRow.class, result);
+
+ xModel = UnoRuntime.queryInterface(XModel.class,
+ values.getObject(1, null));
+
+ } catch (Exception ignore) {
+ LogUtils.DEBUG("Failed to get model exception " + ignore);
+ }
+
+ return xModel;
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/provider/SwingInvocation.java b/scripting/java/com/sun/star/script/framework/provider/SwingInvocation.java
new file mode 100644
index 000000000..af563fa8e
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/SwingInvocation.java
@@ -0,0 +1,39 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.provider;
+
+import javax.swing.SwingUtilities;
+
+// On macOS, AWT/Swing must not be accessed from the AppKit thread, so call
+// SwingUtilities.invokeLater always on a fresh thread to avoid that problem
+// (also, the current thread must not wait for that fresh thread to terminate,
+// as that would cause a deadlock if this thread is the AppKit thread):
+public final class SwingInvocation {
+
+ public static void invoke(final Runnable doRun) {
+ new Thread("SwingInvocation") {
+ @Override
+ public void run() {
+ SwingUtilities.invokeLater(doRun);
+ }
+ } .start();
+ }
+
+ private SwingInvocation() {}
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/provider/beanshell/MANIFEST.MF b/scripting/java/com/sun/star/script/framework/provider/beanshell/MANIFEST.MF
new file mode 100644
index 000000000..689b6fde9
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/beanshell/MANIFEST.MF
@@ -0,0 +1,2 @@
+RegistrationClassName: com.sun.star.script.framework.provider.beanshell.ScriptProviderForBeanShell
+UNO-Type-Path:
diff --git a/scripting/java/com/sun/star/script/framework/provider/beanshell/PlainSourceView.java b/scripting/java/com/sun/star/script/framework/provider/beanshell/PlainSourceView.java
new file mode 100644
index 000000000..e519587ff
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/beanshell/PlainSourceView.java
@@ -0,0 +1,395 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.provider.beanshell;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JComponent;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.KeyStroke;
+import javax.swing.UIManager;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.UndoableEditEvent;
+import javax.swing.event.UndoableEditListener;
+import javax.swing.text.BadLocationException;
+import javax.swing.undo.CompoundEdit;
+import javax.swing.undo.UndoManager;
+import java.util.List;
+import java.util.ArrayList;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PlainSourceView extends JScrollPane implements
+ ScriptSourceView, DocumentListener {
+
+ private final ScriptSourceModel model;
+ private JTextArea ta;
+ private GlyphGutter gg;
+ private int linecount;
+ private boolean isModified = false;
+ private static final String undoKey = "Undo";
+ private static final String redoKey = "Redo";
+ private CompoundEdit compoundEdit = null;
+ private static final int noLimit = -1;
+ UndoManager undoManager;
+ private List<UnsavedChangesListener> unsavedListener = new ArrayList<UnsavedChangesListener>();
+
+ private static final Pattern tabPattern = Pattern.compile("^ *(\\t)");
+ private static final Pattern indentationPattern = Pattern.compile("^([^\\S\\r\\n]*)(([^\\{])*\\{\\s*)*");
+
+ public PlainSourceView(ScriptSourceModel model) {
+ this.model = model;
+ initUI();
+ model.setView(this);
+ }
+
+ public void undo(){
+ if(compoundEdit!=null){
+ compoundEdit.end();
+ undoManager.addEdit(compoundEdit);
+ compoundEdit = null;
+ }
+ if(undoManager.canUndo()){
+ undoManager.undo();
+ }
+ // check if it's the last undoable change
+ if(undoManager.canUndo() == false){
+ setModified(false);
+ }
+ }
+ public void redo(){
+ if(undoManager.canRedo()){
+ undoManager.redo();
+ }
+ }
+ public void clear() {
+ ta.setText("");
+ }
+
+ public void update() {
+ /* Remove ourselves as a DocumentListener while loading the source
+ so we don't get a storm of DocumentEvents during loading */
+ ta.getDocument().removeDocumentListener(this);
+
+ if (!isModified) {
+ int pos = ta.getCaretPosition();
+ ta.setText(model.getText());
+
+ try {
+ ta.setCaretPosition(pos);
+ } catch (IllegalArgumentException iae) {
+ // do nothing and allow JTextArea to set its own position
+ }
+ }
+
+ // scroll to currentPosition of the model
+ try {
+ int line = ta.getLineStartOffset(model.getCurrentPosition());
+ Rectangle rect = ta.modelToView(line);
+ if (rect != null) {
+ ta.scrollRectToVisible(rect);
+ }
+ } catch (BadLocationException e) {
+ // couldn't scroll to line, do nothing
+ }
+
+ gg.repaint();
+
+ // Add back the listener
+ ta.getDocument().addDocumentListener(this);
+ }
+
+ public boolean isModified() {
+ return isModified;
+ }
+
+ private void notifyListeners (boolean isUnsaved) {
+ for (UnsavedChangesListener listener : unsavedListener) {
+ listener.onUnsavedChanges(isUnsaved);
+ }
+ }
+
+ public void setModified(boolean value) {
+ if(value != isModified) {
+ notifyListeners(value);
+ isModified = value;
+ }
+ }
+
+ private void initUI() {
+ try{
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ }
+ catch(Exception e){
+ // What to do here
+ }
+ ta = new JTextArea();
+ ta.setTabSize(4);
+ ta.setRows(15);
+ ta.setColumns(40);
+ ta.setLineWrap(false);
+ ta.insert(model.getText(), 0);
+ ta.setFont(new Font("Monospaced", ta.getFont().getStyle(), ta.getFont().getSize()));
+ undoManager = new UndoManager();
+ undoManager.setLimit(noLimit);
+ ta.getDocument().addUndoableEditListener(new UndoableEditListener(){
+ @Override
+ public void undoableEditHappened(UndoableEditEvent editEvent) {
+ if(compoundEdit == null){
+ compoundEdit = new CompoundEdit();
+ }
+ compoundEdit.addEdit(editEvent.getEdit());
+ }
+ });
+
+ ta.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_MASK), undoKey);
+ ta.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_MASK), redoKey);
+
+ ta.addKeyListener(new KeyAdapter(){
+ @Override
+ public void keyPressed(KeyEvent ke) {
+ // if shift + tab was pressed, remove the first tab before any code begins
+ if (ke.isShiftDown() && ke.getKeyCode() == KeyEvent.VK_TAB) {
+ try {
+ int caretOffset = ta.getCaretPosition();
+ int lineOffset = ta.getLineOfOffset(caretOffset);
+ int startOffset = ta.getLineStartOffset(lineOffset);
+ int endOffset = ta.getLineEndOffset(lineOffset);
+
+ Matcher matcher = tabPattern.matcher(ta.getText(startOffset, endOffset - startOffset));
+ if (matcher.find()) {
+ ta.replaceRange(null, startOffset + matcher.start(1), startOffset + matcher.end(1));
+ }
+ } catch (BadLocationException e) {
+ // could not find correct location of the tab
+ }
+ }
+ // if the enter key was pressed, adjust indentation of the current line accordingly
+ if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
+ try {
+ int caretOffset = ta.getCaretPosition();
+ int lineOffset = ta.getLineOfOffset(caretOffset);
+ int startOffset = ta.getLineStartOffset(lineOffset);
+ int endOffset = ta.getLineEndOffset(lineOffset);
+
+ Matcher matcher = indentationPattern.matcher(ta.getText(startOffset, endOffset - startOffset));
+ // insert new line including indentation of the previous line
+ ta.insert("\n", caretOffset++);
+ if (matcher.find()) {
+ if (matcher.group(1).length() > 0) {
+ ta.insert(matcher.group(1), caretOffset++);
+ }
+ // if there is an open curly bracket in the current line, increase indentation level
+ if (matcher.group(3) != null) {
+ ta.insert("\t", caretOffset);
+ }
+ }
+ ke.consume();
+ } catch (BadLocationException e) {
+ // could not find correct location of the indentation
+ }
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent ke){
+ if(ke.getKeyCode() == KeyEvent.VK_SPACE || ke.getKeyCode() == KeyEvent.VK_ENTER){
+ compoundEdit.end();
+ undoManager.addEdit(compoundEdit);
+ compoundEdit = null;
+ }
+ }
+ });
+
+ ta.getActionMap().put(undoKey, new AbstractAction(undoKey){
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ undo();
+ }
+ });
+
+ ta.getActionMap().put(redoKey, new AbstractAction(redoKey){
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ redo();
+ }
+ });
+
+ linecount = ta.getLineCount();
+
+ gg = new GlyphGutter(this);
+
+ setViewportView(ta);
+ setRowHeaderView(gg);
+
+ ta.getDocument().addDocumentListener(this);
+ }
+
+ /* Implementation of DocumentListener interface */
+ public void insertUpdate(DocumentEvent e) {
+ doChanged();
+ }
+
+ public void removeUpdate(DocumentEvent e) {
+ doChanged();
+ }
+
+ public void changedUpdate(DocumentEvent e) {
+ doChanged();
+ }
+
+ /* If the number of lines in the JTextArea has changed then update the
+ GlyphGutter */
+ private void doChanged() {
+ setModified(true);
+
+ if (linecount != ta.getLineCount()) {
+ gg.update();
+ linecount = ta.getLineCount();
+ }
+ }
+
+ public String getText() {
+ return ta.getText();
+ }
+
+ public JTextArea getTextArea() {
+ return ta;
+ }
+
+ public int getCurrentPosition() {
+ return model.getCurrentPosition();
+ }
+
+ public void addListener(UnsavedChangesListener toAdd) {
+ unsavedListener.add(toAdd);
+ }
+}
+
+class GlyphGutter extends JComponent {
+
+ private final PlainSourceView view;
+ private static final String DUMMY_STRING = "99";
+
+ GlyphGutter(PlainSourceView view) {
+ this.view = view;
+ update();
+ }
+
+ public void update() {
+ JTextArea textArea = view.getTextArea();
+ Font font = textArea.getFont();
+ setFont(font);
+
+ FontMetrics metrics = getFontMetrics(font);
+ int h = metrics.getHeight();
+ int lineCount = textArea.getLineCount() + 1;
+
+ String dummy = Integer.toString(lineCount);
+
+ if (dummy.length() < 2) {
+ dummy = DUMMY_STRING;
+ }
+
+ Dimension d = new Dimension();
+ d.width = metrics.stringWidth(dummy) + 16;
+ d.height = lineCount * h + 100;
+ setPreferredSize(d);
+ setSize(d);
+ }
+
+ @Override
+ public void paintComponent(Graphics g) {
+ JTextArea textArea = view.getTextArea();
+
+ Font font = textArea.getFont();
+ g.setFont(font);
+
+ FontMetrics metrics = getFontMetrics(font);
+ Rectangle clip = g.getClipBounds();
+
+ g.setColor(getBackground());
+ g.fillRect(clip.x, clip.y, clip.width, clip.height);
+
+ int ascent = metrics.getMaxAscent();
+ int h = metrics.getHeight();
+ int lineCount = textArea.getLineCount() + 1;
+
+ int startLine = clip.y / h;
+ int endLine = (clip.y + clip.height) / h + 1;
+ int width = getWidth();
+
+ if (endLine > lineCount) {
+ endLine = lineCount;
+ }
+
+ for (int i = startLine; i < endLine; i++) {
+ String text;
+ text = Integer.toString(i + 1) + " ";
+ int y = i * h;
+ g.setColor(Color.blue);
+ g.drawString(text, 0, y + ascent);
+ int x = width - ascent;
+
+ // if currentPosition is not -1 then a red arrow will be drawn
+ if (i == view.getCurrentPosition()) {
+ drawArrow(g, ascent, x, y);
+ }
+ }
+ }
+
+ private void drawArrow(Graphics g, int ascent, int x, int y) {
+ Polygon arrow = new Polygon();
+ int dx = x;
+ y += ascent - 10;
+ int dy = y;
+ arrow.addPoint(dx, dy + 3);
+ arrow.addPoint(dx + 5, dy + 3);
+
+ for (x = dx + 5; x <= dx + 10; x++, y++) {
+ arrow.addPoint(x, y);
+ }
+
+ for (x = dx + 9; x >= dx + 5; x--, y++) {
+ arrow.addPoint(x, y);
+ }
+
+ arrow.addPoint(dx + 5, dy + 7);
+ arrow.addPoint(dx, dy + 7);
+
+ g.setColor(Color.red);
+ g.fillPolygon(arrow);
+ g.setColor(Color.black);
+ g.drawPolygon(arrow);
+ }
+}
+
diff --git a/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptEditorForBeanShell.java b/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptEditorForBeanShell.java
new file mode 100644
index 000000000..0ab265ecc
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptEditorForBeanShell.java
@@ -0,0 +1,400 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.provider.beanshell;
+
+import com.sun.star.script.framework.container.ScriptMetaData;
+import com.sun.star.script.framework.provider.ClassLoaderFactory;
+import com.sun.star.script.framework.provider.ScriptEditorBase;
+import com.sun.star.script.framework.provider.SwingInvocation;
+import com.sun.star.script.provider.XScriptContext;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.Dimension;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.net.URL;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+import javax.swing.JToolBar;
+import javax.swing.BorderFactory;
+
+public class ScriptEditorForBeanShell extends ScriptEditorBase implements ActionListener {
+
+ private JFrame frame;
+ private String filename;
+
+ private ScriptSourceModel model;
+ private ScriptSourceView view;
+
+ private URL scriptURL = null;
+ private ClassLoader cl = null;
+ private JButton saveBtn;
+
+ // global ScriptEditorForBeanShell returned for getEditor() calls
+ private static ScriptEditorForBeanShell theScriptEditorForBeanShell;
+
+ // global list of ScriptEditors, key is [external form of URL] of file being edited
+ private static Map<String, ScriptEditorForBeanShell> BEING_EDITED =
+ new HashMap<String, ScriptEditorForBeanShell>();
+
+ // template for new BeanShell scripts
+ private static String BSHTEMPLATE;
+
+ // try to load the template for BeanShell scripts
+ static {
+ BSHTEMPLATE = "// BeanShell script";
+ try {
+ URL url = ScriptEditorForBeanShell.class.getResource("template.bsh");
+ if (url != null) {
+ InputStream in = url.openStream();
+ StringBuilder buf = new StringBuilder();
+ byte[] b = new byte[1024];
+ int len;
+
+ while ((len = in.read(b)) != -1) {
+ buf.append(new String(b, 0, len));
+ }
+
+ in.close();
+
+ BSHTEMPLATE = buf.toString();
+ }
+ } catch (IOException ioe) {
+ } catch (Exception e) {
+ }
+ }
+
+ /**
+ * Returns the global ScriptEditorForBeanShell instance.
+ */
+
+ public static synchronized ScriptEditorForBeanShell getEditor() {
+ if (theScriptEditorForBeanShell == null) {
+ theScriptEditorForBeanShell =
+ new ScriptEditorForBeanShell();
+ }
+
+ return theScriptEditorForBeanShell;
+ }
+
+ /**
+ * Get the ScriptEditorForBeanShell instance for this URL
+ *
+ * @param url The URL of the script source file
+ *
+ * @return The ScriptEditorForBeanShell associated with
+ * the given URL if one exists, otherwise null.
+ */
+ public static ScriptEditorForBeanShell getEditor(URL url) {
+ synchronized (BEING_EDITED) {
+ return BEING_EDITED.get(url.toExternalForm());
+ }
+ }
+
+ /**
+ * Returns whether or not the script source being edited in this
+ * ScriptEditorForBeanShell has been modified
+ */
+ public boolean isModified() {
+ return view.isModified();
+ }
+
+ /**
+ * Returns the text being displayed in this ScriptEditorForBeanShell
+ *
+ * @return The text displayed in this ScriptEditorForBeanShell
+ */
+ public String getText() {
+ return view.getText();
+ }
+
+ /**
+ * Returns the template text for BeanShell scripts
+ *
+ * @return The template text for BeanShell scripts
+ */
+ public String getTemplate() {
+ return BSHTEMPLATE;
+ }
+
+ /**
+ * Returns the default extension for BeanShell scripts
+ *
+ * @return The default extension for BeanShell scripts
+ */
+ public String getExtension() {
+ return "bsh";
+ }
+
+ /**
+ * Indicates the line where error occurred
+ *
+ */
+ public void indicateErrorLine(int lineNum) {
+ model.indicateErrorLine(lineNum);
+ }
+
+ /**
+ * Executes the script edited by the editor
+ *
+ */
+ public Object execute() throws Exception {
+ if (!isMacroExecutionEnabled()) {
+ showErrorMessage("Macro Execution has been disabled.");
+ return null;
+ }
+
+ frame.toFront();
+ return model.execute(context, cl);
+ }
+
+ /**
+ * Opens an editor window for the specified ScriptMetaData.
+ * If an editor window is already open for that data it will be
+ * moved to the front.
+ *
+ * @param context The context in which to execute the script
+ * @param entry The metadata describing the script
+ */
+ public void edit(final XScriptContext context, ScriptMetaData entry) {
+ if (entry != null) {
+ try {
+ ClassLoader cl = null;
+
+ try {
+ cl = ClassLoaderFactory.getURLClassLoader(entry);
+ } catch (Exception ignore) { // TODO re-examine error handling
+ }
+
+ final ClassLoader theCl = cl;
+ final URL url = entry.getSourceURL();
+ SwingInvocation.invoke(
+ new Runnable() {
+ public void run() {
+ ScriptEditorForBeanShell editor;
+
+ synchronized (BEING_EDITED) {
+ editor = BEING_EDITED.get(url.toExternalForm());
+
+ if (editor == null) {
+ editor = new ScriptEditorForBeanShell(
+ context, theCl, url);
+ BEING_EDITED.put(url.toExternalForm(), editor);
+ }
+ }
+
+ editor.frame.toFront();
+ }
+ });
+ } catch (IOException ioe) {
+ showErrorMessage("Error loading file: " + ioe.getMessage());
+ }
+ }
+ }
+
+ private ScriptEditorForBeanShell() {
+ }
+
+ private ScriptEditorForBeanShell(XScriptContext context, ClassLoader cl,
+ URL url) {
+ setContext(context);
+ this.scriptURL = url;
+ this.model = new ScriptSourceModel(url);
+ this.filename = ScriptMetaData.getFileName(url);
+ this.cl = cl;
+
+ try {
+
+ Class<?> c =
+ Class.forName("org.openoffice.netbeans.editor.NetBeansSourceView");
+
+ Class<?>[] types = new Class[] { ScriptSourceModel.class };
+
+ java.lang.reflect.Constructor<?> ctor = c.getConstructor(types);
+
+ if (ctor != null) {
+ Object[] args = new Object[] { this.model };
+ this.view = (ScriptSourceView) ctor.newInstance(args);
+ } else {
+ this.view = new PlainSourceView(model);
+ }
+ } catch (java.lang.Error err) {
+ this.view = new PlainSourceView(model);
+ } catch (Exception e) {
+ this.view = new PlainSourceView(model);
+ }
+
+ this.model.setView(this.view);
+ initUI();
+ this.view.addListener(new UnsavedChangesListener() {
+ @Override
+ public void onUnsavedChanges(boolean isUnsaved) {
+ if(filename != null) {
+ // enable or disable save button depending on unsaved changes
+ saveBtn.setEnabled(isUnsaved);
+ }
+ }
+ });
+ frame.setVisible(true);
+ }
+
+ private void initUI() {
+ frame = new JFrame("BeanShell Debug Window: " + filename);
+ frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+
+ frame.addWindowListener(
+ new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ doClose();
+ }
+ }
+ );
+
+ String[] labels = {"Run", "Clear", "Save","Undo","Redo"};
+ JToolBar toolbar = new JToolBar();
+ toolbar.setRollover(true);
+ for (String label : labels) {
+ JButton b = new JButton(label);
+ b.setToolTipText(label);
+ b.addActionListener(this);
+ toolbar.add(b);
+ toolbar.addSeparator();
+
+ // disable save button on start
+ if (label.equals("Save")) {
+ b.setEnabled(false);
+ saveBtn = b;
+ }
+ }
+
+ frame.getContentPane().add((JComponent)view, BorderLayout.CENTER);
+ frame.add(toolbar, BorderLayout.NORTH);
+ frame.pack();
+ frame.setSize(590, 480);
+ frame.setLocation(300, 200);
+ frame.setMinimumSize(new Dimension(500, 300));
+ }
+
+ private void doClose() {
+ if (view.isModified()) {
+
+ int result = JOptionPane.showConfirmDialog(frame,
+ "The script has been modified. Do you want to save the changes?");
+
+ if (result == JOptionPane.CANCEL_OPTION) {
+ // don't close the window, just return
+ return;
+ } else if (result == JOptionPane.YES_OPTION) {
+ boolean saveSuccess = saveTextArea();
+
+ if (!saveSuccess) {
+ return;
+ }
+ }
+ }
+
+ frame.dispose();
+ shutdown();
+ }
+
+ private boolean saveTextArea() {
+ boolean result = true;
+
+ if (!view.isModified()) {
+ return true;
+ }
+
+ OutputStream fos = null;
+
+ try {
+ String s = view.getText();
+ fos = scriptURL.openConnection().getOutputStream();
+
+ if (fos != null) {
+ fos.write(s.getBytes());
+ } else {
+ showErrorMessage(
+ "Error saving script: Could not open stream for file");
+ result = false;
+ }
+
+ view.setModified(false);
+ } catch (IOException ioe) {
+ showErrorMessage("Error saving script: " + ioe.getMessage());
+ result = false;
+ } catch (Exception e) {
+ showErrorMessage("Error saving script: " + e.getMessage());
+ result = false;
+ } finally {
+ if (fos != null) {
+ try {
+ fos.flush();
+ } catch (IOException ignore) {
+ }
+ try {
+ fos.close();
+ } catch (IOException ignore) {
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private void shutdown() {
+ synchronized (BEING_EDITED) {
+ BEING_EDITED.remove(scriptURL.toExternalForm());
+ }
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ String actionCommand = e.getActionCommand();
+ if (actionCommand.equals("Run")) {
+ try {
+ execute();
+ } catch (Exception invokeException) {
+ showErrorMessage(invokeException.toString());
+ }
+ } else if (actionCommand.equals("Save")) {
+ saveTextArea();
+ } else if (actionCommand.equals("Clear")) {
+ view.clear();
+ } else if(actionCommand.equals("Undo")){
+ view.undo();
+ } else if(actionCommand.equals("Redo")){
+ view.redo();
+ }
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptProviderForBeanShell.java b/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptProviderForBeanShell.java
new file mode 100644
index 000000000..2aabba712
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptProviderForBeanShell.java
@@ -0,0 +1,367 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.provider.beanshell;
+
+import bsh.Interpreter;
+
+import com.sun.star.comp.loader.FactoryHelper;
+
+import com.sun.star.document.XScriptInvocationContext;
+
+import com.sun.star.frame.XModel;
+
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+
+import com.sun.star.reflection.InvocationTargetException;
+
+import com.sun.star.registry.XRegistryKey;
+
+import com.sun.star.script.framework.container.ScriptMetaData;
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.ClassLoaderFactory;
+import com.sun.star.script.framework.provider.ScriptContext;
+import com.sun.star.script.framework.provider.ScriptEditor;
+import com.sun.star.script.framework.provider.ScriptProvider;
+import com.sun.star.script.provider.ScriptErrorRaisedException;
+import com.sun.star.script.provider.ScriptExceptionRaisedException;
+import com.sun.star.script.provider.ScriptFrameworkErrorException;
+import com.sun.star.script.provider.ScriptFrameworkErrorType;
+import com.sun.star.script.provider.XScript;
+
+import com.sun.star.uno.Any;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.XComponentContext;
+
+import java.net.URL;
+
+import java.util.StringTokenizer;
+
+public class ScriptProviderForBeanShell {
+
+ public static class ScriptProviderForBeanShell_2 extends ScriptProvider {
+
+ public ScriptProviderForBeanShell_2(XComponentContext ctx) {
+ super(ctx, "BeanShell");
+ }
+
+ @Override
+ public XScript getScript(/*IN*/String scriptURI) throws
+ com.sun.star.uno.RuntimeException, ScriptFrameworkErrorException {
+
+ ScriptMetaData scriptData = getScriptData(scriptURI);
+
+ try {
+
+ ScriptImpl script =
+ new ScriptImpl(m_xContext, scriptData, m_xModel, m_xInvocContext);
+
+ return script;
+ } catch (com.sun.star.uno.RuntimeException re) {
+ throw new ScriptFrameworkErrorException(
+ "Failed to create script object: " + re.getMessage(),
+ null, scriptData.getLanguageName(), language,
+ ScriptFrameworkErrorType.UNKNOWN);
+ }
+ }
+
+ @Override
+ public boolean hasScriptEditor() {
+ return true;
+ }
+
+ @Override
+ public ScriptEditor getScriptEditor() {
+ return ScriptEditorForBeanShell.getEditor();
+ }
+ }
+
+ /**
+ * Returns a factory for creating the service.
+ * This method is called by the <code>JavaLoader</code>
+ * <p>
+ *
+ * @param implName the name of the implementation for which a service is desired
+ * @param multiFactory the service manager to be used if needed
+ * @param regKey the registryKey
+ * @return returns a <code>XSingleServiceFactory</code> for creating
+ * the component
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(
+ String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey) {
+
+ XSingleServiceFactory xSingleServiceFactory = null;
+
+ if (implName.equals(
+ ScriptProviderForBeanShell.ScriptProviderForBeanShell_2.class.getName())) {
+
+ xSingleServiceFactory =
+ FactoryHelper.getServiceFactory(
+ ScriptProviderForBeanShell.ScriptProviderForBeanShell_2.class,
+ "com.sun.star.script.provider.ScriptProviderForBeanShell",
+ multiFactory, regKey);
+
+ }
+
+ return xSingleServiceFactory;
+ }
+}
+
+class ScriptImpl implements XScript {
+
+ private final ScriptMetaData metaData;
+ private final XComponentContext m_xContext;
+ private XMultiComponentFactory m_xMultiComponentFactory;
+ private final XModel m_xModel;
+ private final XScriptInvocationContext m_xInvocContext;
+
+ ScriptImpl(XComponentContext ctx, ScriptMetaData metaData, XModel xModel,
+ XScriptInvocationContext xContext) throws
+ com.sun.star.uno.RuntimeException {
+
+ this.metaData = metaData;
+ this.m_xContext = ctx;
+ this.m_xModel = xModel;
+ this.m_xInvocContext = xContext;
+
+ try {
+ this.m_xMultiComponentFactory = m_xContext.getServiceManager();
+ } catch (Exception e) {
+ throw new com.sun.star.uno.RuntimeException(e);
+ }
+
+ LogUtils.DEBUG("ScriptImpl [beanshell] script data = " + metaData);
+ }
+
+ /**
+ * documentStorageID and document reference
+ * for use in script name resolving
+ *
+ * @param aParams All parameters; pure, out params are
+ * undefined in sequence, i.e., the value
+ * has to be ignored by the callee
+ *
+ * @param aOutParamIndex Out indices
+ *
+ * @param aOutParam Out parameters
+ *
+ * @return The value returned from the function
+ * being invoked
+ *
+ * @throws IllegalArgumentException If there is no matching script name
+ *
+ * @throws InvocationTargetException If the running script throws
+ * an exception this information
+ * is captured and rethrown as
+ * this exception type.
+ */
+
+ public Object invoke(/*IN*/Object[] aParams,
+ /*OUT*/short[][] aOutParamIndex,
+ /*OUT*/Object[][] aOutParam) throws
+ ScriptFrameworkErrorException, InvocationTargetException {
+
+ // Initialise the out parameters - not used at the moment
+ aOutParamIndex[0] = new short[0];
+ aOutParam[0] = new Object[0];
+
+ ClassLoader cl = null;
+ URL sourceUrl = null;
+
+ try {
+ cl = ClassLoaderFactory.getURLClassLoader(metaData);
+ sourceUrl = metaData.getSourceURL();
+ } catch (java.net.MalformedURLException mfu) {
+ // Framework error
+ throw new ScriptFrameworkErrorException(
+ mfu.getMessage(), null,
+ metaData.getLanguageName(), metaData.getLanguage(),
+ ScriptFrameworkErrorType.MALFORMED_URL);
+ }
+
+ // Set class loader to be used for class files
+ // and jar files
+ Thread.currentThread().setContextClassLoader(cl);
+ Interpreter interpreter = new Interpreter();
+
+ interpreter.getNameSpace().clear();
+ // Set class loader to be used by interpreter
+ // to look for classes by source e.g. interpreter
+ // will use this classloader to search classpath
+ // for source file ( bla.java ) on import or reference
+ interpreter.setClassLoader(cl);
+
+ try {
+
+ interpreter.set("XSCRIPTCONTEXT",
+ ScriptContext.createContext(m_xModel, m_xInvocContext,
+ m_xContext, m_xMultiComponentFactory));
+
+ interpreter.set("ARGUMENTS", aParams);
+ } catch (bsh.EvalError e) {
+ // Framework error setting up context
+ throw new ScriptFrameworkErrorException(
+ e.getMessage(), null,
+ metaData.getLanguageName(), metaData.getLanguage(),
+ ScriptFrameworkErrorType.UNKNOWN);
+ }
+
+ try {
+ Object result;
+
+ ScriptEditorForBeanShell editor =
+ ScriptEditorForBeanShell.getEditor(sourceUrl);
+
+ if (editor != null) {
+ result = editor.execute();
+
+ if (result == null) {
+ return new Any(new Type(), null);
+ }
+
+ return result;
+ }
+
+ metaData.loadSource();
+ String source = metaData.getSource();
+
+ if (source == null || source.length() == 0) {
+ throw new ScriptFrameworkErrorException(
+ "Failed to read script", null,
+ metaData.getLanguageName(), metaData.getLanguage(),
+ ScriptFrameworkErrorType.NO_SUCH_SCRIPT);
+ }
+
+ result = interpreter.eval(source);
+
+ if (result == null) {
+ return new Any(new Type(), null);
+ }
+
+ return result;
+ } catch (bsh.ParseException pe) {
+ throw new InvocationTargetException(
+ "Beanshell failed to parse " + metaData.getLanguageName(),
+ null, processBshException(pe, metaData.getLanguageName()));
+ } catch (bsh.TargetError te) {
+ throw new InvocationTargetException(
+ "Beanshell uncaught exception for " + metaData.getLanguageName(),
+ null, processBshException(te, metaData.getLanguageName()));
+ } catch (bsh.EvalError ex) {
+ throw new InvocationTargetException(
+ "Beanshell error for " + metaData.getLanguageName(),
+ null, processBshException(ex, metaData.getLanguageName()));
+ } catch (Exception e) {
+ throw new ScriptFrameworkErrorException(
+ "Failed to read script", null, metaData.getLanguageName(),
+ metaData.getLanguage(), ScriptFrameworkErrorType.UNKNOWN);
+ }
+ }
+ private void raiseEditor(int lineNum) {
+ try {
+ URL sourceUrl = metaData.getSourceURL();
+
+ ScriptEditorForBeanShell editor =
+ ScriptEditorForBeanShell.getEditor(sourceUrl);
+
+ if (editor == null) {
+ editor = ScriptEditorForBeanShell.getEditor();
+
+ editor.edit(
+ ScriptContext.createContext(m_xModel, m_xInvocContext, m_xContext,
+ m_xMultiComponentFactory), metaData);
+
+ editor = ScriptEditorForBeanShell.getEditor(sourceUrl);
+ }
+
+ if (editor != null) {
+ editor.indicateErrorLine(lineNum);
+ }
+ } catch (java.net.MalformedURLException ignore) {
+ }
+ }
+
+ private ScriptErrorRaisedException processBshException(
+ bsh.EvalError e, String script) {
+
+ LogUtils.DEBUG("Beanshell error RAW message " + e.getMessage());
+ String message = e.getMessage();
+ int usefulInfoIndex = message.lastIndexOf("\' :");
+ int lineNum = e.getErrorLineNumber();
+
+ raiseEditor(lineNum);
+
+ if (usefulInfoIndex > -1) {
+ message = message.substring(usefulInfoIndex + 2);
+ }
+
+ if (e instanceof bsh.TargetError) {
+ LogUtils.DEBUG("got instance of TargetError");
+
+ if (usefulInfoIndex == -1) {
+ message = ((bsh.TargetError)e).getTarget().getMessage();
+ }
+
+ String wrappedException = "";
+ String full = e.toString();
+ int index = full.indexOf("Target exception:");
+
+ if (index > -1) {
+ String toParse = full.substring(index);
+ LogUtils.DEBUG("About to parse " + toParse);
+
+ StringTokenizer tokenizer =
+ new StringTokenizer(full.substring(index), ":");
+
+ if (tokenizer.countTokens() > 2) {
+ LogUtils.DEBUG("First token = " + tokenizer.nextToken());
+ wrappedException = tokenizer.nextToken();
+ LogUtils.DEBUG("wrapped exception = = " + wrappedException);
+ }
+ }
+
+ ScriptExceptionRaisedException se =
+ new ScriptExceptionRaisedException(message);
+
+ se.lineNum = lineNum;
+ se.scriptName = script;
+ se.exceptionType = wrappedException;
+ se.language = "BeanShell";
+
+ LogUtils.DEBUG("UnCaught Exception error: ");
+ LogUtils.DEBUG("\tscript: " + script);
+ LogUtils.DEBUG("\tline: " + lineNum);
+ LogUtils.DEBUG("\twrapped exception: " + wrappedException);
+ LogUtils.DEBUG("\tmessage: " + message);
+
+ return se;
+
+ } else {
+ LogUtils.DEBUG("Error or ParseError Exception error: ");
+ LogUtils.DEBUG("\tscript: " + script);
+ LogUtils.DEBUG("\tline: " + lineNum);
+ LogUtils.DEBUG("\tmessage: " + message);
+
+ return new ScriptErrorRaisedException(message, null, script,
+ "BeanShell", lineNum);
+
+ }
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptSourceModel.java b/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptSourceModel.java
new file mode 100644
index 000000000..165f00844
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptSourceModel.java
@@ -0,0 +1,125 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.provider.beanshell;
+
+import com.sun.star.script.provider.XScriptContext;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.net.URL;
+
+public class ScriptSourceModel {
+
+ private int currentPosition = -1;
+ private final URL file;
+ private ScriptSourceView view = null;
+
+ public ScriptSourceModel(URL file) {
+ this.file = file;
+ }
+
+ private String load() throws IOException {
+ StringBuilder buf = new StringBuilder();
+ InputStream in = file.openStream();
+
+ byte[] contents = new byte[1024];
+ int len;
+
+ while ((len = in.read(contents, 0, 1024)) != -1) {
+ buf.append(new String(contents, 0, len));
+ }
+
+ try {
+ in.close();
+ } catch (IOException ignore) {
+ }
+
+ return buf.toString();
+ }
+
+ public String getText() {
+ String result = "";
+
+ try {
+ result = load();
+ } catch (IOException ioe) {
+ // do nothing, empty string will be returned
+ }
+
+ return result;
+ }
+
+ public int getCurrentPosition() {
+ return this.currentPosition;
+ }
+
+ public void setView(ScriptSourceView view) {
+ this.view = view;
+ }
+
+ public Object execute(final XScriptContext context, ClassLoader cl)
+ throws Exception {
+ if (cl != null) {
+ // sets this threads class loader
+ // hopefully any threads spawned by this
+ // will inherit this cl
+ // this enables any class files imported
+ // from the interpreter to be loaded
+ // note: setting the classloader on the
+ // interpreter has a slightly different
+ // meaning in that the classloader for
+ // the interpreter seems only to look for
+ // source files ( bla.java ) in the classpath
+ Thread.currentThread().setContextClassLoader(cl);
+ }
+
+ bsh.Interpreter interpreter = new bsh.Interpreter();
+
+ if (cl != null) {
+ // additionally set class loader on the interpreter
+ // to allow it to load java classes defined in source
+ // files e.g. bla.java
+ interpreter.getNameSpace().clear();
+ }
+
+
+ // reset position
+ currentPosition = -1;
+ view.update();
+
+ interpreter.set("XSCRIPTCONTEXT", context);
+ interpreter.set("ARGUMENTS", new Object[0]);
+
+ Object result;
+
+ if (view.isModified()) {
+ result = interpreter.eval(view.getText());
+ } else {
+ result = interpreter.eval(getText());
+ }
+
+ return result;
+ }
+
+ public void indicateErrorLine(int lineNum) {
+ System.out.println("Beanshell indicateErrorLine " + lineNum);
+ currentPosition = lineNum - 1;
+ view.update();
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptSourceView.java b/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptSourceView.java
new file mode 100644
index 000000000..e39511c24
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptSourceView.java
@@ -0,0 +1,29 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.provider.beanshell;
+
+public interface ScriptSourceView {
+ void clear();
+ void update();
+ boolean isModified();
+ void setModified(boolean value);
+ String getText();
+ void undo();
+ void redo();
+ void addListener(UnsavedChangesListener toAdd);
+}
diff --git a/scripting/java/com/sun/star/script/framework/provider/beanshell/UnsavedChangesListener.java b/scripting/java/com/sun/star/script/framework/provider/beanshell/UnsavedChangesListener.java
new file mode 100644
index 000000000..8efb2087c
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/beanshell/UnsavedChangesListener.java
@@ -0,0 +1,13 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.sun.star.script.framework.provider.beanshell;
+
+public interface UnsavedChangesListener {
+ void onUnsavedChanges(boolean isModified);
+}
diff --git a/scripting/java/com/sun/star/script/framework/provider/beanshell/template.bsh b/scripting/java/com/sun/star/script/framework/provider/beanshell/template.bsh
new file mode 100644
index 000000000..3bf6d22a3
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/beanshell/template.bsh
@@ -0,0 +1,65 @@
+/*
+ * 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 .
+ */
+/*
+ Import standard OpenOffice.org API classes. For more information on
+ these classes and the OpenOffice.org API, see the OpenOffice.org
+ Developers Guide at:
+
+ https://api.libreoffice.org/
+*/
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.frame.XDesktop;
+import com.sun.star.frame.XModel;
+
+/*
+ Import XScriptContext class. An instance of this class is available
+ to all BeanShell scripts in the global variable "XSCRIPTCONTEXT". This
+ variable can be used to access the document for which this script
+ was invoked.
+
+ Methods available are:
+
+ XSCRIPTCONTEXT.getDocument() returns XModel
+ XSCRIPTCONTEXT.getInvocationContext() returns XScriptInvocationContext or NULL
+ XSCRIPTCONTEXT.getDesktop() returns XDesktop
+ XSCRIPTCONTEXT.getComponentContext() returns XComponentContext
+
+ For more information on using this class see the scripting
+ developer guides at:
+
+ https://api.libreoffice.org/docs/DevelopersGuide/ScriptingFramework/ScriptingFramework.xhtml
+*/
+
+// Hello World in BeanShell
+import com.sun.star.text.XTextDocument;
+import com.sun.star.text.XText;
+import com.sun.star.text.XTextRange;
+
+oDoc = UnoRuntime.queryInterface(XModel.class,XSCRIPTCONTEXT.getInvocationContext());
+if ( oDoc == null )
+ oDoc = XSCRIPTCONTEXT.getDocument();
+
+xTextDoc = (XTextDocument) UnoRuntime.queryInterface(XTextDocument.class,oDoc);
+xText = xTextDoc.getText();
+xTextRange = xText.getEnd();
+xTextRange.setString( "Hello World (in BeanShell)" );
+
+// BeanShell scripts in LibreOffice should always return 0
+return 0;
diff --git a/scripting/java/com/sun/star/script/framework/provider/java/MANIFEST.MF b/scripting/java/com/sun/star/script/framework/provider/java/MANIFEST.MF
new file mode 100644
index 000000000..f2056d0c4
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/java/MANIFEST.MF
@@ -0,0 +1,2 @@
+RegistrationClassName: com.sun.star.script.framework.provider.java.ScriptProviderForJava
+UNO-Type-Path:
diff --git a/scripting/java/com/sun/star/script/framework/provider/java/Resolver.java b/scripting/java/com/sun/star/script/framework/provider/java/Resolver.java
new file mode 100644
index 000000000..8192f4724
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/java/Resolver.java
@@ -0,0 +1,36 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.provider.java;
+
+/**
+ * The Resolver interface is an interface common to all classes which
+ * want to implement an algorithm for obtaining a ScriptProxy object
+ * for a particular ScriptDescriptor and Class
+ */
+public interface Resolver {
+
+ /**
+ * Returns a ScriptProxy object for the given ScriptDescriptor and Class
+ *
+ * @param sd A script Descriptor
+ * @param c A Class
+ * @return The ScriptProxy value
+ */
+ ScriptProxy getProxy(ScriptDescriptor sd, Class<?> c) throws
+ NoSuchMethodException;
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/provider/java/ScriptDescriptor.java b/scripting/java/com/sun/star/script/framework/provider/java/ScriptDescriptor.java
new file mode 100644
index 000000000..ff56564b2
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/java/ScriptDescriptor.java
@@ -0,0 +1,165 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.provider.java;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * The <code>ScriptDescriptor</code> object is used to store the search
+ * criteria that should be used for finding a particular script
+ */
+public class ScriptDescriptor {
+
+ private final String m_name;
+ private final String m_methodName;
+ private final String m_className;
+ private List<String> m_classpath;
+ private final ArrayList<Class<?>> m_argumentTypes = new ArrayList<Class<?>>(11);
+
+ /**
+ * Constructs a ScriptDescriptor for the given name
+ *
+ * @param name Script Name
+ * @exception IllegalArgumentException if the given name does not contain a "."
+ */
+ public ScriptDescriptor(String name) throws IllegalArgumentException {
+ int idx = name.lastIndexOf('.');
+
+ if (idx == -1) {
+ throw new IllegalArgumentException("Invalid method name");
+ }
+
+ this.m_name = name;
+ this.m_methodName = name.substring(idx + 1);
+ this.m_className = name.substring(0, idx);
+ }
+
+ /**
+ * Gets the fully qualified name of this <code>ScriptDescriptor</code>
+ *
+ * @return The Script Name value
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * Gets the fully qualified name of this <code>ScriptDescriptor</code>
+ *
+ * @return The Script Name value
+ */
+ public String getClassName() {
+ return m_className;
+ }
+
+ /**
+ * Gets the method name of this <code>ScriptDescriptor</code>
+ *
+ * @return The methodName value
+ */
+ public String getMethodName() {
+ return m_methodName;
+ }
+
+ /**
+ * Sets the classpath value stored by this <code>ScriptDescriptor</code>
+ *
+ * @param classpath The new classpath value
+ */
+ public void setClasspath(String classpath) {
+ StringTokenizer stk = new StringTokenizer(classpath, ":");
+
+ while (stk.hasMoreTokens()) {
+ this.m_classpath.add(stk.nextToken());
+ }
+ }
+
+ /**
+ * Sets the classpath value stored by this <code>ScriptDescriptor</code>
+ *
+ * @param classpath The new classpath value
+ */
+ public void setClasspath(List<String> classpath) {
+ this.m_classpath = classpath;
+ }
+
+ /**
+ * Gets the classpath value stored by this <code>ScriptDescriptor</code>
+ *
+ * @return The classpath value
+ */
+ public List<String> getClasspath() {
+ return m_classpath;
+ }
+
+ /**
+ * Adds the given <code>Class</code> to the list of argument types stored in
+ * this ScriptDescriptor
+ *
+ * @param clazz The feature to be added to the ArgumentType attribute
+ */
+
+ public synchronized void addArgumentType(Class<?> clazz) {
+ m_argumentTypes.add(clazz);
+ }
+
+ /**
+ * Gets a list of the types of the arguments stored in this
+ * <code>ScriptDescriptor</code>
+ *
+ * return the argument types as an array of Class
+ *
+ * @return The argumentTypes value
+ */
+
+ public synchronized Class<?>[] getArgumentTypes() {
+ if (m_argumentTypes.size() > 0)
+ return m_argumentTypes.toArray(new Class[ m_argumentTypes.size() ]);
+ else
+ return null;
+ }
+
+ /**
+ * Returns a <code>String</code> representation of this
+ * <code>ScriptDescriptor</code>
+ *
+ * @return The scriptName including the parameters.
+ */
+ @Override
+ public String toString() {
+ StringBuilder description = new StringBuilder(m_name);
+ Class<?>[] types = getArgumentTypes();
+
+ description.append(" (");
+
+ if (types != null) {
+ for (int i = 0; i < types.length - 1; i++) {
+ description.append(types[ i ].getName());
+ description.append(", ");
+ }
+
+ description.append(types[ types.length - 1 ].getName());
+ }
+
+ description.append(")");
+
+ return description.toString();
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/provider/java/ScriptProviderForJava.java b/scripting/java/com/sun/star/script/framework/provider/java/ScriptProviderForJava.java
new file mode 100644
index 000000000..eeea0d49e
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/java/ScriptProviderForJava.java
@@ -0,0 +1,307 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.provider.java;
+
+import com.sun.star.comp.loader.FactoryHelper;
+
+import com.sun.star.document.XScriptInvocationContext;
+
+import com.sun.star.frame.XModel;
+
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+
+import com.sun.star.registry.XRegistryKey;
+
+import com.sun.star.script.framework.container.ScriptMetaData;
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.ClassLoaderFactory;
+import com.sun.star.script.framework.provider.ScriptContext;
+import com.sun.star.script.framework.provider.ScriptEditor;
+import com.sun.star.script.framework.provider.ScriptProvider;
+import com.sun.star.script.provider.ScriptExceptionRaisedException;
+import com.sun.star.script.provider.ScriptFrameworkErrorException;
+import com.sun.star.script.provider.ScriptFrameworkErrorType;
+import com.sun.star.script.provider.XScript;
+import com.sun.star.script.provider.XScriptContext;
+
+import com.sun.star.uno.Any;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.XComponentContext;
+
+import java.util.ArrayList;
+
+public class ScriptProviderForJava {
+
+ public static class _ScriptProviderForJava extends ScriptProvider {
+
+ private final Resolver m_resolutionPolicy = new StrictResolver();
+
+ public _ScriptProviderForJava(XComponentContext ctx) {
+ super(ctx, "Java");
+ }
+
+ @Override
+ public XScript getScript(/*IN*/String scriptURI) throws
+ com.sun.star.uno.RuntimeException, ScriptFrameworkErrorException {
+
+ ScriptMetaData scriptData = getScriptData(scriptURI);
+
+ try {
+
+ ScriptImpl script =
+ new ScriptImpl(m_xContext, m_resolutionPolicy, scriptData, m_xModel,
+ m_xInvocContext);
+
+ return script;
+ } catch (com.sun.star.uno.RuntimeException re) {
+ ScriptFrameworkErrorException e2 = new ScriptFrameworkErrorException(
+ "Failed to create script object: " + re, null,
+ scriptData.getLanguageName(), language,
+ ScriptFrameworkErrorType.UNKNOWN);
+ e2.initCause(re);
+ throw e2;
+ }
+ }
+
+ @Override
+ public boolean hasScriptEditor() {
+ return false;
+ }
+
+ @Override
+ public ScriptEditor getScriptEditor() {
+ return null;
+ }
+ }
+
+ /**
+ * Returns a factory for creating the service.
+ * This method is called by the <code>JavaLoader</code>
+ * <p>
+ *
+ * @param implName the name of the implementation for which a service is desired
+ * @param multiFactory the service manager to be used if needed
+ * @param regKey the registryKey
+ * @return returns a <code>XSingleServiceFactory</code> for creating
+ * the component
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(
+ String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey) {
+
+ XSingleServiceFactory xSingleServiceFactory = null;
+
+ if (implName.equals(
+ ScriptProviderForJava._ScriptProviderForJava.class.getName())) {
+
+ xSingleServiceFactory =
+ FactoryHelper.getServiceFactory(
+ ScriptProviderForJava._ScriptProviderForJava.class,
+ "com.sun.star.script.provider.ScriptProviderForJava",
+ multiFactory, regKey);
+
+ }
+
+ return xSingleServiceFactory;
+ }
+}
+
+class ScriptImpl implements XScript {
+
+ private final ScriptMetaData metaData;
+ private final XComponentContext m_xContext;
+ private final XModel m_xModel;
+ private final XScriptInvocationContext m_xInvocContext;
+ private XMultiComponentFactory m_xMultiComponentFactory;
+ private final Resolver m_resolutionPolicy;
+
+ ScriptImpl(XComponentContext ctx, Resolver resolver, ScriptMetaData metaData,
+ XModel xModel, XScriptInvocationContext xInvocContext) throws
+ com.sun.star.uno.RuntimeException {
+
+ this.metaData = metaData;
+ this.m_xContext = ctx;
+ this.m_xModel = xModel;
+ this.m_xInvocContext = xInvocContext;
+ this.m_resolutionPolicy = resolver;
+
+ try {
+ this.m_xMultiComponentFactory = m_xContext.getServiceManager();
+ } catch (Exception e) {
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ throw new com.sun.star.uno.RuntimeException(
+ e, "Error constructing ScriptProvider: " + e);
+ }
+
+ LogUtils.DEBUG("ScriptImpl [java] script data = " + metaData);
+ }
+
+ /**
+ * Invoke
+ *
+ *
+ * @param params All parameters; pure, out params are undefined in
+ * sequence, i.e., the value has to be ignored by the callee
+ * @param aOutParamIndex Out indices
+ * @param aOutParam Out parameters
+ * @return The value returned from the function being invoked
+ * @throws IllegalArgumentException If there is no matching script name
+ * @throws com.sun.star.reflection.InvocationTargetException If the running script throws an exception
+ * this information is captured and rethrown as this exception type.
+ */
+ public Object invoke(
+ /*IN*/Object[] params,
+ /*OUT*/short[][] aOutParamIndex,
+ /*OUT*/Object[][] aOutParam) throws
+ ScriptFrameworkErrorException,
+ com.sun.star.reflection.InvocationTargetException {
+
+ LogUtils.DEBUG("** ScriptProviderForJava::invoke: Starting...");
+
+ // Initialise the out parameters - not used at the moment
+ aOutParamIndex[0] = new short[0];
+ aOutParam[0] = new Object[0];
+
+ ScriptDescriptor scriptDesc =
+ new ScriptDescriptor(metaData.getLanguageName());
+
+ LogUtils.DEBUG("Classloader starting...");
+
+ ClassLoader scriptLoader =
+ ClassLoaderFactory.getURLClassLoader(metaData);
+
+ LogUtils.DEBUG("Classloader finished...");
+
+ ArrayList<Object> invocationArgList = new ArrayList<Object>();
+ Object[] invocationArgs = null;
+
+ LogUtils.DEBUG("Parameter Mapping...");
+
+ // Setup Context Object
+ XScriptContext xSc =
+ ScriptContext.createContext(m_xModel, m_xInvocContext,
+ m_xContext, m_xMultiComponentFactory);
+
+ scriptDesc.addArgumentType(XScriptContext.class);
+ invocationArgList.add(xSc);
+
+ for (int i = 0; i < params.length; i++) {
+ scriptDesc.addArgumentType(params[ i ].getClass());
+ invocationArgList.add(params[ i ]);
+ }
+
+ if (!invocationArgList.isEmpty()) {
+ invocationArgs = invocationArgList.toArray();
+ }
+
+ LogUtils.DEBUG("ScriptProxy starting... ");
+ ScriptProxy script = null;
+
+ try {
+
+ String className = metaData.getLanguageName().substring(0,
+ metaData.getLanguageName().lastIndexOf('.'));
+
+ LogUtils.DEBUG("About to load Class " + className + " starting... ");
+
+ long start = new java.util.Date().getTime();
+ Class<?> c = scriptLoader.loadClass(className);
+ long end = new java.util.Date().getTime();
+
+ LogUtils.DEBUG("loadClass took: " + (end - start) + "milliseconds");
+
+ try {
+ LogUtils.DEBUG("class loaded ... ");
+ script = m_resolutionPolicy.getProxy(scriptDesc, c);
+ LogUtils.DEBUG("script resolved ... ");
+ } catch (NoSuchMethodException e) {
+ // Framework error
+ ScriptFrameworkErrorException e2 = new ScriptFrameworkErrorException(
+ e.toString(), null, metaData.getLanguageName(),
+ metaData.getLanguage(), ScriptFrameworkErrorType.NO_SUCH_SCRIPT);
+ e2.initCause(e);
+ throw e2;
+ }
+ } catch (ClassNotFoundException e) {
+ // Framework error
+ ScriptFrameworkErrorException e2 = new ScriptFrameworkErrorException(
+ e.toString(), null, metaData.getLanguageName(),
+ metaData.getLanguage(), ScriptFrameworkErrorType.NO_SUCH_SCRIPT);
+ e2.initCause(e);
+ throw e2;
+ }
+
+ LogUtils.DEBUG("Starting Invoke on Proxy ...");
+ Object result = null;
+
+ try {
+ long start = new java.util.Date().getTime();
+ result = script.invoke(invocationArgs);
+ long end = new java.util.Date().getTime();
+ LogUtils.DEBUG("invoke took: " + (end - start) + "milliseconds");
+ } catch (java.lang.IllegalArgumentException iae) {
+ ScriptFrameworkErrorException e2 = new ScriptFrameworkErrorException(
+ iae.getMessage(), null, metaData.getLanguageName(),
+ metaData.getLanguage(), ScriptFrameworkErrorType.UNKNOWN);
+ e2.initCause(iae);
+ throw e2;
+ } catch (java.lang.IllegalAccessException ia) {
+ ScriptFrameworkErrorException e2 = new ScriptFrameworkErrorException(
+ ia.toString(), null, metaData.getLanguageName(),
+ metaData.getLanguage(), ScriptFrameworkErrorType.UNKNOWN);
+ e2.initCause(ia);
+ throw e2;
+ } catch (java.lang.reflect.InvocationTargetException ite) {
+ Throwable targetException = ite.getTargetException();
+
+ ScriptExceptionRaisedException se =
+ new ScriptExceptionRaisedException(targetException.toString());
+
+ se.lineNum = -1;
+ se.scriptName = metaData.getLanguageName();
+ se.language = "Java";
+ se.exceptionType = targetException.getClass().getName();
+
+ throw new com.sun.star.reflection.InvocationTargetException(
+ "Scripting Framework error executing script ", null, se);
+
+ } catch (Exception unknown) {
+ ScriptExceptionRaisedException se =
+ new ScriptExceptionRaisedException(unknown.toString());
+ se.lineNum = -1;
+ se.scriptName = metaData.getLanguageName();
+ se.language = "Java";
+ se.exceptionType = unknown.getClass().getName();
+ throw new com.sun.star.reflection.InvocationTargetException(
+ "Scripting Framework error executing script ", null, se);
+ }
+
+ if (result == null) {
+ LogUtils.DEBUG("Got Nothing Back");
+ // in the case where there is no return type
+ Any voidAny = new Any(new Type(), null);
+ result = voidAny;
+ } else {
+ LogUtils.DEBUG("Got object " + result);
+ }
+
+ return result;
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/provider/java/ScriptProxy.java b/scripting/java/com/sun/star/script/framework/provider/java/ScriptProxy.java
new file mode 100644
index 000000000..921b282cc
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/java/ScriptProxy.java
@@ -0,0 +1,69 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.provider.java;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * A ScriptProxy object acts as a proxy for a Java <code>Method</code>
+ *
+ * @see java.lang.reflect.Method
+ */
+public class ScriptProxy {
+
+ private Object m_targetObject;
+ private final Method m_method;
+
+ /**
+ * Constructs a <code>ScriptProxy</code> object for the given
+ * <code>Method</code>
+ *
+ * @param method Description of the Parameter
+ */
+ public ScriptProxy(Method method) {
+ this.m_method = method;
+ }
+
+ /**
+ * Sets the <code>Object</code> on which the ScriptProxy should invoke
+ * the method
+ *
+ * @param obj The new targetObject value
+ */
+ public void setTargetObject(Object obj) {
+ m_targetObject = obj;
+ }
+
+ /**
+ * Invokes the method contained in this <code>ScriptProxy</code>,
+ * any exceptions resulting from the invocation will be thrown
+ *
+ * @param args the arguments to be passed when invoking
+ * the method
+ * @return the Object returned from the method
+ * invocation, may be null
+ * @see java.lang.reflect.Method for the exceptions
+ * that may be thrown
+ */
+ public Object invoke(Object[] args) throws
+ IllegalAccessException, InvocationTargetException, IllegalArgumentException {
+
+ return m_method.invoke(m_targetObject, args);
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/provider/java/StrictResolver.java b/scripting/java/com/sun/star/script/framework/provider/java/StrictResolver.java
new file mode 100644
index 000000000..08d06dce3
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/java/StrictResolver.java
@@ -0,0 +1,113 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.provider.java;
+
+import com.sun.star.script.framework.log.LogUtils;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+/**
+ * A StrictResolver can be used to get a ScriptProxy object for a given
+ * ScriptDescriptor and Class. The StrictResolver is an implementation of
+ * the Resolver strategy. It will only return a ScriptProxy object if a
+ * method accepting all of the arguments specified in the ScriptDescriptor
+ * can be found in the Class.
+ */
+public class StrictResolver implements Resolver {
+
+ /**
+ *Constructor for the StrictResolver object
+ */
+ public StrictResolver() {
+ LogUtils.DEBUG(this.getClass().getName() + " created");
+ }
+
+ /**
+ * Returns a ScriptProxy object for the given ScriptDescriptor and Class.
+ * Only a strict match will be returned ie. where all of the arguments in
+ * the given ScriptDescriptor match the types of the
+ *
+ * @param sd the ScriptDescriptor for which a ScriptProxy is required
+ * @param c the Class file in which to search for the method
+ * @return the ScriptProxy matching the criteria, or null if no match is found
+ */
+ public ScriptProxy getProxy(ScriptDescriptor sd, Class<?> c) throws
+ NoSuchMethodException {
+
+ Method m = null;
+
+ LogUtils.DEBUG("StrictResolver.getProxy() for: " + sd.toString());
+
+ try {
+ m = resolveArguments(sd, c);
+ } catch (ClassNotFoundException ex1) {
+ NoSuchMethodException ex2 = new NoSuchMethodException(
+ "StrictResolver.getProxy: Can't find method: " + sd.getMethodName());
+ ex2.initCause(ex1);
+ throw ex2;
+ } catch (NoSuchMethodException ex1) {
+ NoSuchMethodException ex2 = new NoSuchMethodException(
+ "StrictResolver.getProxy: Can't find method: " + sd.getMethodName());
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+
+ ScriptProxy sp = new ScriptProxy(m);
+
+ int modifiers = m.getModifiers();
+
+ if (!Modifier.isStatic(modifiers)) {
+ Object o;
+
+ try {
+ o = c.newInstance();
+ } catch (InstantiationException ex1) {
+ NoSuchMethodException ex2 = new NoSuchMethodException(
+ "getScriptProxy: Can't instantiate: " + c.getName());
+ ex2.initCause(ex1);
+ throw ex2;
+ } catch (IllegalAccessException ex1) {
+ NoSuchMethodException ex2 = new NoSuchMethodException(
+ "getScriptProxy: Can't access: " + c.getName());
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+
+ sp.setTargetObject(o);
+ }
+
+ return sp;
+ }
+
+ /**
+ * Description of the Method
+ *
+ * @param sd Description of the Parameter
+ * @param c Description of the Parameter
+ * @return Description of the Return Value
+ * @exception ClassNotFoundException
+ * @exception NoSuchMethodException
+ */
+ private Method resolveArguments(ScriptDescriptor sd, Class<?> c) throws
+ ClassNotFoundException, NoSuchMethodException {
+
+ return c.getMethod(sd.getMethodName(), sd.getArgumentTypes());
+ }
+} \ No newline at end of file
diff --git a/scripting/java/com/sun/star/script/framework/provider/javascript/MANIFEST.MF b/scripting/java/com/sun/star/script/framework/provider/javascript/MANIFEST.MF
new file mode 100644
index 000000000..fe2f543c0
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/javascript/MANIFEST.MF
@@ -0,0 +1,2 @@
+RegistrationClassName: com.sun.star.script.framework.provider.javascript.ScriptProviderForJavaScript
+UNO-Type-Path:
diff --git a/scripting/java/com/sun/star/script/framework/provider/javascript/ScriptEditorForJavaScript.java b/scripting/java/com/sun/star/script/framework/provider/javascript/ScriptEditorForJavaScript.java
new file mode 100644
index 000000000..1f0e8fd72
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/javascript/ScriptEditorForJavaScript.java
@@ -0,0 +1,319 @@
+/*
+ * 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 .
+ */
+
+package com.sun.star.script.framework.provider.javascript;
+
+import com.sun.star.script.framework.container.ScriptMetaData;
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.ScriptEditorBase;
+import com.sun.star.script.framework.provider.SwingInvocation;
+import com.sun.star.script.provider.XScriptContext;
+
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.ImporterTopLevel;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.tools.debugger.Main;
+import org.mozilla.javascript.tools.debugger.ScopeProvider;
+
+public class ScriptEditorForJavaScript extends ScriptEditorBase {
+
+ // global ScriptEditorForJavaScript instance
+ private static ScriptEditorForJavaScript theScriptEditorForJavaScript;
+
+ // template for JavaScript scripts
+ private static String JSTEMPLATE;
+
+ private static Main rhinoWindow;
+ private URL scriptURL;
+ // global list of ScriptEditors, key is [external form of URL] of file being edited
+ private static Map<String, ScriptEditorForJavaScript> BEING_EDITED = new
+ HashMap<String, ScriptEditorForJavaScript>();
+
+ static {
+ JSTEMPLATE = "// JavaScript script";
+ try {
+ URL url = ScriptEditorForJavaScript.class.getResource("template.js");
+ if (url != null) {
+ InputStream in = url.openStream();
+ StringBuilder buf = new StringBuilder();
+ byte[] b = new byte[1024];
+ int len;
+
+ while ((len = in.read(b)) != -1) {
+ buf.append(new String(b, 0, len));
+ }
+
+ in.close();
+
+ JSTEMPLATE = buf.toString();
+ }
+ } catch (IOException ioe) {
+ } catch (Exception e) {
+ }
+ }
+
+ /**
+ * Returns the global ScriptEditorForJavaScript instance.
+ */
+
+ public static synchronized ScriptEditorForJavaScript getEditor() {
+ if (theScriptEditorForJavaScript == null) {
+ theScriptEditorForJavaScript = new ScriptEditorForJavaScript();
+ }
+
+ return theScriptEditorForJavaScript;
+ }
+
+ /**
+ * Get the ScriptEditorForJavaScript instance for this URL
+ *
+ * @param url The URL of the script source file
+ *
+ * @return The ScriptEditorForJavaScript associated with
+ * the given URL if one exists, otherwise null.
+ */
+ public static ScriptEditorForJavaScript getEditor(URL url) {
+ synchronized (BEING_EDITED) {
+ return BEING_EDITED.get(url.toExternalForm());
+ }
+ }
+
+ /**
+ * Returns whether or not the script source being edited in this
+ * ScriptEditorForJavaScript has been modified
+ */
+ public boolean isModified() {
+ return rhinoWindow.isModified(scriptURL);
+ }
+
+ /**
+ * Returns the text being displayed in this ScriptEditorForJavaScript
+ *
+ * @return The text displayed in this ScriptEditorForJavaScript
+ */
+ public String getText() {
+ return rhinoWindow.getText(scriptURL);
+ }
+
+ /**
+ * Returns the Rhino Debugger url of this ScriptEditorForJavaScript
+ *
+ * @return The url of this ScriptEditorForJavaScript
+ */
+ public String getURL() {
+ return scriptURL.toString();
+ }
+
+ /**
+ * Returns the template text for JavaScript scripts
+ *
+ * @return The template text for JavaScript scripts
+ */
+ public String getTemplate() {
+ return JSTEMPLATE;
+ }
+
+ /**
+ * Returns the default extension for JavaScript scripts
+ *
+ * @return The default extension for JavaScript scripts
+ */
+ public String getExtension() {
+ return "js";
+ }
+
+ /**
+ * Opens an editor window for the specified ScriptMetaData.
+ * If an editor window is already open for that data it will be
+ * moved to the front.
+ *
+ * @param context The context in which to execute the script
+ * @param entry The metadata describing the script
+ */
+ public void edit(final XScriptContext context, ScriptMetaData entry) {
+ try {
+ String sUrl = entry.getParcelLocation();
+
+ if (!sUrl.endsWith("/")) {
+ sUrl += "/";
+ }
+
+ sUrl += entry.getLanguageName();
+ final URL url = entry.getSourceURL();
+ SwingInvocation.invoke(
+ new Runnable() {
+ public void run() {
+ synchronized (BEING_EDITED) {
+ ScriptEditorForJavaScript editor = BEING_EDITED.get(url.toExternalForm());
+
+ if (editor == null) {
+ editor = new ScriptEditorForJavaScript(context, url);
+ BEING_EDITED.put(url.toExternalForm(), editor);
+ }
+ }
+
+ assert rhinoWindow != null;
+ rhinoWindow.showScriptWindow(url);
+ rhinoWindow.toFront();
+ }
+ });
+ } catch (IOException e) {
+ LogUtils.DEBUG("Caught exception: " + e);
+ LogUtils.DEBUG(LogUtils.getTrace(e));
+ }
+ }
+
+ // Ensures that new instances of this class can only be created using
+ // the factory methods
+ private ScriptEditorForJavaScript() {
+ }
+
+ private ScriptEditorForJavaScript(XScriptContext context, URL url) {
+ setContext(context);
+ // Need to check that before showing the window. Checking in execute() has no effect.
+ if (!isMacroExecutionEnabled()) {
+ showErrorMessage("Macro Execution has been disabled.");
+ return ;
+ }
+ initUI();
+ Scriptable scope = getScope(context);
+ rhinoWindow.openFile(url, scope, new CloseHandler(url));
+ this.scriptURL = url;
+ }
+
+ /**
+ * Executes the script edited by the editor
+ *
+ */
+
+ public Object execute() throws Exception {
+ rhinoWindow.toFront();
+
+ return rhinoWindow.runScriptWindow(scriptURL);
+ }
+
+ /**
+ * Indicates the line where error occurred
+ *
+ */
+ public void indicateErrorLine(int lineNum) {
+ rhinoWindow.toFront();
+ rhinoWindow.highlighLineInScriptWindow(scriptURL, lineNum);
+ }
+ // This code is based on the main method of the Rhino Debugger Main class
+ // We pass in the XScriptContext in the global scope for script execution
+ private void initUI() {
+ try {
+ synchronized (ScriptEditorForJavaScript.class) {
+ if (rhinoWindow != null) {
+ return;
+ }
+
+ final Main sdb = new Main("Rhino JavaScript Debugger");
+ sdb.pack();
+ sdb.setSize(640, 640);
+ sdb.setVisible(true);
+ sdb.setExitAction(new Runnable() {
+ public void run() {
+ sdb.clearAllBreakpoints();
+ sdb.dispose();
+ shutdown();
+ }
+ });
+ Context.addContextListener(sdb);
+ sdb.setScopeProvider(new ScopeProvider() {
+ @Override
+ public Scriptable getScope() {
+ return org.mozilla.javascript.tools.shell.Main.getScope();
+ }
+ });
+ sdb.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ shutdown();
+ }
+ });
+ rhinoWindow = sdb;
+ }
+ } catch (Exception exc) {
+ LogUtils.DEBUG(LogUtils.getTrace(exc));
+ }
+ }
+
+ private void shutdown() {
+ // dereference Rhino Debugger window
+ rhinoWindow = null;
+ this.scriptURL = null;
+
+ // remove all scripts from BEING_EDITED
+ synchronized (BEING_EDITED) {
+ java.util.Iterator<String> iter = BEING_EDITED.keySet().iterator();
+ java.util.ArrayList<String> keysToRemove = new java.util.ArrayList<String>();
+
+ while (iter.hasNext()) {
+ String key = iter.next();
+ keysToRemove.add(key);
+ }
+
+ for (int i = 0; i < keysToRemove.size(); i++) {
+ BEING_EDITED.remove(keysToRemove.get(i));
+ }
+
+ keysToRemove = null;
+ }
+
+ }
+ private Scriptable getScope(XScriptContext xsctxt) {
+ Context ctxt = Context.enter();
+ ImporterTopLevel scope = new ImporterTopLevel(ctxt);
+
+ Scriptable jsCtxt = Context.toObject(xsctxt, scope);
+ scope.put("XSCRIPTCONTEXT", scope, jsCtxt);
+
+ Scriptable jsArgs = Context.toObject(new Object[0], scope);
+ scope.put("ARGUMENTS", scope, jsArgs);
+
+ Context.exit();
+ return scope;
+ }
+
+ private static class CloseHandler implements Runnable {
+
+ private final URL url;
+
+ private CloseHandler(URL url) {
+ this.url = url;
+ }
+
+ public void run() {
+ synchronized (BEING_EDITED) {
+ BEING_EDITED.remove(this.url.toExternalForm());
+ }
+ }
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/provider/javascript/ScriptProviderForJavaScript.java b/scripting/java/com/sun/star/script/framework/provider/javascript/ScriptProviderForJavaScript.java
new file mode 100644
index 000000000..9465a646f
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/javascript/ScriptProviderForJavaScript.java
@@ -0,0 +1,330 @@
+/*
+ * 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 .
+ */
+package com.sun.star.script.framework.provider.javascript;
+
+import com.sun.star.comp.loader.FactoryHelper;
+
+import com.sun.star.document.XScriptInvocationContext;
+
+import com.sun.star.frame.XModel;
+
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+
+import com.sun.star.reflection.InvocationTargetException;
+
+import com.sun.star.registry.XRegistryKey;
+
+import com.sun.star.script.framework.container.ScriptMetaData;
+import com.sun.star.script.framework.log.LogUtils;
+import com.sun.star.script.framework.provider.ClassLoaderFactory;
+import com.sun.star.script.framework.provider.ScriptContext;
+import com.sun.star.script.framework.provider.ScriptEditor;
+import com.sun.star.script.framework.provider.ScriptProvider;
+import com.sun.star.script.provider.ScriptExceptionRaisedException;
+import com.sun.star.script.provider.ScriptFrameworkErrorException;
+import com.sun.star.script.provider.ScriptFrameworkErrorType;
+import com.sun.star.script.provider.XScript;
+
+import com.sun.star.uno.XComponentContext;
+
+import java.net.URL;
+
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.ImporterTopLevel;
+import org.mozilla.javascript.JavaScriptException;
+import org.mozilla.javascript.Scriptable;
+
+public class ScriptProviderForJavaScript {
+
+ public static class ScriptProviderForJavaScript_2 extends ScriptProvider {
+
+ public ScriptProviderForJavaScript_2(XComponentContext ctx) {
+ super(ctx, "JavaScript");
+ }
+
+ @Override
+ public XScript getScript(/*IN*/String scriptURI)
+ throws com.sun.star.uno.RuntimeException, ScriptFrameworkErrorException {
+ ScriptMetaData scriptData = null;
+
+ try {
+ scriptData = getScriptData(scriptURI);
+ ScriptImpl script = new ScriptImpl(m_xContext, scriptData, m_xModel,
+ m_xInvocContext);
+ return script;
+ } catch (com.sun.star.uno.RuntimeException re) {
+ throw new ScriptFrameworkErrorException(
+ "Failed to create script object: " + re.getMessage(),
+ null, scriptData.getLanguageName(), language, ScriptFrameworkErrorType.UNKNOWN);
+ }
+ }
+
+ @Override
+ public boolean hasScriptEditor() {
+ return true;
+ }
+
+ @Override
+ public ScriptEditor getScriptEditor() {
+ return ScriptEditorForJavaScript.getEditor();
+ }
+ }
+
+ /**
+ * Returns a factory for creating the service.
+ * This method is called by the <code>JavaLoader</code>
+ * <p>
+ *
+ * @param implName the name of the implementation for which a service is desired
+ * @param multiFactory the service manager to be used if needed
+ * @param regKey the registryKey
+ * @return returns a <code>XSingleServiceFactory</code> for creating
+ * the component
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(String implName,
+ XMultiServiceFactory multiFactory, XRegistryKey regKey) {
+
+ XSingleServiceFactory xSingleServiceFactory = null;
+
+ if (implName.equals(
+ ScriptProviderForJavaScript.ScriptProviderForJavaScript_2.class.getName())) {
+
+ xSingleServiceFactory =
+ FactoryHelper.getServiceFactory(
+ ScriptProviderForJavaScript.ScriptProviderForJavaScript_2.class,
+ "com.sun.star.script.provider.ScriptProviderForJavaScript",
+ multiFactory, regKey);
+
+ }
+
+ return xSingleServiceFactory;
+ }
+}
+
+class ScriptImpl implements XScript {
+
+ private final ScriptMetaData metaData;
+ private final XComponentContext m_xContext;
+ private XMultiComponentFactory m_xMultiComponentFactory;
+ private final XModel m_xModel;
+ private final XScriptInvocationContext m_xInvocContext;
+
+ ScriptImpl(XComponentContext ctx, ScriptMetaData metaData, XModel xModel,
+ XScriptInvocationContext xInvocContext) throws
+ com.sun.star.uno.RuntimeException {
+
+ this.metaData = metaData;
+ this.m_xContext = ctx;
+ this.m_xModel = xModel;
+ this.m_xInvocContext = xInvocContext;
+
+ try {
+ this.m_xMultiComponentFactory = m_xContext.getServiceManager();
+ } catch (Exception e) {
+ throw new com.sun.star.uno.RuntimeException(e);
+ }
+
+ LogUtils.DEBUG("ScriptImpl [javascript] script data = " + metaData);
+ }
+
+ /**
+ * The invoke method of the ScriptProviderForJavaScript runs the
+ * JavaScript script specified in the URI
+ *
+ *
+ *
+ * @param params All parameters; pure, out params are
+ * undefined in sequence, i.e., the value
+ * has to be ignored by the callee
+ *
+ * @param aOutParamIndex Out indices
+ *
+ * @param aOutParam Out parameters
+ *
+ * @return The value returned from the function
+ * being invoked
+ *
+ * @throws ScriptFrameworkErrorException If there is no matching script name
+ *
+ *
+ * @throws InvocationTargetException If the running script throws
+ * an exception this information
+ * is captured and rethrown as
+ * ScriptErrorRaisedException or
+ * ScriptExceptionRaisedException
+ */
+ public Object invoke(
+ /*IN*/Object[] params,
+ /*OUT*/short[][] aOutParamIndex,
+ /*OUT*/Object[][] aOutParam)
+ throws ScriptFrameworkErrorException, InvocationTargetException {
+
+ // Initialise the out parameters - not used at the moment
+ aOutParamIndex[0] = new short[0];
+ aOutParam[0] = new Object[0];
+
+ ClassLoader cl = null;
+
+ try {
+ cl = ClassLoaderFactory.getURLClassLoader(metaData);
+ metaData.getSourceURL();
+ } catch (java.net.MalformedURLException mfu) {
+ throw new ScriptFrameworkErrorException(
+ mfu.getMessage(), null,
+ metaData.getLanguageName(), metaData.getLanguage(),
+ ScriptFrameworkErrorType.MALFORMED_URL);
+ }
+
+ Context ctxt = null;
+
+ try {
+ Object result = null;
+
+ ScriptEditorForJavaScript editor =
+ ScriptEditorForJavaScript.getEditor(metaData.getSourceURL());
+
+ if (editor != null) {
+ result = editor.execute();
+
+ if (result != null &&
+ result.getClass().getName().equals("org.mozilla.javascript.Undefined")) {
+ // Always return a string
+ // TODO revisit
+ return Context.toString(result);
+ }
+
+ }
+
+ String source;
+
+ if (editor != null && editor.isModified()) {
+ LogUtils.DEBUG("GOT A MODIFIED SOURCE");
+ source = editor.getText();
+ } else {
+ metaData.loadSource();
+ source = metaData.getSource();
+
+ }
+
+ if (source == null || source.length() == 0) {
+ throw new ScriptFrameworkErrorException(
+ "Failed to read source data for script", null,
+ metaData.getLanguageName(), metaData.getLanguage(),
+ ScriptFrameworkErrorType.UNKNOWN);
+ }
+
+ /* Set the context ClassLoader on the current thread to
+ be our custom ClassLoader. This is the suggested method
+ for setting up a ClassLoader to be used by the Rhino
+ interpreter
+ */
+ if (cl != null) {
+ Thread.currentThread().setContextClassLoader(cl);
+ }
+
+ // Initialize a Rhino Context object
+ ctxt = Context.enter();
+
+ /* The ImporterTopLevel ensures that importClass and
+ importPackage statements work in Javascript scripts
+ Make the XScriptContext available as a global variable
+ to the script
+ */
+ ImporterTopLevel scope = new ImporterTopLevel(ctxt);
+
+ Scriptable jsCtxt =
+ Context.toObject(
+ ScriptContext.createContext(
+ m_xModel, m_xInvocContext, m_xContext,
+ m_xMultiComponentFactory),
+ scope);
+
+ scope.put("XSCRIPTCONTEXT", scope, jsCtxt);
+
+ Scriptable jsArgs = Context.toObject(params, scope);
+ scope.put("ARGUMENTS", scope, jsArgs);
+
+ result = ctxt.evaluateString(scope, source, "<stdin>", 1, null);
+ result = Context.toString(result);
+ return result;
+ } catch (JavaScriptException jse) {
+ LogUtils.DEBUG("Caught JavaScriptException exception for JavaScript type = "
+ + jse.getClass());
+ String message = jse.getMessage();
+ Object wrap = jse.getValue();
+ LogUtils.DEBUG("\t message " + message);
+ LogUtils.DEBUG("\t wrapped type " + wrap.getClass());
+ LogUtils.DEBUG("\t wrapped toString " + wrap.toString());
+ ScriptExceptionRaisedException se = new
+ ScriptExceptionRaisedException(message);
+ se.lineNum = -1;
+ se.language = "JavaScript";
+ se.scriptName = metaData.getLanguageName();
+ se.exceptionType = wrap.getClass().getName();
+ se.language = metaData.getLanguage();
+ LogUtils.DEBUG("ExceptionRaised exception ");
+ LogUtils.DEBUG("\t message " + se.getMessage());
+ LogUtils.DEBUG("\t lineNum " + se.lineNum);
+ LogUtils.DEBUG("\t language " + se.language);
+ LogUtils.DEBUG("\t scriptName " + se.scriptName);
+ raiseEditor(se.lineNum);
+ throw new InvocationTargetException(
+ "JavaScript uncaught exception" + metaData.getLanguageName(), null, se);
+ } catch (Exception ex) {
+ LogUtils.DEBUG("Caught Exception " + ex);
+ LogUtils.DEBUG("rethrowing as ScriptFramework error");
+ throw new ScriptFrameworkErrorException(
+ ex.getMessage(), null, metaData.getLanguageName(),
+ metaData.getLanguage(), ScriptFrameworkErrorType.UNKNOWN);
+ } finally {
+ if (ctxt != null) {
+ Context.exit();
+ }
+ }
+ }
+
+ private void raiseEditor(int lineNum) {
+ try {
+ URL sourceUrl = metaData.getSourceURL();
+
+ ScriptEditorForJavaScript editor =
+ ScriptEditorForJavaScript.getEditor(sourceUrl);
+
+ if (editor == null) {
+ editor = ScriptEditorForJavaScript.getEditor();
+
+ editor.edit(
+ ScriptContext.createContext(m_xModel, m_xInvocContext,
+ m_xContext, m_xMultiComponentFactory),
+ metaData);
+
+ editor = ScriptEditorForJavaScript.getEditor(sourceUrl);
+ }
+
+ if (editor != null) {
+ System.out.println("** Have raised IDE for JavaScript, calling indicateErrorLine for line "
+ + lineNum);
+ editor.indicateErrorLine(lineNum);
+ }
+ } catch (java.net.MalformedURLException ignore) {
+ }
+ }
+}
diff --git a/scripting/java/com/sun/star/script/framework/provider/javascript/template.js b/scripting/java/com/sun/star/script/framework/provider/javascript/template.js
new file mode 100644
index 000000000..939ba339c
--- /dev/null
+++ b/scripting/java/com/sun/star/script/framework/provider/javascript/template.js
@@ -0,0 +1,54 @@
+/*
+ * 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 .
+ */
+// Hello World in JavaScript
+// Import standard OpenOffice.org API classes. For more information on
+// these classes and the OpenOffice.org API, see the OpenOffice.org
+// Developers Guide at:
+// https://api.libreoffice.org/
+
+importClass(Packages.com.sun.star.uno.UnoRuntime);
+importClass(Packages.com.sun.star.text.XTextDocument);
+importClass(Packages.com.sun.star.text.XText);
+importClass(Packages.com.sun.star.text.XTextRange);
+importClass(Packages.com.sun.star.frame.XModel);
+
+// Import XScriptContext class. An instance of this class is available
+// to all JavaScript scripts in the global variable "XSCRIPTCONTEXT". This
+// variable can be used to access the document for which this script
+// was invoked.
+
+// Methods available are:
+
+// XSCRIPTCONTEXT.getDocument() returns XModel
+// XSCRIPTCONTEXT.getInvocationContext() returns XScriptInvocationContext or NULL
+// XSCRIPTCONTEXT.getDesktop() returns XDesktop
+// XSCRIPTCONTEXT.getComponentContext() returns XComponentContext
+
+// For more information on using this class see the scripting
+// developer guides at:
+
+// https://api.libreoffice.org/docs/DevelopersGuide/ScriptingFramework/ScriptingFramework.xhtml
+
+
+oDoc = UnoRuntime.queryInterface(XModel,XSCRIPTCONTEXT.getInvocationContext());
+if ( !oDoc )
+ oDoc = XSCRIPTCONTEXT.getDocument();
+xTextDoc = UnoRuntime.queryInterface(XTextDocument,oDoc);
+xText = xTextDoc.getText();
+xTextRange = xText.getEnd();
+xTextRange.setString( "Hello World (in JavaScript)" );
diff --git a/scripting/source/basprov/baslibnode.cxx b/scripting/source/basprov/baslibnode.cxx
new file mode 100644
index 000000000..33942c6b2
--- /dev/null
+++ b/scripting/source/basprov/baslibnode.cxx
@@ -0,0 +1,130 @@
+/* -*- 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 "baslibnode.hxx"
+#include "basmodnode.hxx"
+#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
+#include <comphelper/sequence.hxx>
+#include <vcl/svapp.hxx>
+#include <basic/basmgr.hxx>
+#include <basic/sbstar.hxx>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::script;
+
+
+namespace basprov
+{
+
+
+ // BasicLibraryNodeImpl
+
+
+ BasicLibraryNodeImpl::BasicLibraryNodeImpl( const Reference< XComponentContext >& rxContext,
+ const OUString& sScriptingContext, BasicManager* pBasicManager,
+ const Reference< script::XLibraryContainer >& xLibContainer, const OUString& sLibName, bool isAppScript )
+ :m_xContext( rxContext )
+ ,m_sScriptingContext( sScriptingContext )
+ ,m_pBasicManager( pBasicManager )
+ ,m_xLibContainer( xLibContainer )
+ ,m_sLibName( sLibName )
+ ,m_bIsAppScript( isAppScript )
+ {
+ if ( m_xLibContainer.is() )
+ {
+ Any aElement = m_xLibContainer->getByName( m_sLibName );
+ aElement >>= m_xLibrary;
+ }
+ }
+
+
+ BasicLibraryNodeImpl::~BasicLibraryNodeImpl()
+ {
+ }
+
+
+ // XBrowseNode
+
+
+ OUString BasicLibraryNodeImpl::getName( )
+ {
+ SolarMutexGuard aGuard;
+
+ return m_sLibName;
+ }
+
+
+ Sequence< Reference< browse::XBrowseNode > > BasicLibraryNodeImpl::getChildNodes( )
+ {
+ SolarMutexGuard aGuard;
+
+ std::vector< Reference< browse::XBrowseNode > > aChildNodes;
+
+ if ( m_xLibContainer.is() && m_xLibContainer->hasByName( m_sLibName ) && !m_xLibContainer->isLibraryLoaded( m_sLibName ) )
+ m_xLibContainer->loadLibrary( m_sLibName );
+
+ if ( m_pBasicManager )
+ {
+ StarBASIC* pBasic = m_pBasicManager->GetLib( m_sLibName );
+ if ( pBasic && m_xLibrary.is() )
+ {
+ Sequence< OUString > aNames = m_xLibrary->getElementNames();
+ sal_Int32 nCount = aNames.getLength();
+ const OUString* pNames = aNames.getConstArray();
+ aChildNodes.resize( nCount );
+
+ for ( sal_Int32 i = 0 ; i < nCount ; ++i )
+ {
+ SbModule* pModule = pBasic->FindModule( pNames[i] );
+ if ( pModule )
+ aChildNodes[i] = new BasicModuleNodeImpl(m_xContext, m_sScriptingContext,
+ pModule, m_bIsAppScript);
+ }
+ }
+ }
+
+ return comphelper::containerToSequence(aChildNodes);
+ }
+
+
+ sal_Bool BasicLibraryNodeImpl::hasChildNodes( )
+ {
+ SolarMutexGuard aGuard;
+
+ bool bReturn = false;
+ if ( m_xLibrary.is() )
+ bReturn = m_xLibrary->hasElements();
+
+ return bReturn;
+ }
+
+
+ sal_Int16 BasicLibraryNodeImpl::getType( )
+ {
+ return browse::BrowseNodeTypes::CONTAINER;
+ }
+
+
+} // namespace basprov
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/basprov/baslibnode.hxx b/scripting/source/basprov/baslibnode.hxx
new file mode 100644
index 000000000..46d31aae5
--- /dev/null
+++ b/scripting/source/basprov/baslibnode.hxx
@@ -0,0 +1,70 @@
+/* -*- 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/script/browse/XBrowseNode.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/implbase.hxx>
+
+class BasicManager;
+
+
+namespace basprov
+{
+
+
+
+
+ typedef ::cppu::WeakImplHelper<
+ css::script::browse::XBrowseNode > BasicLibraryNodeImpl_BASE;
+
+
+ class BasicLibraryNodeImpl : public BasicLibraryNodeImpl_BASE
+ {
+ private:
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ OUString m_sScriptingContext;
+ BasicManager* m_pBasicManager;
+ css::uno::Reference< css::script::XLibraryContainer > m_xLibContainer;
+ css::uno::Reference< css::container::XNameContainer > m_xLibrary;
+ OUString m_sLibName;
+ bool m_bIsAppScript;
+
+ public:
+ BasicLibraryNodeImpl( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const OUString& sScriptingContext,
+ BasicManager* pBasicManager,
+ const css::uno::Reference< css::script::XLibraryContainer >& xLibContainer,
+ const OUString& sLibName, bool isAppScript );
+ virtual ~BasicLibraryNodeImpl() override;
+
+ // XBrowseNode
+ virtual OUString SAL_CALL getName( ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::script::browse::XBrowseNode > > SAL_CALL getChildNodes( ) override;
+ virtual sal_Bool SAL_CALL hasChildNodes( ) override;
+ virtual sal_Int16 SAL_CALL getType( ) override;
+ };
+
+
+} // namespace basprov
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/basprov/basmethnode.cxx b/scripting/source/basprov/basmethnode.cxx
new file mode 100644
index 000000000..fca2cafe8
--- /dev/null
+++ b/scripting/source/basprov/basmethnode.cxx
@@ -0,0 +1,291 @@
+/* -*- 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 "basmethnode.hxx"
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/frame/DispatchHelper.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/svapp.hxx>
+#include <basic/sbstar.hxx>
+#include <basic/sbmeth.hxx>
+#include <basic/sbmod.hxx>
+
+#include <util/MiscUtils.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::comphelper;
+using namespace ::com::sun::star::script;
+using namespace ::sf_misc;
+
+#define BASPROV_PROPERTY_ID_URI 1
+#define BASPROV_PROPERTY_ID_EDITABLE 2
+
+constexpr OUStringLiteral BASPROV_PROPERTY_URI = u"URI";
+constexpr OUStringLiteral BASPROV_PROPERTY_EDITABLE = u"Editable";
+
+#define BASPROV_DEFAULT_ATTRIBS() PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT | PropertyAttribute::READONLY
+
+
+namespace basprov
+{
+
+
+ // BasicMethodNodeImpl
+
+
+ BasicMethodNodeImpl::BasicMethodNodeImpl( const Reference< XComponentContext >& rxContext,
+ const OUString& sScriptingContext, SbMethod* pMethod, bool isAppScript )
+ : ::scripting_helper::OBroadcastHelperHolder( m_aMutex )
+ ,OPropertyContainer( GetBroadcastHelper() )
+ ,m_xContext( rxContext )
+ ,m_sScriptingContext( sScriptingContext )
+ ,m_pMethod( pMethod )
+ ,m_bIsAppScript( isAppScript )
+ ,m_bEditable( true )
+ {
+ if ( m_pMethod )
+ {
+ SbModule* pModule = m_pMethod->GetModule();
+ if ( pModule )
+ {
+ StarBASIC* pBasic = static_cast< StarBASIC* >( pModule->GetParent() );
+ if ( pBasic )
+ {
+ m_sURI = "vnd.sun.star.script:";
+ m_sURI += pBasic->GetName();
+ m_sURI += ".";
+ m_sURI += pModule->GetName();
+ m_sURI += ".";
+ m_sURI += m_pMethod->GetName();
+ m_sURI += "?language=Basic&location=";
+ if ( m_bIsAppScript )
+ m_sURI += "application";
+ else
+ m_sURI += "document";
+ }
+ }
+ }
+
+ registerProperty( BASPROV_PROPERTY_URI, BASPROV_PROPERTY_ID_URI, BASPROV_DEFAULT_ATTRIBS(), &m_sURI, cppu::UnoType<decltype(m_sURI)>::get() );
+ registerProperty( BASPROV_PROPERTY_EDITABLE, BASPROV_PROPERTY_ID_EDITABLE, BASPROV_DEFAULT_ATTRIBS(), &m_bEditable, cppu::UnoType<decltype(m_bEditable)>::get() );
+ }
+
+
+ BasicMethodNodeImpl::~BasicMethodNodeImpl()
+ {
+ }
+
+
+ // XInterface
+
+
+ IMPLEMENT_FORWARD_XINTERFACE2( BasicMethodNodeImpl, BasicMethodNodeImpl_BASE, OPropertyContainer )
+
+
+ // XTypeProvider
+
+
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( BasicMethodNodeImpl, BasicMethodNodeImpl_BASE, OPropertyContainer )
+
+
+ // XBrowseNode
+
+
+ OUString BasicMethodNodeImpl::getName( )
+ {
+ SolarMutexGuard aGuard;
+
+ OUString sMethodName;
+ if ( m_pMethod )
+ sMethodName = m_pMethod->GetName();
+
+ return sMethodName;
+ }
+
+
+ Sequence< Reference< browse::XBrowseNode > > BasicMethodNodeImpl::getChildNodes( )
+ {
+ return Sequence< Reference< browse::XBrowseNode > >();
+ }
+
+
+ sal_Bool BasicMethodNodeImpl::hasChildNodes( )
+ {
+ return false;
+ }
+
+
+ sal_Int16 BasicMethodNodeImpl::getType( )
+ {
+ return browse::BrowseNodeTypes::SCRIPT;
+ }
+
+
+ // OPropertySetHelper
+
+
+ ::cppu::IPropertyArrayHelper& BasicMethodNodeImpl::getInfoHelper( )
+ {
+ return *getArrayHelper();
+ }
+
+
+ // OPropertyArrayUsageHelper
+
+
+ ::cppu::IPropertyArrayHelper* BasicMethodNodeImpl::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+ }
+
+
+ // XPropertySet
+
+
+ Reference< XPropertySetInfo > BasicMethodNodeImpl::getPropertySetInfo( )
+ {
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+ }
+
+
+ // XInvocation
+
+
+ Reference< XIntrospectionAccess > BasicMethodNodeImpl::getIntrospection( )
+ {
+ return Reference< XIntrospectionAccess >();
+ }
+
+
+ Any BasicMethodNodeImpl::invoke( const OUString& aFunctionName, const Sequence< Any >&,
+ Sequence< sal_Int16 >&, Sequence< Any >& )
+ {
+ if ( aFunctionName != BASPROV_PROPERTY_EDITABLE )
+ {
+ throw IllegalArgumentException(
+ "BasicMethodNodeImpl::invoke: function name not supported!",
+ Reference< XInterface >(), 1 );
+ }
+
+ OUString sDocURL, sLibName, sModName;
+ sal_uInt16 nLine1 = 0;
+
+ if ( !m_bIsAppScript )
+ {
+ Reference< frame::XModel > xModel = MiscUtils::tDocUrlToModel( m_sScriptingContext );
+
+ if ( xModel.is() )
+ {
+ sDocURL = xModel->getURL();
+ if ( sDocURL.isEmpty() )
+ {
+ const Sequence < PropertyValue > aProps = xModel->getArgs();
+ // TODO: according to MBA the property 'Title' may change in future
+ const PropertyValue* pProp = std::find_if(aProps.begin(), aProps.end(),
+ [](const PropertyValue& rProp) { return rProp.Name == "Title"; });
+ if (pProp != aProps.end())
+ pProp->Value >>= sDocURL;
+ }
+ }
+ }
+
+ if ( m_pMethod )
+ {
+ sal_uInt16 nLine2;
+ m_pMethod->GetLineRange( nLine1, nLine2 );
+ SbModule* pModule = m_pMethod->GetModule();
+ if ( pModule )
+ {
+ sModName = pModule->GetName();
+ StarBASIC* pBasic = static_cast< StarBASIC* >( pModule->GetParent() );
+ if ( pBasic )
+ sLibName = pBasic->GetName();
+ }
+ }
+
+ if ( m_xContext.is() )
+ {
+ Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( m_xContext );
+
+ Reference < frame::XDispatchProvider > xProv( xDesktop->getCurrentFrame(), UNO_QUERY );
+
+ if ( xProv.is() )
+ {
+ Reference< frame::XDispatchHelper > xHelper( frame::DispatchHelper::create( m_xContext ) );
+
+ Sequence < PropertyValue > aArgs{
+ comphelper::makePropertyValue("Document", sDocURL),
+ comphelper::makePropertyValue("LibName", sLibName),
+ comphelper::makePropertyValue("Name", sModName),
+ comphelper::makePropertyValue("Type", OUString("Module")),
+ comphelper::makePropertyValue("Line", static_cast< sal_uInt32 >( nLine1 ))
+ };
+ xHelper->executeDispatch( xProv, ".uno:BasicIDEAppear", OUString(), 0, aArgs );
+ }
+ }
+
+
+ return Any();
+ }
+
+
+ void BasicMethodNodeImpl::setValue( const OUString&, const Any& )
+ {
+ throw UnknownPropertyException(
+ "BasicMethodNodeImpl::setValue: property name is unknown!" );
+ }
+
+
+ Any BasicMethodNodeImpl::getValue( const OUString& )
+ {
+ throw UnknownPropertyException(
+ "BasicMethodNodeImpl::getValue: property name is unknown!" );
+ }
+
+
+ sal_Bool BasicMethodNodeImpl::hasMethod( const OUString& aName )
+ {
+ bool bReturn = false;
+ if ( aName == BASPROV_PROPERTY_EDITABLE )
+ bReturn = true;
+
+ return bReturn;
+ }
+
+
+ sal_Bool BasicMethodNodeImpl::hasProperty( const OUString& )
+ {
+ return false;
+ }
+
+
+} // namespace basprov
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/basprov/basmethnode.hxx b/scripting/source/basprov/basmethnode.hxx
new file mode 100644
index 000000000..d1eddada0
--- /dev/null
+++ b/scripting/source/basprov/basmethnode.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 <bcholder.hxx>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/script/XInvocation.hpp>
+#include <com/sun/star/script/browse/XBrowseNode.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/implbase.hxx>
+
+
+class SbMethod;
+
+
+namespace basprov
+{
+
+
+
+
+ typedef ::cppu::WeakImplHelper<
+ css::script::browse::XBrowseNode,
+ css::script::XInvocation > BasicMethodNodeImpl_BASE;
+
+ class BasicMethodNodeImpl : public BasicMethodNodeImpl_BASE,
+ public cppu::BaseMutex,
+ public ::scripting_helper::OBroadcastHelperHolder,
+ public ::comphelper::OPropertyContainer,
+ public ::comphelper::OPropertyArrayUsageHelper< BasicMethodNodeImpl >
+ {
+ private:
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ OUString m_sScriptingContext;
+ SbMethod* m_pMethod;
+ bool m_bIsAppScript;
+
+ // properties
+ OUString m_sURI;
+ bool m_bEditable;
+
+ protected:
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper( ) override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ public:
+ BasicMethodNodeImpl( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const OUString& sScriptingContext,
+ SbMethod* pMethod, bool isAppScript );
+ virtual ~BasicMethodNodeImpl() override;
+
+ // XInterface
+ DECLARE_XINTERFACE()
+
+ // XTypeProvider
+ DECLARE_XTYPEPROVIDER()
+
+ // XBrowseNode
+ virtual OUString SAL_CALL getName( ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::script::browse::XBrowseNode > > SAL_CALL getChildNodes( ) override;
+ virtual sal_Bool SAL_CALL hasChildNodes( ) override;
+ virtual sal_Int16 SAL_CALL getType( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XInvocation
+ virtual css::uno::Reference< css::beans::XIntrospectionAccess > SAL_CALL getIntrospection( ) override;
+ virtual css::uno::Any SAL_CALL invoke(
+ const OUString& aFunctionName,
+ const css::uno::Sequence< css::uno::Any >& aParams,
+ css::uno::Sequence< sal_Int16 >& aOutParamIndex,
+ css::uno::Sequence< css::uno::Any >& aOutParam ) override;
+ virtual void SAL_CALL setValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getValue( const OUString& aPropertyName ) override;
+ virtual sal_Bool SAL_CALL hasMethod( const OUString& aName ) override;
+ virtual sal_Bool SAL_CALL hasProperty( const OUString& aName ) override;
+ };
+
+
+} // namespace basprov
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/basprov/basmodnode.cxx b/scripting/source/basprov/basmodnode.cxx
new file mode 100644
index 000000000..986e3062d
--- /dev/null
+++ b/scripting/source/basprov/basmodnode.cxx
@@ -0,0 +1,134 @@
+/* -*- 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 "basmodnode.hxx"
+#include "basmethnode.hxx"
+#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
+#include <vcl/svapp.hxx>
+#include <basic/sbx.hxx>
+#include <basic/sbmod.hxx>
+#include <basic/sbmeth.hxx>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::script;
+
+
+namespace basprov
+{
+
+
+ // BasicModuleNodeImpl
+
+
+ BasicModuleNodeImpl::BasicModuleNodeImpl( const Reference< XComponentContext >& rxContext,
+ const OUString& sScriptingContext, SbModule* pModule, bool isAppScript )
+ :m_xContext( rxContext )
+ ,m_sScriptingContext( sScriptingContext )
+ ,m_pModule( pModule )
+ ,m_bIsAppScript( isAppScript )
+ {
+ }
+
+
+ BasicModuleNodeImpl::~BasicModuleNodeImpl()
+ {
+ }
+
+
+ // XBrowseNode
+
+
+ OUString BasicModuleNodeImpl::getName( )
+ {
+ SolarMutexGuard aGuard;
+
+ OUString sModuleName;
+ if ( m_pModule )
+ sModuleName = m_pModule->GetName();
+
+ return sModuleName;
+ }
+
+
+ Sequence< Reference< browse::XBrowseNode > > BasicModuleNodeImpl::getChildNodes( )
+ {
+ SolarMutexGuard aGuard;
+
+ Sequence< Reference< browse::XBrowseNode > > aChildNodes;
+
+ if ( m_pModule )
+ {
+ SbxArray* pMethods = m_pModule->GetMethods().get();
+ if ( pMethods )
+ {
+ sal_uInt32 nCount = pMethods->Count();
+ sal_Int32 nRealCount = 0;
+ for ( sal_uInt32 i = 0; i < nCount; ++i )
+ {
+ SbMethod* pMethod = static_cast<SbMethod*>(pMethods->Get(i));
+ if ( pMethod && !pMethod->IsHidden() )
+ ++nRealCount;
+ }
+ aChildNodes.realloc( nRealCount );
+ Reference< browse::XBrowseNode >* pChildNodes = aChildNodes.getArray();
+
+ sal_Int32 iTarget = 0;
+ for ( sal_uInt32 i = 0; i < nCount; ++i )
+ {
+ SbMethod* pMethod = static_cast<SbMethod*>(pMethods->Get(i));
+ if ( pMethod && !pMethod->IsHidden() )
+ pChildNodes[iTarget++] = new BasicMethodNodeImpl(
+ m_xContext, m_sScriptingContext, pMethod, m_bIsAppScript);
+ }
+ }
+ }
+
+ return aChildNodes;
+ }
+
+
+ sal_Bool BasicModuleNodeImpl::hasChildNodes( )
+ {
+ SolarMutexGuard aGuard;
+
+ bool bReturn = false;
+ if ( m_pModule )
+ {
+ SbxArray* pMethods = m_pModule->GetMethods().get();
+ if (pMethods && pMethods->Count() > 0)
+ bReturn = true;
+ }
+
+ return bReturn;
+ }
+
+
+ sal_Int16 BasicModuleNodeImpl::getType( )
+ {
+ return browse::BrowseNodeTypes::CONTAINER;
+ }
+
+
+} // namespace basprov
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/basprov/basmodnode.hxx b/scripting/source/basprov/basmodnode.hxx
new file mode 100644
index 000000000..ebf0957ef
--- /dev/null
+++ b/scripting/source/basprov/basmodnode.hxx
@@ -0,0 +1,64 @@
+/* -*- 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/browse/XBrowseNode.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/implbase.hxx>
+
+class SbModule;
+
+
+namespace basprov
+{
+
+
+
+
+ typedef ::cppu::WeakImplHelper<
+ css::script::browse::XBrowseNode > BasicModuleNodeImpl_BASE;
+
+
+ class BasicModuleNodeImpl : public BasicModuleNodeImpl_BASE
+ {
+ private:
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ OUString m_sScriptingContext;
+ SbModule* m_pModule;
+ bool m_bIsAppScript;
+
+ public:
+ BasicModuleNodeImpl( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const OUString& sScriptingContext,
+ SbModule* pModule, bool isAppScript );
+ virtual ~BasicModuleNodeImpl() override;
+
+ // XBrowseNode
+ virtual OUString SAL_CALL getName( ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::script::browse::XBrowseNode > > SAL_CALL getChildNodes( ) override;
+ virtual sal_Bool SAL_CALL hasChildNodes( ) override;
+ virtual sal_Int16 SAL_CALL getType( ) override;
+ };
+
+
+} // namespace basprov
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/basprov/basprov.component b/scripting/source/basprov/basprov.component
new file mode 100644
index 000000000..d0d6bf974
--- /dev/null
+++ b/scripting/source/basprov/basprov.component
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.scripting.ScriptProviderForBasic"
+ constructor="scripting_BasicProviderImpl_get_implementation">
+ <service name="com.sun.star.script.browse.BrowseNode"/>
+ <service name="com.sun.star.script.provider.LanguageScriptProvider"/>
+ <service name="com.sun.star.script.provider.ScriptProvider"/>
+ <service name="com.sun.star.script.provider.ScriptProviderForBasic"/>
+ </implementation>
+</component>
diff --git a/scripting/source/basprov/basprov.cxx b/scripting/source/basprov/basprov.cxx
new file mode 100644
index 000000000..d4afb41ea
--- /dev/null
+++ b/scripting/source/basprov/basprov.cxx
@@ -0,0 +1,477 @@
+/* -*- 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 "basprov.hxx"
+#include "basscript.hxx"
+#include "baslibnode.hxx"
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorException.hpp>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
+#include <com/sun/star/document/XEmbeddedScripts.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+
+#include <cppuhelper/supportsservice.hxx>
+#include <rtl/uri.hxx>
+#include <sal/log.hxx>
+#include <osl/file.hxx>
+#include <vcl/svapp.hxx>
+#include <basic/basmgr.hxx>
+#include <basic/basicmanagerrepository.hxx>
+#include <basic/sbstar.hxx>
+#include <basic/sbmod.hxx>
+#include <basic/sbmeth.hxx>
+#include <sfx2/app.hxx>
+
+#include <com/sun/star/util/theMacroExpander.hpp>
+#include <com/sun/star/script/XLibraryContainer2.hpp>
+#include <com/sun/star/uri/XUriReference.hpp>
+#include <com/sun/star/uri/XUriReferenceFactory.hpp>
+#include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
+
+#include <util/MiscUtils.hxx>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::document;
+using namespace ::sf_misc;
+
+
+namespace basprov
+{
+
+ // BasicProviderImpl
+
+
+ BasicProviderImpl::BasicProviderImpl( const Reference< XComponentContext >& xContext )
+ :m_pAppBasicManager( nullptr )
+ ,m_pDocBasicManager( nullptr )
+ ,m_xContext( xContext )
+ ,m_bIsAppScriptCtx( true )
+ ,m_bIsUserCtx(true)
+ {
+ }
+
+
+ BasicProviderImpl::~BasicProviderImpl()
+ {
+ SolarMutexGuard aGuard;
+ EndListeningAll();
+ }
+
+
+ bool BasicProviderImpl::isLibraryShared( const Reference< script::XLibraryContainer >& rxLibContainer, const OUString& rLibName )
+ {
+ bool bIsShared = false;
+
+ Reference< script::XLibraryContainer2 > xLibContainer( rxLibContainer, UNO_QUERY );
+ if ( xLibContainer.is() && xLibContainer->hasByName( rLibName ) && xLibContainer->isLibraryLink( rLibName ) )
+ {
+ OUString aFileURL;
+ if ( m_xContext.is() )
+ {
+ Reference< uri::XUriReferenceFactory > xUriFac( uri::UriReferenceFactory::create( m_xContext ) );
+
+ OUString aLinkURL( xLibContainer->getLibraryLinkURL( rLibName ) );
+ Reference< uri::XUriReference > xUriRef = xUriFac->parse( aLinkURL );
+
+ if ( xUriRef.is() )
+ {
+ OUString aScheme = xUriRef->getScheme();
+ if ( aScheme.equalsIgnoreAsciiCase("file") )
+ {
+ aFileURL = aLinkURL;
+ }
+ else if ( aScheme.equalsIgnoreAsciiCase("vnd.sun.star.pkg") )
+ {
+ OUString aAuthority = xUriRef->getAuthority();
+ if ( aAuthority.matchIgnoreAsciiCase( "vnd.sun.star.expand:" ) )
+ {
+ OUString aDecodedURL( aAuthority.copy( sizeof ( "vnd.sun.star.expand:" ) - 1 ) );
+ aDecodedURL = ::rtl::Uri::decode( aDecodedURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
+ Reference<util::XMacroExpander> xMacroExpander =
+ util::theMacroExpander::get(m_xContext);
+ aFileURL = xMacroExpander->expandMacros( aDecodedURL );
+ }
+ }
+ }
+ }
+
+ if ( !aFileURL.isEmpty() )
+ {
+ osl::DirectoryItem aFileItem;
+ osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileURL );
+ OSL_VERIFY( osl::DirectoryItem::get( aFileURL, aFileItem ) == osl::FileBase::E_None );
+ OSL_VERIFY( aFileItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None );
+ OUString aCanonicalFileURL( aFileStatus.getFileURL() );
+
+ if( aCanonicalFileURL.indexOf( "share/basic" ) != -1
+ || aCanonicalFileURL.indexOf( "share/uno_packages" ) != -1 )
+ bIsShared = true;
+ }
+ }
+
+ return bIsShared;
+ }
+
+ // SfxListener
+ void BasicProviderImpl::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+ {
+ if (auto pManager = dynamic_cast<const BasicManager*>(&rBC))
+ if (pManager == m_pAppBasicManager && rHint.GetId() == SfxHintId::Dying)
+ {
+ EndListening(*m_pAppBasicManager);
+ m_pAppBasicManager = nullptr;
+ }
+ }
+
+ // XServiceInfo
+ OUString BasicProviderImpl::getImplementationName( )
+ {
+ return "com.sun.star.comp.scripting.ScriptProviderForBasic";
+ }
+
+ sal_Bool BasicProviderImpl::supportsService( const OUString& rServiceName )
+ {
+ return cppu::supportsService(this, rServiceName);
+ }
+
+ Sequence< OUString > BasicProviderImpl::getSupportedServiceNames( )
+ {
+ return {
+ "com.sun.star.script.provider.ScriptProviderForBasic",
+ "com.sun.star.script.provider.LanguageScriptProvider",
+ "com.sun.star.script.provider.ScriptProvider",
+ "com.sun.star.script.browse.BrowseNode"};
+ }
+
+
+ // XInitialization
+
+
+ void BasicProviderImpl::initialize( const Sequence< Any >& aArguments )
+ {
+ // TODO
+
+ SolarMutexGuard aGuard;
+
+ if ( aArguments.getLength() != 1 )
+ {
+ throw IllegalArgumentException(
+ "BasicProviderImpl::initialize: incorrect argument count.",
+ *this,
+ 1
+ );
+ }
+
+ Reference< frame::XModel > xModel;
+
+ m_xInvocationContext.set( aArguments[0], UNO_QUERY );
+ if ( m_xInvocationContext.is() )
+ {
+ xModel.set( m_xInvocationContext->getScriptContainer(), UNO_QUERY );
+ if ( !xModel.is() )
+ {
+ throw IllegalArgumentException(
+ "BasicProviderImpl::initialize: unable to determine the document model from the script invocation context.",
+ *this,
+ 1
+ );
+ }
+ }
+ else
+ {
+ if ( !( aArguments[0] >>= m_sScriptingContext ) )
+ {
+ throw IllegalArgumentException(
+ "BasicProviderImpl::initialize: incorrect argument type " + aArguments[0].getValueTypeName(),
+ *this,
+ 1
+ );
+ }
+
+ if ( m_sScriptingContext.startsWith( "vnd.sun.star.tdoc" ) )
+ {
+ xModel = MiscUtils::tDocUrlToModel( m_sScriptingContext );
+ }
+ }
+
+ if ( xModel.is() )
+ {
+ Reference< XEmbeddedScripts > xDocumentScripts( xModel, UNO_QUERY );
+ if ( xDocumentScripts.is() )
+ {
+ m_pDocBasicManager = ::basic::BasicManagerRepository::getDocumentBasicManager( xModel );
+ m_xLibContainerDoc = xDocumentScripts->getBasicLibraries();
+ OSL_ENSURE( m_pDocBasicManager && m_xLibContainerDoc.is(),
+ "BasicProviderImpl::initialize: invalid BasicManager, or invalid script container!" );
+ }
+ m_bIsAppScriptCtx = false;
+ }
+ else
+ {
+ // Provider has been created with application context for user
+ // or share
+ if ( m_sScriptingContext != "user" )
+ {
+ m_bIsUserCtx = false;
+ }
+ else
+ {
+ /*
+ throw RuntimeException(
+ "BasicProviderImpl::initialize: no scripting context!" );
+ */
+ }
+ }
+
+ // TODO
+ if ( !m_pAppBasicManager )
+ {
+ m_pAppBasicManager = SfxApplication::GetBasicManager();
+ if (m_pAppBasicManager)
+ StartListening(*m_pAppBasicManager);
+ }
+
+ if ( !m_xLibContainerApp.is() )
+ m_xLibContainerApp = SfxGetpApp()->GetBasicContainer();
+ }
+
+
+ // XScriptProvider
+
+
+ Reference < provider::XScript > BasicProviderImpl::getScript( const OUString& scriptURI )
+ {
+ // TODO
+
+ SolarMutexGuard aGuard;
+
+ Reference< provider::XScript > xScript;
+ Reference< uri::XUriReferenceFactory > xFac ( uri::UriReferenceFactory::create( m_xContext ) );
+
+ Reference< uri::XUriReference > uriRef = xFac->parse( scriptURI );
+
+ Reference < uri::XVndSunStarScriptUrl > sfUri( uriRef, UNO_QUERY );
+
+ if ( !uriRef.is() || !sfUri.is() )
+ {
+ throw provider::ScriptFrameworkErrorException(
+ "BasicProviderImpl::getScript: failed to parse URI: " + scriptURI,
+ Reference< XInterface >(),
+ scriptURI, "Basic",
+ provider::ScriptFrameworkErrorType::MALFORMED_URL );
+ }
+
+
+ OUString aDescription = sfUri->getName();
+ OUString aLocation = sfUri->getParameter( "location" );
+
+ sal_Int32 nIndex = 0;
+ // In some strange circumstances the Library name can have an
+ // apparently illegal '.' in it ( in imported VBA )
+
+ BasicManager* pBasicMgr = nullptr;
+ if ( aLocation == "document" )
+ {
+ pBasicMgr = m_pDocBasicManager;
+ }
+ else if ( aLocation == "application" )
+ {
+ pBasicMgr = m_pAppBasicManager;
+ }
+ OUString sProjectName;
+ if ( pBasicMgr )
+ sProjectName = pBasicMgr->GetName();
+
+ OUString aLibrary;
+ if ( !sProjectName.isEmpty() && aDescription.match( sProjectName ) )
+ {
+ SAL_WARN("scripting", "LibraryName " << sProjectName << " is part of the url " << aDescription );
+ aLibrary = sProjectName;
+ nIndex = sProjectName.getLength() + 1;
+ }
+ else
+ aLibrary = aDescription.getToken( 0, '.', nIndex );
+ OUString aModule;
+ if ( nIndex != -1 )
+ aModule = aDescription.getToken( 0, '.', nIndex );
+ OUString aMethod;
+ if ( nIndex != -1 )
+ aMethod = aDescription.getToken( 0, '.', nIndex );
+
+ if ( !aLibrary.isEmpty() && !aModule.isEmpty() && !aMethod.isEmpty() && !aLocation.isEmpty() )
+ {
+
+ if ( pBasicMgr )
+ {
+ StarBASIC* pBasic = pBasicMgr->GetLib( aLibrary );
+ if ( !pBasic )
+ {
+ sal_uInt16 nId = pBasicMgr->GetLibId( aLibrary );
+ if ( nId != LIB_NOTFOUND )
+ {
+ pBasicMgr->LoadLib( nId );
+ pBasic = pBasicMgr->GetLib( aLibrary );
+ }
+ }
+ if ( pBasic )
+ {
+ SbModule* pModule = pBasic->FindModule( aModule );
+ if ( pModule )
+ {
+ SbMethod* pMethod = pModule->FindMethod( aMethod, SbxClassType::Method );
+ if ( pMethod && !pMethod->IsHidden() )
+ {
+ if ( m_pDocBasicManager == pBasicMgr )
+ xScript = new BasicScriptImpl( aDescription, pMethod, *m_pDocBasicManager, m_xInvocationContext );
+ else
+ xScript = new BasicScriptImpl( aDescription, pMethod );
+ }
+ }
+ }
+ }
+ }
+
+ if ( !xScript.is() )
+ {
+ throw provider::ScriptFrameworkErrorException(
+ "The following Basic script could not be found:\n"
+ "library: '" + aLibrary + "'\n"
+ "module: '" + aModule + "'\n"
+ "method: '" + aMethod + "'\n"
+ "location: '" + aLocation + "'\n",
+ Reference< XInterface >(),
+ scriptURI, "Basic",
+ provider::ScriptFrameworkErrorType::NO_SUCH_SCRIPT );
+ }
+
+ return xScript;
+ }
+
+
+ // XBrowseNode
+
+
+ OUString BasicProviderImpl::getName( )
+ {
+ return "Basic";
+ }
+
+
+ Sequence< Reference< browse::XBrowseNode > > BasicProviderImpl::getChildNodes( )
+ {
+ SolarMutexGuard aGuard;
+
+ Reference< script::XLibraryContainer > xLibContainer;
+ BasicManager* pBasicManager = nullptr;
+
+ if ( m_bIsAppScriptCtx )
+ {
+ xLibContainer = m_xLibContainerApp;
+ pBasicManager = m_pAppBasicManager;
+ }
+ else
+ {
+ xLibContainer = m_xLibContainerDoc;
+ pBasicManager = m_pDocBasicManager;
+ }
+
+ Sequence< Reference< browse::XBrowseNode > > aChildNodes;
+
+ if ( pBasicManager && xLibContainer.is() )
+ {
+ const Sequence< OUString > aLibNames = xLibContainer->getElementNames();
+ sal_Int32 nLibCount = aLibNames.getLength();
+ aChildNodes.realloc( nLibCount );
+ Reference< browse::XBrowseNode >* pChildNodes = aChildNodes.getArray();
+ sal_Int32 childrenFound = 0;
+
+ for ( const OUString& rLibName : aLibNames )
+ {
+ bool bCreate = false;
+ if ( m_bIsAppScriptCtx )
+ {
+ const bool bShared = isLibraryShared( xLibContainer, rLibName );
+ if (m_bIsUserCtx != bShared)
+ bCreate = true;
+ }
+ else
+ {
+ bCreate = true;
+ }
+ if ( bCreate )
+ {
+ pChildNodes[childrenFound++]
+ = new BasicLibraryNodeImpl(m_xContext, m_sScriptingContext, pBasicManager,
+ xLibContainer, rLibName, m_bIsAppScriptCtx);
+ }
+ }
+
+ if ( childrenFound != nLibCount )
+ aChildNodes.realloc( childrenFound );
+ }
+
+ return aChildNodes;
+ }
+
+
+ sal_Bool BasicProviderImpl::hasChildNodes( )
+ {
+ SolarMutexGuard aGuard;
+
+ bool bReturn = false;
+ Reference< script::XLibraryContainer > xLibContainer;
+ if ( m_bIsAppScriptCtx )
+ {
+ xLibContainer = m_xLibContainerApp;
+ }
+ else
+ {
+ xLibContainer = m_xLibContainerDoc;
+ }
+ if ( xLibContainer.is() )
+ bReturn = xLibContainer->hasElements();
+
+ return bReturn;
+ }
+
+
+ sal_Int16 BasicProviderImpl::getType( )
+ {
+ return browse::BrowseNodeTypes::CONTAINER;
+ }
+
+
+ // component operations
+
+ extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ scripting_BasicProviderImpl_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+ {
+ return cppu::acquire(new BasicProviderImpl(context));
+ }
+
+
+} // namespace basprov
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/basprov/basprov.hxx b/scripting/source/basprov/basprov.hxx
new file mode 100644
index 000000000..994113b62
--- /dev/null
+++ b/scripting/source/basprov/basprov.hxx
@@ -0,0 +1,97 @@
+/* -*- 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 <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/script/XLibraryContainer.hpp>
+#include <com/sun/star/script/browse/XBrowseNode.hpp>
+#include <com/sun/star/script/provider/XScriptProvider.hpp>
+#include <com/sun/star/document/XScriptInvocationContext.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <svl/lstner.hxx>
+
+class BasicManager;
+
+
+namespace basprov
+{
+
+
+
+
+ typedef ::cppu::WeakImplHelper<
+ css::lang::XServiceInfo,
+ css::lang::XInitialization,
+ css::script::provider::XScriptProvider,
+ css::script::browse::XBrowseNode > BasicProviderImpl_BASE;
+
+
+ class BasicProviderImpl : public BasicProviderImpl_BASE, public SfxListener
+ {
+ private:
+ BasicManager* m_pAppBasicManager;
+ BasicManager* m_pDocBasicManager;
+ css::uno::Reference< css::script::XLibraryContainer > m_xLibContainerApp;
+ css::uno::Reference< css::script::XLibraryContainer > m_xLibContainerDoc;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::document::XScriptInvocationContext > m_xInvocationContext;
+ OUString m_sScriptingContext;
+ bool m_bIsAppScriptCtx;
+ bool m_bIsUserCtx;
+
+ bool isLibraryShared(
+ const css::uno::Reference< css::script::XLibraryContainer >& rxLibContainer,
+ const OUString& rLibName );
+
+ public:
+ explicit BasicProviderImpl(
+ const css::uno::Reference< css::uno::XComponentContext >& xContext );
+ virtual ~BasicProviderImpl() 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;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XScriptProvider
+ virtual css::uno::Reference < css::script::provider::XScript > SAL_CALL getScript(
+ const OUString& scriptURI ) override;
+
+ // XBrowseNode
+ virtual OUString SAL_CALL getName( ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::script::browse::XBrowseNode > > SAL_CALL getChildNodes( ) override;
+ virtual sal_Bool SAL_CALL hasChildNodes( ) override;
+ virtual sal_Int16 SAL_CALL getType( ) override;
+
+ protected:
+ // SfxListener
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+ };
+
+
+} // namespace basprov
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/basprov/basscript.cxx b/scripting/source/basprov/basscript.cxx
new file mode 100644
index 000000000..b5a3f6136
--- /dev/null
+++ b/scripting/source/basprov/basscript.cxx
@@ -0,0 +1,314 @@
+/* -*- 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 "basscript.hxx"
+#include <vcl/svapp.hxx>
+#include <basic/sbx.hxx>
+#include <basic/sbmod.hxx>
+#include <basic/sbmeth.hxx>
+#include <basic/sbuno.hxx>
+#include <basic/basmgr.hxx>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorException.hpp>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
+#include <bcholder.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <map>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::beans;
+
+
+namespace basprov
+{
+
+#define BASSCRIPT_PROPERTY_ID_CALLER 1
+constexpr OUStringLiteral BASSCRIPT_PROPERTY_CALLER = u"Caller";
+
+#define BASSCRIPT_DEFAULT_ATTRIBS() PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT
+
+ typedef ::std::map< sal_Int16, Any > OutParamMap;
+
+
+ // BasicScriptImpl
+
+
+ BasicScriptImpl::BasicScriptImpl( const OUString& funcName, SbMethodRef const & xMethod )
+ : ::scripting_helper::OBroadcastHelperHolder( m_aMutex )
+ ,OPropertyContainer( GetBroadcastHelper() )
+ ,m_xMethod( xMethod )
+ ,m_funcName( funcName )
+ ,m_documentBasicManager( nullptr )
+ ,m_xDocumentScriptContext()
+ {
+ registerProperty( BASSCRIPT_PROPERTY_CALLER, BASSCRIPT_PROPERTY_ID_CALLER, BASSCRIPT_DEFAULT_ATTRIBS(), &m_caller, cppu::UnoType<decltype(m_caller)>::get() );
+ }
+
+
+ BasicScriptImpl::BasicScriptImpl( const OUString& funcName, SbMethodRef const & xMethod,
+ BasicManager& documentBasicManager, const Reference< XScriptInvocationContext >& documentScriptContext ) : ::scripting_helper::OBroadcastHelperHolder( m_aMutex )
+ ,OPropertyContainer( GetBroadcastHelper() )
+ ,m_xMethod( xMethod )
+ ,m_funcName( funcName )
+ ,m_documentBasicManager( &documentBasicManager )
+ ,m_xDocumentScriptContext( documentScriptContext )
+ {
+ StartListening( *m_documentBasicManager );
+ registerProperty( BASSCRIPT_PROPERTY_CALLER, BASSCRIPT_PROPERTY_ID_CALLER, BASSCRIPT_DEFAULT_ATTRIBS(), &m_caller, cppu::UnoType<decltype(m_caller)>::get() );
+ }
+
+
+ BasicScriptImpl::~BasicScriptImpl()
+ {
+ SolarMutexGuard g;
+
+ if ( m_documentBasicManager )
+ EndListening( *m_documentBasicManager );
+ }
+
+
+ // SfxListener
+
+ void BasicScriptImpl::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+ {
+ if ( &rBC != m_documentBasicManager )
+ {
+ OSL_ENSURE( false, "BasicScriptImpl::Notify: where does this come from?" );
+ // not interested in
+ return;
+ }
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ m_documentBasicManager = nullptr;
+ EndListening( rBC ); // prevent multiple notifications
+ }
+ }
+
+
+ // XInterface
+
+
+ IMPLEMENT_FORWARD_XINTERFACE2( BasicScriptImpl, BasicScriptImpl_BASE, OPropertyContainer )
+
+
+ // XTypeProvider
+
+
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( BasicScriptImpl, BasicScriptImpl_BASE, OPropertyContainer )
+
+
+ // OPropertySetHelper
+
+
+ ::cppu::IPropertyArrayHelper& BasicScriptImpl::getInfoHelper( )
+ {
+ return *getArrayHelper();
+ }
+
+
+ // OPropertyArrayUsageHelper
+
+
+ ::cppu::IPropertyArrayHelper* BasicScriptImpl::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+ }
+
+
+ // XPropertySet
+
+
+ Reference< XPropertySetInfo > BasicScriptImpl::getPropertySetInfo( )
+ {
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+ }
+
+
+ // XScript
+
+
+ Any BasicScriptImpl::invoke( const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
+ {
+ // TODO: throw CannotConvertException
+ // TODO: check length of aOutParamIndex, aOutParam
+
+ SolarMutexGuard aGuard;
+
+ Any aReturn;
+
+ if ( m_xMethod.is() )
+ {
+ // check if compiled
+ SbModule* pModule = static_cast< SbModule* >( m_xMethod->GetParent() );
+ if ( pModule && !pModule->IsCompiled() )
+ pModule->Compile();
+
+ // check number of parameters
+ sal_Int32 nParamsCount = aParams.getLength();
+ SbxInfo* pInfo = m_xMethod->GetInfo();
+ if ( pInfo )
+ {
+ sal_Int32 nSbxOptional = 0;
+ sal_uInt16 n = 1;
+ for ( const SbxParamInfo* pParamInfo = pInfo->GetParam( n ); pParamInfo; pParamInfo = pInfo->GetParam( ++n ) )
+ {
+ if ( pParamInfo->nFlags & SbxFlagBits::Optional )
+ ++nSbxOptional;
+ else
+ nSbxOptional = 0;
+ }
+ sal_Int32 nSbxCount = n - 1;
+ if ( nParamsCount < nSbxCount - nSbxOptional )
+ {
+ throw provider::ScriptFrameworkErrorException(
+ "wrong number of parameters!",
+ Reference< XInterface >(),
+ m_funcName,
+ "Basic",
+ provider::ScriptFrameworkErrorType::NO_SUCH_SCRIPT );
+ }
+ }
+
+ // set parameters
+ SbxArrayRef xSbxParams;
+ if ( nParamsCount > 0 )
+ {
+ xSbxParams = new SbxArray;
+ const Any* pParams = aParams.getConstArray();
+ for ( sal_Int32 i = 0; i < nParamsCount; ++i )
+ {
+ SbxVariableRef xSbxVar = new SbxVariable( SbxVARIANT );
+ unoToSbxValue( xSbxVar.get(), pParams[i] );
+ xSbxParams->Put(xSbxVar.get(), static_cast<sal_uInt32>(i) + 1);
+
+ if (pInfo)
+ {
+ if (auto* p = pInfo->GetParam(static_cast<sal_uInt16>(i) + 1))
+ {
+ SbxDataType t = static_cast<SbxDataType>(p->eType & 0x0FFF);
+ // tdf#133889 Revert the downcasting performed in sbxToUnoValueImpl
+ // to allow passing by reference.
+ SbxDataType a = xSbxVar->GetType();
+ if (t == SbxSINGLE && (a == SbxINTEGER || a == SbxLONG))
+ {
+ sal_Int32 val = xSbxVar->GetLong();
+ if (val >= -16777216 && val <= 16777215)
+ xSbxVar->SetType(t);
+ }
+ else if (t == SbxDOUBLE && (a == SbxINTEGER || a == SbxLONG))
+ xSbxVar->SetType(t);
+ else if (t == SbxLONG && a == SbxINTEGER)
+ xSbxVar->SetType(t);
+ else if (t == SbxULONG && a == SbxUSHORT)
+ xSbxVar->SetType(t);
+ // Enable passing by ref
+ if (t != SbxVARIANT)
+ xSbxVar->SetFlag(SbxFlagBits::Fixed);
+ }
+ }
+ }
+ }
+ if ( xSbxParams.is() )
+ m_xMethod->SetParameters( xSbxParams.get() );
+
+ // call method
+ SbxVariableRef xReturn = new SbxVariable;
+ ErrCode nErr = ERRCODE_NONE;
+
+ // if it's a document-based script, temporarily reset ThisComponent to the script invocation context
+ Any aOldThisComponent;
+ if ( m_documentBasicManager && m_xDocumentScriptContext.is() )
+ m_documentBasicManager->SetGlobalUNOConstant( "ThisComponent", Any( m_xDocumentScriptContext ), &aOldThisComponent );
+
+ if ( m_caller.hasElements() && m_caller[ 0 ].hasValue() )
+ {
+ SbxVariableRef xCallerVar = new SbxVariable( SbxVARIANT );
+ unoToSbxValue( xCallerVar.get(), m_caller[ 0 ] );
+ nErr = m_xMethod->Call( xReturn.get(), xCallerVar.get() );
+ }
+ else
+ nErr = m_xMethod->Call( xReturn.get() );
+
+ if ( m_documentBasicManager && m_xDocumentScriptContext.is() )
+ m_documentBasicManager->SetGlobalUNOConstant( "ThisComponent", aOldThisComponent );
+
+ if ( nErr != ERRCODE_NONE )
+ {
+ // TODO: throw InvocationTargetException ?
+ }
+
+ // get output parameters
+ if ( xSbxParams.is() )
+ {
+ SbxInfo* pInfo_ = m_xMethod->GetInfo();
+ if ( pInfo_ )
+ {
+ OutParamMap aOutParamMap;
+ for (sal_uInt32 n = 1, nCount = xSbxParams->Count(); n < nCount; ++n)
+ {
+ assert(nCount <= std::numeric_limits<sal_uInt16>::max());
+ const SbxParamInfo* pParamInfo = pInfo_->GetParam( sal::static_int_cast<sal_uInt16>(n) );
+ if ( pParamInfo && ( pParamInfo->eType & SbxBYREF ) != 0 )
+ {
+ SbxVariable* pVar = xSbxParams->Get(n);
+ if ( pVar )
+ {
+ SbxVariableRef xVar = pVar;
+ aOutParamMap.emplace( n - 1, sbxToUnoValue( xVar.get() ) );
+ }
+ }
+ }
+ sal_Int32 nOutParamCount = aOutParamMap.size();
+ aOutParamIndex.realloc( nOutParamCount );
+ aOutParam.realloc( nOutParamCount );
+ sal_Int16* pOutParamIndex = aOutParamIndex.getArray();
+ Any* pOutParam = aOutParam.getArray();
+ for ( const auto& rEntry : aOutParamMap )
+ {
+ *pOutParamIndex = rEntry.first;
+ ++pOutParamIndex;
+ *pOutParam = rEntry.second;
+ ++pOutParam;
+ }
+ }
+ }
+
+ // get return value
+ aReturn = sbxToUnoValue( xReturn.get() );
+
+ // reset parameters
+ m_xMethod->SetParameters( nullptr );
+ }
+
+ return aReturn;
+ }
+
+
+} // namespace basprov
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/basprov/basscript.hxx b/scripting/source/basprov/basscript.hxx
new file mode 100644
index 000000000..d0f9e6e7a
--- /dev/null
+++ b/scripting/source/basprov/basscript.hxx
@@ -0,0 +1,103 @@
+/* -*- 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 <bcholder.hxx>
+#include <com/sun/star/script/provider/XScript.hpp>
+#include <com/sun/star/document/XScriptInvocationContext.hpp>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <basic/sbmeth.hxx>
+#include <svl/lstner.hxx>
+
+class BasicManager;
+
+
+namespace basprov
+{
+
+
+
+
+ typedef ::cppu::WeakImplHelper<
+ css::script::provider::XScript > BasicScriptImpl_BASE;
+
+
+ class BasicScriptImpl : public BasicScriptImpl_BASE, public SfxListener,
+ public cppu::BaseMutex,
+ public ::scripting_helper::OBroadcastHelperHolder,
+ public ::comphelper::OPropertyContainer,
+ public ::comphelper::OPropertyArrayUsageHelper< BasicScriptImpl >
+ {
+ private:
+ SbMethodRef m_xMethod;
+ OUString m_funcName;
+ BasicManager* m_documentBasicManager;
+ css::uno::Reference< css::document::XScriptInvocationContext >
+ m_xDocumentScriptContext;
+ // hack, OPropertyContainer doesn't allow you to define a property of unknown
+ // type ( I guess because an Any can't contain an Any... I've always wondered why?
+ // as it's not unusual to do that in corba )
+ css::uno::Sequence< css::uno::Any > m_caller;
+ protected:
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper( ) override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ public:
+ BasicScriptImpl(
+ const OUString& funcName,
+ SbMethodRef const & xMethod
+ );
+ BasicScriptImpl(
+ const OUString& funcName,
+ SbMethodRef const & xMethod,
+ BasicManager& documentBasicManager,
+ const css::uno::Reference< css::document::XScriptInvocationContext >& documentScriptContext
+ );
+ virtual ~BasicScriptImpl() override;
+
+ // XInterface
+ DECLARE_XINTERFACE()
+
+ // XTypeProvider
+ DECLARE_XTYPEPROVIDER()
+
+ // XScript
+ virtual css::uno::Any SAL_CALL invoke(
+ const css::uno::Sequence< css::uno::Any >& aParams,
+ css::uno::Sequence< sal_Int16 >& aOutParamIndex,
+ css::uno::Sequence< css::uno::Any >& aOutParam ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // SfxListener
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+ };
+
+
+} // namespace basprov
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/dlgprov/DialogModelProvider.cxx b/scripting/source/dlgprov/DialogModelProvider.cxx
new file mode 100644
index 000000000..e49ed058d
--- /dev/null
+++ b/scripting/source/dlgprov/DialogModelProvider.cxx
@@ -0,0 +1,166 @@
+/* -*- 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 "DialogModelProvider.hxx"
+#include "dlgprov.hxx"
+#include <com/sun/star/resource/XStringResourceManager.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+
+#include <cppuhelper/supportsservice.hxx>
+
+/// anonymous implementation namespace
+namespace dlgprov {
+
+using namespace ::com::sun::star;
+using namespace awt;
+using namespace lang;
+using namespace uno;
+using namespace script;
+using namespace beans;
+
+
+DialogModelProvider::DialogModelProvider(Reference< XComponentContext > const & context) :
+ m_xContext(context)
+{}
+
+// lang::XInitialization:
+void SAL_CALL DialogModelProvider::initialize(const css::uno::Sequence< uno::Any > & aArguments)
+{
+ if ( aArguments.getLength() != 1 )
+ return;
+
+ OUString sURL;
+ if ( !( aArguments[ 0 ] >>= sURL ))
+ throw css::lang::IllegalArgumentException();
+ // Try any other URL with SimpleFileAccess
+ Reference< ucb::XSimpleFileAccess3 > xSFI = ucb::SimpleFileAccess::create(m_xContext);
+
+ try
+ {
+ Reference< io::XInputStream > xInput = xSFI->openFileRead( sURL );
+ Reference< resource::XStringResourceManager > xStringResourceManager;
+ if ( xInput.is() )
+ {
+ xStringResourceManager = dlgprov::lcl_getStringResourceManager(m_xContext,sURL);
+ Any aDialogSourceURLAny;
+ aDialogSourceURLAny <<= sURL;
+
+ Reference< frame::XModel > xModel;
+ m_xDialogModel.set( dlgprov::lcl_createDialogModel( m_xContext, xInput , xModel, xStringResourceManager, aDialogSourceURLAny ), UNO_SET_THROW);
+ m_xDialogModelProp.set(m_xDialogModel, UNO_QUERY_THROW);
+ }
+ }
+ catch( Exception& )
+ {}
+ //m_sURL = sURL;
+}
+
+// container::XElementAccess:
+uno::Type SAL_CALL DialogModelProvider::getElementType()
+{
+ return m_xDialogModel->getElementType();
+}
+
+sal_Bool SAL_CALL DialogModelProvider::hasElements()
+{
+ return m_xDialogModel->hasElements();
+}
+
+// container::XNameAccess:
+uno::Any SAL_CALL DialogModelProvider::getByName(const OUString & aName)
+{
+ return m_xDialogModel->getByName(aName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL DialogModelProvider::getElementNames()
+{
+ return m_xDialogModel->getElementNames();
+}
+
+sal_Bool SAL_CALL DialogModelProvider::hasByName(const OUString & aName)
+{
+ return m_xDialogModel->hasByName(aName);
+}
+
+// container::XNameReplace:
+void SAL_CALL DialogModelProvider::replaceByName(const OUString & aName, const uno::Any & aElement)
+{
+ m_xDialogModel->replaceByName(aName,aElement);
+}
+
+// container::XNameContainer:
+void SAL_CALL DialogModelProvider::insertByName(const OUString & aName, const uno::Any & aElement)
+{
+ m_xDialogModel->insertByName(aName,aElement);
+}
+
+void SAL_CALL DialogModelProvider::removeByName(const OUString & aName)
+{
+ m_xDialogModel->removeByName(aName);
+}
+uno::Reference< beans::XPropertySetInfo > SAL_CALL DialogModelProvider::getPropertySetInfo( )
+{
+ return m_xDialogModelProp->getPropertySetInfo();
+}
+void SAL_CALL DialogModelProvider::setPropertyValue( const OUString&, const uno::Any& )
+{
+}
+uno::Any SAL_CALL DialogModelProvider::getPropertyValue( const OUString& PropertyName )
+{
+ return m_xDialogModelProp->getPropertyValue(PropertyName);
+}
+void SAL_CALL DialogModelProvider::addPropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& )
+{
+}
+void SAL_CALL DialogModelProvider::removePropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& )
+{
+}
+void SAL_CALL DialogModelProvider::addVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >& )
+{
+}
+void SAL_CALL DialogModelProvider::removeVetoableChangeListener( const OUString& ,const uno::Reference< beans::XVetoableChangeListener >& )
+{
+}
+
+// com.sun.star.uno.XServiceInfo:
+OUString SAL_CALL DialogModelProvider::getImplementationName()
+{
+ return "com.sun.star.comp.scripting.DialogModelProvider";
+}
+
+sal_Bool SAL_CALL DialogModelProvider::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL DialogModelProvider::getSupportedServiceNames()
+{
+ return { "com.sun.star.awt.UnoControlDialogModelProvider" };
+}
+
+} // closing anonymous implementation namespace
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scripting_DialogModelProvider_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new dlgprov::DialogModelProvider(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/dlgprov/DialogModelProvider.hxx b/scripting/source/dlgprov/DialogModelProvider.hxx
new file mode 100644
index 000000000..d9a41ef64
--- /dev/null
+++ b/scripting/source/dlgprov/DialogModelProvider.hxx
@@ -0,0 +1,87 @@
+/* -*- 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 <cppuhelper/factory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+/// anonymous implementation namespace
+namespace dlgprov{
+
+class DialogModelProvider:
+ public ::cppu::WeakImplHelper<
+ css::lang::XInitialization,
+ css::container::XNameContainer,
+ css::beans::XPropertySet,
+ css::lang::XServiceInfo>
+{
+public:
+ explicit DialogModelProvider(css::uno::Reference< css::uno::XComponentContext > const & context);
+private:
+ // css::lang::XInitialization:
+ virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > & aArguments) override;
+
+ // css::container::XElementAccess:
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // css::container::XNameAccess:
+ virtual css::uno::Any SAL_CALL getByName(const OUString & aName) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override;
+ virtual sal_Bool SAL_CALL hasByName(const OUString & aName) override;
+
+ // css::container::XNameReplace:
+ virtual void SAL_CALL replaceByName(const OUString & aName, const css::uno::Any & aElement) override;
+
+ // css::container::XNameContainer:
+ virtual void SAL_CALL insertByName(const OUString & aName, const css::uno::Any & aElement) override;
+ virtual void SAL_CALL removeByName(const OUString & Name) override;
+
+ // css::lang::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;
+
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+private:
+ DialogModelProvider(const DialogModelProvider &) = delete;
+ DialogModelProvider& operator=(const DialogModelProvider &) = delete;
+
+ // destructor is private and will be called indirectly by the release call virtual ~DialogModelProvider() {}
+
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::container::XNameContainer> m_xDialogModel;
+ css::uno::Reference< css::beans::XPropertySet> m_xDialogModelProp;
+};
+} // closing anonymous implementation namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/dlgprov/dlgevtatt.cxx b/scripting/source/dlgprov/dlgevtatt.cxx
new file mode 100644
index 000000000..704518e07
--- /dev/null
+++ b/scripting/source/dlgprov/dlgevtatt.cxx
@@ -0,0 +1,658 @@
+/* -*- 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 "dlgevtatt.hxx"
+
+#include "dlgprov.hxx"
+
+#include <sfx2/strings.hrc>
+#include <sfx2/sfxresid.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/awt/XControlContainer.hpp>
+#include <com/sun/star/awt/XDialogEventHandler.hpp>
+#include <com/sun/star/awt/XContainerWindowEventHandler.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+#include <com/sun/star/script/XScriptEventsSupplier.hpp>
+#include <com/sun/star/script/provider/XScriptProvider.hpp>
+#include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
+#include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
+#include <com/sun/star/script/vba/XVBACompatibility.hpp>
+#include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
+#include <com/sun/star/reflection/XIdlMethod.hpp>
+#include <com/sun/star/beans/MethodConcept.hpp>
+#include <com/sun/star/beans/XMaterialHolder.hpp>
+
+#include <ooo/vba/XVBAToOOEventDescGen.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::reflection;
+
+
+namespace dlgprov
+{
+ namespace {
+
+ class DialogSFScriptListenerImpl : public DialogScriptListenerImpl
+ {
+ protected:
+ Reference< frame::XModel > m_xModel;
+ virtual void firing_impl( const script::ScriptEvent& aScriptEvent, uno::Any* pRet ) override;
+ public:
+ DialogSFScriptListenerImpl( const Reference< XComponentContext >& rxContext, const Reference< frame::XModel >& rxModel ) : DialogScriptListenerImpl( rxContext ), m_xModel( rxModel ) {}
+ };
+
+ class DialogLegacyScriptListenerImpl : public DialogSFScriptListenerImpl
+ {
+ protected:
+ virtual void firing_impl( const script::ScriptEvent& aScriptEvent, uno::Any* pRet ) override;
+ public:
+ DialogLegacyScriptListenerImpl( const Reference< XComponentContext >& rxContext, const Reference< frame::XModel >& rxModel ) : DialogSFScriptListenerImpl( rxContext, rxModel ){}
+ };
+
+ class DialogUnoScriptListenerImpl : public DialogSFScriptListenerImpl
+ {
+ Reference< awt::XControl > m_xControl;
+ Reference< XInterface > m_xHandler;
+ Reference< beans::XIntrospectionAccess > m_xIntrospectionAccess;
+ bool m_bDialogProviderMode;
+
+ virtual void firing_impl( const script::ScriptEvent& aScriptEvent, uno::Any* pRet ) override;
+
+ public:
+ DialogUnoScriptListenerImpl( const Reference< XComponentContext >& rxContext,
+ const Reference< frame::XModel >& rxModel,
+ const Reference< awt::XControl >& rxControl,
+ const Reference< XInterface >& rxHandler,
+ const Reference< beans::XIntrospectionAccess >& rxIntrospectionAccess,
+ bool bDialogProviderMode ); // false: ContainerWindowProvider mode
+
+ };
+
+ class DialogVBAScriptListenerImpl : public DialogScriptListenerImpl
+ {
+ protected:
+ OUString msDialogCodeName;
+ OUString msDialogLibName;
+ Reference< script::XScriptListener > mxListener;
+ virtual void firing_impl( const script::ScriptEvent& aScriptEvent, uno::Any* pRet ) override;
+ public:
+ DialogVBAScriptListenerImpl( const Reference< XComponentContext >& rxContext, const Reference< awt::XControl >& rxControl, const Reference< frame::XModel >& xModel, const OUString& sDialogLibName );
+ };
+
+ }
+
+ DialogVBAScriptListenerImpl::DialogVBAScriptListenerImpl( const Reference< XComponentContext >& rxContext, const Reference< awt::XControl >& rxControl, const Reference< frame::XModel >& xModel, const OUString& sDialogLibName ) : DialogScriptListenerImpl( rxContext ), msDialogLibName( sDialogLibName )
+ {
+ Reference< XMultiComponentFactory > xSMgr( m_xContext->getServiceManager() );
+ Sequence< Any > args(1);
+ if ( xSMgr.is() )
+ {
+ args.getArray()[0] <<= xModel;
+ mxListener.set( xSMgr->createInstanceWithArgumentsAndContext( "ooo.vba.EventListener", args, m_xContext ), UNO_QUERY );
+ }
+ if ( !rxControl.is() )
+ return;
+
+ try
+ {
+ Reference< XPropertySet > xProps( rxControl->getModel(), UNO_QUERY_THROW );
+ xProps->getPropertyValue("Name") >>= msDialogCodeName;
+ xProps.set( mxListener, UNO_QUERY_THROW );
+ xProps->setPropertyValue("Model", args[ 0 ] );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+
+ }
+
+ void DialogVBAScriptListenerImpl::firing_impl( const script::ScriptEvent& aScriptEvent, uno::Any* )
+ {
+ if ( !(aScriptEvent.ScriptType == "VBAInterop" && mxListener.is()) )
+ return;
+
+ ScriptEvent aScriptEventCopy( aScriptEvent );
+ aScriptEventCopy.ScriptCode = msDialogLibName + "." + msDialogCodeName;
+ try
+ {
+ mxListener->firing( aScriptEventCopy );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+ }
+
+
+ // DialogEventsAttacherImpl
+
+
+ DialogEventsAttacherImpl::DialogEventsAttacherImpl( const Reference< XComponentContext >& rxContext, const Reference< frame::XModel >& rxModel, const Reference< awt::XControl >& rxControl, const Reference< XInterface >& rxHandler, const Reference< beans::XIntrospectionAccess >& rxIntrospect, bool bProviderMode, const Reference< script::XScriptListener >& rxRTLListener, const OUString& sDialogLibName )
+ :mbUseFakeVBAEvents( false ), m_xContext( rxContext )
+ {
+ // key listeners by protocol when ScriptType = 'Script'
+ // otherwise key is the ScriptType e.g. StarBasic
+ if ( rxRTLListener.is() ) // set up handler for RTL_BASIC
+ listenersForTypes[ OUString("StarBasic") ] = rxRTLListener;
+ else
+ listenersForTypes[ OUString("StarBasic") ] = new DialogLegacyScriptListenerImpl( rxContext, rxModel );
+ // handler for Script & OUString("vnd.sun.star.UNO:")
+ listenersForTypes[ OUString("vnd.sun.star.UNO") ] = new DialogUnoScriptListenerImpl( rxContext, rxModel, rxControl, rxHandler, rxIntrospect, bProviderMode );
+ listenersForTypes[ OUString("vnd.sun.star.script") ] = new DialogSFScriptListenerImpl( rxContext, rxModel );
+
+ // determine the VBA compatibility mode from the Basic library container
+ try
+ {
+ uno::Reference< beans::XPropertySet > xModelProps( rxModel, uno::UNO_QUERY_THROW );
+ uno::Reference< script::vba::XVBACompatibility > xVBACompat(
+ xModelProps->getPropertyValue("BasicLibraries"), uno::UNO_QUERY_THROW );
+ mbUseFakeVBAEvents = xVBACompat->getVBACompatibilityMode();
+ }
+ catch( uno::Exception& )
+ {
+ }
+ if ( mbUseFakeVBAEvents )
+ listenersForTypes[ OUString("VBAInterop") ] = new DialogVBAScriptListenerImpl( rxContext, rxControl, rxModel, sDialogLibName );
+ }
+
+
+ DialogEventsAttacherImpl::~DialogEventsAttacherImpl()
+ {
+ }
+
+
+ Reference< script::XScriptListener > const &
+ DialogEventsAttacherImpl::getScriptListenerForKey( const OUString& sKey )
+ {
+ ListenerHash::iterator it = listenersForTypes.find( sKey );
+ if ( it == listenersForTypes.end() )
+ throw RuntimeException(); // more text info here please
+ return it->second;
+ }
+ Reference< XScriptEventsSupplier > DialogEventsAttacherImpl::getFakeVbaEventsSupplier( const Reference< XControl >& xControl, OUString const & sControlName )
+ {
+ Reference< XScriptEventsSupplier > xEventsSupplier;
+ Reference< XMultiComponentFactory > xSMgr( m_xContext->getServiceManager() );
+ if ( xSMgr.is() )
+ {
+ Reference< ooo::vba::XVBAToOOEventDescGen > xVBAToOOEvtDesc( xSMgr->createInstanceWithContext("ooo.vba.VBAToOOEventDesc", m_xContext ), UNO_QUERY );
+ if ( xVBAToOOEvtDesc.is() )
+ xEventsSupplier = xVBAToOOEvtDesc->getEventSupplier( xControl, sControlName );
+
+ }
+ return xEventsSupplier;
+ }
+
+
+ void DialogEventsAttacherImpl::attachEventsToControl( const Reference< XControl>& xControl, const Reference< XScriptEventsSupplier >& xEventsSupplier, const Any& Helper )
+ {
+ if ( !xEventsSupplier.is() )
+ return;
+
+ Reference< container::XNameContainer > xEventCont = xEventsSupplier->getEvents();
+
+ Reference< XControlModel > xControlModel = xControl->getModel();
+ if ( !xEventCont.is() )
+ return;
+
+ const Sequence< OUString > aNames = xEventCont->getElementNames();
+
+ for ( const OUString& rName : aNames )
+ {
+ ScriptEventDescriptor aDesc;
+
+ Any aElement = xEventCont->getByName( rName );
+ aElement >>= aDesc;
+ OUString sKey = aDesc.ScriptType;
+ if ( aDesc.ScriptType == "Script" || aDesc.ScriptType == "UNO" )
+ {
+ sal_Int32 nIndex = aDesc.ScriptCode.indexOf( ':' );
+ sKey = aDesc.ScriptCode.copy( 0, nIndex );
+ }
+ Reference< XAllListener > xAllListener =
+ new DialogAllListenerImpl( getScriptListenerForKey( sKey ), aDesc.ScriptType, aDesc.ScriptCode );
+
+ // try first to attach event to the ControlModel
+ bool bSuccess = false;
+ try
+ {
+ Reference< XEventListener > xListener_ = m_xEventAttacher->attachSingleEventListener(
+ xControlModel, xAllListener, Helper, aDesc.ListenerType,
+ aDesc.AddListenerParam, aDesc.EventMethod );
+
+ if ( xListener_.is() )
+ bSuccess = true;
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+
+ try
+ {
+ // if we had no success, try to attach to the control
+ if ( !bSuccess )
+ {
+ m_xEventAttacher->attachSingleEventListener(
+ xControl, xAllListener, Helper, aDesc.ListenerType,
+ aDesc.AddListenerParam, aDesc.EventMethod );
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+ }
+ }
+
+
+ void DialogEventsAttacherImpl::nestedAttachEvents( const Sequence< Reference< XInterface > >& Objects, const Any& Helper, OUString& sDialogCodeName )
+ {
+ for ( const Reference< XInterface >& rObject : Objects )
+ {
+ // We know that we have to do with instances of XControl.
+ // Otherwise this is not the right implementation for
+ // XScriptEventsAttacher and we have to give up.
+ Reference< XControl > xControl( rObject, UNO_QUERY );
+ Reference< XControlContainer > xControlContainer( xControl, UNO_QUERY );
+ Reference< XDialog > xDialog( xControl, UNO_QUERY );
+ if ( !xControl.is() )
+ throw IllegalArgumentException();
+
+ // get XEventsSupplier from control model
+ Reference< XControlModel > xControlModel = xControl->getModel();
+ Reference< XScriptEventsSupplier > xEventsSupplier( xControlModel, UNO_QUERY );
+ attachEventsToControl( xControl, xEventsSupplier, Helper );
+ if ( mbUseFakeVBAEvents )
+ {
+ xEventsSupplier.set( getFakeVbaEventsSupplier( xControl, sDialogCodeName ) );
+ Any newHelper(xControl );
+ attachEventsToControl( xControl, xEventsSupplier, newHelper );
+ }
+ if ( xControlContainer.is() && !xDialog.is() )
+ {
+ Sequence< Reference< XControl > > aControls = xControlContainer->getControls();
+ sal_Int32 nControlCount = aControls.getLength();
+
+ Sequence< Reference< XInterface > > aObjects( nControlCount );
+ Reference< XInterface >* pObjects2 = aObjects.getArray();
+ const Reference< XControl >* pControls = aControls.getConstArray();
+
+ for ( sal_Int32 i2 = 0; i2 < nControlCount; ++i2 )
+ {
+ pObjects2[i2].set( pControls[i2], UNO_QUERY );
+ }
+ nestedAttachEvents( aObjects, Helper, sDialogCodeName );
+ }
+ }
+ }
+
+
+ // XScriptEventsAttacher
+
+
+ void SAL_CALL DialogEventsAttacherImpl::attachEvents( const Sequence< Reference< XInterface > >& Objects,
+ const css::uno::Reference<css::script::XScriptListener>&,
+ const Any& Helper )
+ {
+ // get EventAttacher
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( !m_xEventAttacher.is() )
+ {
+ Reference< XMultiComponentFactory > xSMgr( m_xContext->getServiceManager() );
+ if ( !xSMgr.is() )
+ throw RuntimeException();
+
+ m_xEventAttacher.set( xSMgr->createInstanceWithContext(
+ "com.sun.star.script.EventAttacher", m_xContext ), UNO_QUERY );
+
+ if ( !m_xEventAttacher.is() )
+ throw ServiceNotRegisteredException();
+ }
+ }
+ OUString sDialogCodeName;
+ sal_Int32 nObjCount = Objects.getLength();
+ Reference< awt::XControl > xDlgControl( Objects[ nObjCount - 1 ], uno::UNO_QUERY ); // last object is the dialog
+ if ( xDlgControl.is() )
+ {
+ Reference< XPropertySet > xProps( xDlgControl->getModel(), UNO_QUERY );
+ try
+ {
+ xProps->getPropertyValue("Name") >>= sDialogCodeName;
+ }
+ catch( Exception& ){}
+ }
+ // go over all objects
+ nestedAttachEvents( Objects, Helper, sDialogCodeName );
+ }
+
+
+ // DialogAllListenerImpl
+
+
+ DialogAllListenerImpl::DialogAllListenerImpl( const Reference< XScriptListener >& rxListener,
+ const OUString& rScriptType, const OUString& rScriptCode )
+ :m_xScriptListener( rxListener )
+ ,m_sScriptType( rScriptType )
+ ,m_sScriptCode( rScriptCode )
+ {
+ }
+
+
+ DialogAllListenerImpl::~DialogAllListenerImpl()
+ {
+ }
+
+
+ void DialogAllListenerImpl::firing_impl( const AllEventObject& Event, Any* pRet )
+ {
+ ScriptEvent aScriptEvent;
+ aScriptEvent.Source = static_cast<OWeakObject *>(this); // get correct XInterface
+ aScriptEvent.ListenerType = Event.ListenerType;
+ aScriptEvent.MethodName = Event.MethodName;
+ aScriptEvent.Arguments = Event.Arguments;
+ aScriptEvent.Helper = Event.Helper;
+ aScriptEvent.ScriptType = m_sScriptType;
+ aScriptEvent.ScriptCode = m_sScriptCode;
+
+ if ( m_xScriptListener.is() )
+ {
+ if ( pRet )
+ *pRet = m_xScriptListener->approveFiring( aScriptEvent );
+ else
+ m_xScriptListener->firing( aScriptEvent );
+ }
+ }
+
+
+ // XEventListener
+
+
+ void DialogAllListenerImpl::disposing(const EventObject& )
+ {
+ }
+
+
+ // XAllListener
+
+
+ void DialogAllListenerImpl::firing( const AllEventObject& Event )
+ {
+ //::osl::MutexGuard aGuard( getMutex() );
+
+ firing_impl( Event, nullptr );
+ }
+
+
+ Any DialogAllListenerImpl::approveFiring( const AllEventObject& Event )
+ {
+ //::osl::MutexGuard aGuard( getMutex() );
+
+ Any aReturn;
+ firing_impl( Event, &aReturn );
+ return aReturn;
+ }
+
+
+ // DialogScriptListenerImpl
+
+
+ DialogUnoScriptListenerImpl::DialogUnoScriptListenerImpl( const Reference< XComponentContext >& rxContext,
+ const Reference< css::frame::XModel >& rxModel,
+ const Reference< css::awt::XControl >& rxControl,
+ const Reference< css::uno::XInterface >& rxHandler,
+ const Reference< css::beans::XIntrospectionAccess >& rxIntrospectionAccess,
+ bool bDialogProviderMode )
+ : DialogSFScriptListenerImpl( rxContext, rxModel )
+ ,m_xControl( rxControl )
+ ,m_xHandler( rxHandler )
+ ,m_xIntrospectionAccess( rxIntrospectionAccess )
+ ,m_bDialogProviderMode( bDialogProviderMode )
+ {
+ }
+
+
+ DialogScriptListenerImpl::~DialogScriptListenerImpl()
+ {
+ }
+
+
+ void DialogSFScriptListenerImpl::firing_impl( const ScriptEvent& aScriptEvent, Any* pRet )
+ {
+ try
+ {
+ Reference< provider::XScriptProvider > xScriptProvider;
+ if ( m_xModel.is() )
+ {
+ Reference< provider::XScriptProviderSupplier > xSupplier( m_xModel, UNO_QUERY );
+ OSL_ENSURE( xSupplier.is(), "DialogScriptListenerImpl::firing_impl: failed to get script provider supplier" );
+ if ( xSupplier.is() )
+ xScriptProvider.set( xSupplier->getScriptProvider() );
+ }
+ else
+ {
+ OSL_ASSERT( m_xContext.is() );
+ if ( m_xContext.is() )
+ {
+ Reference< provider::XScriptProviderFactory > xFactory =
+ provider::theMasterScriptProviderFactory::get( m_xContext );
+
+ Any aCtx;
+ aCtx <<= OUString("user");
+ xScriptProvider = xFactory->createScriptProvider( aCtx );
+ }
+ }
+
+ OSL_ENSURE( xScriptProvider.is(), "DialogScriptListenerImpl::firing_impl: failed to get script provider" );
+
+ if ( xScriptProvider.is() )
+ {
+ Reference< provider::XScript > xScript = xScriptProvider->getScript( aScriptEvent.ScriptCode );
+ OSL_ENSURE( xScript.is(), "DialogScriptListenerImpl::firing_impl: failed to get script" );
+
+ if ( xScript.is() )
+ {
+ Sequence< Any > aInParams;
+ Sequence< sal_Int16 > aOutParamsIndex;
+ Sequence< Any > aOutParams;
+
+ // get arguments for script
+ aInParams = aScriptEvent.Arguments;
+
+ Any aResult = xScript->invoke( aInParams, aOutParamsIndex, aOutParams );
+ if ( pRet )
+ *pRet = aResult;
+ }
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+ }
+
+ void DialogLegacyScriptListenerImpl::firing_impl( const ScriptEvent& aScriptEvent, Any* pRet )
+ {
+ OUString sScriptURL;
+ OUString sScriptCode( aScriptEvent.ScriptCode );
+
+ if ( aScriptEvent.ScriptType != "StarBasic" )
+ return;
+
+ // StarBasic script: convert ScriptCode to scriptURL
+ sal_Int32 nIndex = sScriptCode.indexOf( ':' );
+ if ( nIndex >= 0 && nIndex < sScriptCode.getLength() )
+ {
+ sScriptURL = OUString::Concat("vnd.sun.star.script:") +
+ sScriptCode.subView( nIndex + 1 ) +
+ "?language=Basic&location=" +
+ sScriptCode.subView( 0, nIndex );
+ }
+ ScriptEvent aSFScriptEvent( aScriptEvent );
+ aSFScriptEvent.ScriptCode = sScriptURL;
+ DialogSFScriptListenerImpl::firing_impl( aSFScriptEvent, pRet );
+ }
+
+ void DialogUnoScriptListenerImpl::firing_impl( const ScriptEvent& aScriptEvent, Any* pRet )
+ {
+ OUString aMethodName = aScriptEvent.ScriptCode.copy( strlen("vnd.sun.star.UNO:") );
+
+ const Any* pArguments = aScriptEvent.Arguments.getConstArray();
+ Any aEventObject = pArguments[0];
+
+ bool bHandled = false;
+ if( m_xHandler.is() )
+ {
+ if( m_bDialogProviderMode )
+ {
+ Reference< XDialogEventHandler > xDialogEventHandler( m_xHandler, UNO_QUERY );
+ if( xDialogEventHandler.is() )
+ {
+ Reference< XDialog > xDialog( m_xControl, UNO_QUERY );
+ bHandled = xDialogEventHandler->callHandlerMethod( xDialog, aEventObject, aMethodName );
+ }
+ }
+ else
+ {
+ Reference< XContainerWindowEventHandler > xContainerWindowEventHandler( m_xHandler, UNO_QUERY );
+ if( xContainerWindowEventHandler.is() )
+ {
+ Reference< XWindow > xWindow( m_xControl, UNO_QUERY );
+ bHandled = xContainerWindowEventHandler->callHandlerMethod( xWindow, aEventObject, aMethodName );
+ }
+ }
+ }
+
+ Any aRet;
+ if( !bHandled && m_xIntrospectionAccess.is() )
+ {
+ try
+ {
+ // call method
+ const Reference< XIdlMethod >& rxMethod = m_xIntrospectionAccess->
+ getMethod( aMethodName, MethodConcept::ALL - MethodConcept::DANGEROUS );
+
+ Reference< XMaterialHolder > xMaterialHolder =
+ Reference< XMaterialHolder >::query( m_xIntrospectionAccess );
+ Any aHandlerObject = xMaterialHolder->getMaterial();
+
+ Sequence< Reference< XIdlClass > > aParamTypeSeq = rxMethod->getParameterTypes();
+ sal_Int32 nParamCount = aParamTypeSeq.getLength();
+ if( nParamCount == 0 )
+ {
+ Sequence<Any> args;
+ rxMethod->invoke( aHandlerObject, args );
+ bHandled = true;
+ }
+ else if( nParamCount == 2 )
+ {
+ // Signature check automatically done by reflection
+ Sequence<Any> Args(2);
+ Any* pArgs = Args.getArray();
+ if( m_bDialogProviderMode )
+ {
+ Reference< XDialog > xDialog( m_xControl, UNO_QUERY );
+ pArgs[0] <<= xDialog;
+ }
+ else
+ {
+ Reference< XWindow > xWindow( m_xControl, UNO_QUERY );
+ pArgs[0] <<= xWindow;
+ }
+ pArgs[1] = aEventObject;
+ aRet = rxMethod->invoke( aHandlerObject, Args );
+ bHandled = true;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+ }
+
+ if( bHandled )
+ {
+ if( pRet )
+ *pRet = aRet;
+ }
+ else
+ {
+ OUString aRes(SfxResId(STR_ERRUNOEVENTBINDUNG));
+ OUString aQuoteChar( "\"" );
+
+ sal_Int32 nIndex = aRes.indexOf( '%' );
+
+ OUString aOUFinal =
+ aRes.subView( 0, nIndex ) +
+ aQuoteChar + aMethodName + aQuoteChar +
+ aRes.subView( nIndex + 2 );
+
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Warning, VclButtonsType::Ok, aOUFinal));
+ xBox->run();
+ }
+ }
+
+
+ // XEventListener
+
+
+ void DialogScriptListenerImpl::disposing(const EventObject& )
+ {
+ }
+
+
+ // XScriptListener
+
+
+ void DialogScriptListenerImpl::firing( const ScriptEvent& aScriptEvent )
+ {
+ //::osl::MutexGuard aGuard( getMutex() );
+
+ firing_impl( aScriptEvent, nullptr );
+ }
+
+
+ Any DialogScriptListenerImpl::approveFiring( const ScriptEvent& aScriptEvent )
+ {
+ //::osl::MutexGuard aGuard( getMutex() );
+
+ Any aReturn;
+ firing_impl( aScriptEvent, &aReturn );
+ return aReturn;
+ }
+
+
+} // namespace dlgprov
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/dlgprov/dlgevtatt.hxx b/scripting/source/dlgprov/dlgevtatt.hxx
new file mode 100644
index 000000000..239cb6530
--- /dev/null
+++ b/scripting/source/dlgprov/dlgevtatt.hxx
@@ -0,0 +1,130 @@
+/* -*- 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/script/XAllListener.hpp>
+#include <com/sun/star/script/XEventAttacher.hpp>
+#include <com/sun/star/script/XScriptEventsAttacher.hpp>
+#include <com/sun/star/script/XScriptListener.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/beans/XIntrospectionAccess.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/script/XScriptEventsSupplier.hpp>
+
+#include <unordered_map>
+
+namespace dlgprov
+{
+ typedef std::unordered_map< OUString,
+ css::uno::Reference< css::script::XScriptListener > > ListenerHash;
+
+ typedef ::cppu::WeakImplHelper<
+ css::script::XScriptEventsAttacher > DialogEventsAttacherImpl_BASE;
+
+
+ class DialogEventsAttacherImpl : public DialogEventsAttacherImpl_BASE
+ {
+ private:
+ bool mbUseFakeVBAEvents;
+ ListenerHash listenersForTypes;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::script::XEventAttacher > m_xEventAttacher;
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::script::XScriptListener > const & getScriptListenerForKey( const OUString& sScriptName );
+ css::uno::Reference< css::script::XScriptEventsSupplier > getFakeVbaEventsSupplier( const css::uno::Reference< css::awt::XControl>& xControl, OUString const & sCodeName );
+ void nestedAttachEvents( const css::uno::Sequence< css::uno::Reference< css::uno::XInterface > >& Objects, const css::uno::Any& Helper, OUString& sDialogCodeName );
+ void attachEventsToControl( const css::uno::Reference< css::awt::XControl>& xControl, const css::uno::Reference< css::script::XScriptEventsSupplier >& events, const css::uno::Any& Helper );
+ public:
+ DialogEventsAttacherImpl( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const css::uno::Reference< css::frame::XModel >& xModel,
+ const css::uno::Reference< css::awt::XControl >& xControl,
+ const css::uno::Reference< css::uno::XInterface >& xHandler,
+ const css::uno::Reference< css::beans::XIntrospectionAccess >& xIntrospect,
+ bool bProviderMode,
+ const css::uno::Reference< css::script::XScriptListener >& xRTLListener ,const OUString& sDialogLibName );
+ virtual ~DialogEventsAttacherImpl() override;
+
+ // XScriptEventsAttacher
+ virtual void SAL_CALL attachEvents( const css::uno::Sequence<
+ css::uno::Reference< css::uno::XInterface > >& Objects,
+ const css::uno::Reference<css::script::XScriptListener>&,
+ const css::uno::Any& Helper ) override;
+ };
+
+
+
+
+ typedef ::cppu::WeakImplHelper<
+ css::script::XAllListener > DialogAllListenerImpl_BASE;
+
+
+ class DialogAllListenerImpl : public DialogAllListenerImpl_BASE
+ {
+ private:
+ css::uno::Reference< css::script::XScriptListener > m_xScriptListener;
+ OUString m_sScriptType;
+ OUString m_sScriptCode;
+
+ void firing_impl( const css::script::AllEventObject& Event, css::uno::Any* pRet );
+
+ public:
+ DialogAllListenerImpl( const css::uno::Reference< css::script::XScriptListener >& rxListener,
+ const OUString& rScriptType, const OUString& rScriptCode );
+ virtual ~DialogAllListenerImpl() override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XAllListener
+ virtual void SAL_CALL firing( const css::script::AllEventObject& Event ) override;
+ virtual css::uno::Any SAL_CALL approveFiring( const css::script::AllEventObject& Event ) override;
+ };
+
+
+
+
+ typedef ::cppu::WeakImplHelper<
+ css::script::XScriptListener > DialogScriptListenerImpl_BASE;
+
+
+ class DialogScriptListenerImpl : public DialogScriptListenerImpl_BASE
+ {
+ protected:
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ virtual void firing_impl( const css::script::ScriptEvent& aScriptEvent, css::uno::Any* pRet ) = 0;
+ public:
+ explicit DialogScriptListenerImpl( const css::uno::Reference< css::uno::XComponentContext >& rxContext ) : m_xContext( rxContext ) {}
+ virtual ~DialogScriptListenerImpl() override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XScriptListener
+ virtual void SAL_CALL firing( const css::script::ScriptEvent& aScriptEvent ) override;
+ virtual css::uno::Any SAL_CALL approveFiring( const css::script::ScriptEvent& aScriptEvent ) override;
+ };
+
+
+} // namespace dlgprov
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/dlgprov/dlgprov.component b/scripting/source/dlgprov/dlgprov.component
new file mode 100644
index 000000000..35203afb8
--- /dev/null
+++ b/scripting/source/dlgprov/dlgprov.component
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.scripting.DialogProvider"
+ constructor="scripting_DialogProviderImpl_get_implementation">
+ <service name="com.sun.star.awt.ContainerWindowProvider"/>
+ <service name="com.sun.star.awt.DialogProvider"/>
+ <service name="com.sun.star.awt.DialogProvider2"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.scripting.DialogModelProvider"
+ constructor="scripting_DialogModelProvider_get_implementation">
+ <service name="com.sun.star.awt.UnoControlDialogModelProvider"/>
+ </implementation>
+</component>
diff --git a/scripting/source/dlgprov/dlgprov.cxx b/scripting/source/dlgprov/dlgprov.cxx
new file mode 100644
index 000000000..18815f499
--- /dev/null
+++ b/scripting/source/dlgprov/dlgprov.cxx
@@ -0,0 +1,702 @@
+/* -*- 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 "dlgprov.hxx"
+#include "dlgevtatt.hxx"
+#include <com/sun/star/awt/UnoControlDialog.hpp>
+#include <com/sun/star/awt/Toolkit.hpp>
+#include <com/sun/star/awt/XControlContainer.hpp>
+#include <com/sun/star/awt/XWindowPeer.hpp>
+#include <com/sun/star/beans/theIntrospection.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/XEmbeddedScripts.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/io/XInputStreamProvider.hpp>
+#include <com/sun/star/resource/XStringResourceSupplier.hpp>
+#include <com/sun/star/resource/XStringResourceManager.hpp>
+#include <com/sun/star/script/XLibraryContainer.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/uri/XUriReference.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
+#include <com/sun/star/uri/XVndSunStarExpandUrl.hpp>
+#include <com/sun/star/util/theMacroExpander.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <sfx2/app.hxx>
+#include <xmlscript/xmldlg_imexp.hxx>
+#include <tools/urlobj.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <util/MiscUtils.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+using namespace ::com::sun::star;
+using namespace awt;
+using namespace lang;
+using namespace uno;
+using namespace script;
+using namespace beans;
+using namespace document;
+using namespace ::sf_misc;
+
+namespace dlgprov
+{
+
+ Reference< resource::XStringResourceManager > lcl_getStringResourceManager(const Reference< XComponentContext >& i_xContext, std::u16string_view i_sURL)
+ {
+ INetURLObject aInetObj( i_sURL );
+ OUString aDlgName = aInetObj.GetBase();
+ aInetObj.removeSegment();
+ OUString aDlgLocation = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ css::lang::Locale aLocale = Application::GetSettings().GetUILanguageTag().getLocale();
+
+ Reference< task::XInteractionHandler > xDummyHandler;
+
+ Sequence<Any> aArgs{ Any(aDlgLocation),
+ Any(true), // bReadOnly
+ Any(aLocale),
+ Any(aDlgName),
+ Any(OUString()),
+ Any(xDummyHandler) };
+
+ Reference< XMultiComponentFactory > xSMgr_( i_xContext->getServiceManager(), UNO_SET_THROW );
+ // TODO: Ctor
+ Reference< resource::XStringResourceManager > xStringResourceManager( xSMgr_->createInstanceWithContext
+ ( "com.sun.star.resource.StringResourceWithLocation",
+ i_xContext ), UNO_QUERY );
+ if( xStringResourceManager.is() )
+ {
+ Reference< XInitialization > xInit( xStringResourceManager, UNO_QUERY );
+ if( xInit.is() )
+ xInit->initialize( aArgs );
+ }
+ return xStringResourceManager;
+ }
+ Reference< container::XNameContainer > lcl_createControlModel(const Reference< XComponentContext >& i_xContext)
+ {
+ Reference< XMultiComponentFactory > xSMgr_( i_xContext->getServiceManager(), UNO_SET_THROW );
+ Reference< container::XNameContainer > xControlModel( xSMgr_->createInstanceWithContext("com.sun.star.awt.UnoControlDialogModel", i_xContext ), UNO_QUERY_THROW );
+ return xControlModel;
+ }
+ Reference< container::XNameContainer > lcl_createDialogModel( const Reference< XComponentContext >& i_xContext,
+ const Reference< io::XInputStream >& xInput,
+ const Reference< frame::XModel >& xModel,
+ const Reference< resource::XStringResourceManager >& xStringResourceManager,
+ const Any &aDialogSourceURL)
+ {
+ Reference< container::XNameContainer > xDialogModel( lcl_createControlModel(i_xContext) );
+
+ Reference< beans::XPropertySet > xDlgPropSet( xDialogModel, UNO_QUERY );
+ xDlgPropSet->setPropertyValue( "DialogSourceURL", aDialogSourceURL );
+
+ // #TODO we really need to detect the source of the Dialog, is it
+ // the dialog. E.g. if the dialog was created from basic ( then we just
+ // can't tell where its from )
+ // If we are happy to always substitute the form model for the awt
+ // one then maybe the presence of a document model is enough to trigger
+ // swapping out the models ( or perhaps we only want to do this
+ // for vba mode ) there are a number of feasible and valid possibilities
+ ::xmlscript::importDialogModel( xInput, xDialogModel, i_xContext, xModel );
+
+ // Set resource property
+ if( xStringResourceManager.is() )
+ {
+ Reference< beans::XPropertySet > xDlgPSet( xDialogModel, UNO_QUERY );
+ Any aStringResourceManagerAny;
+ aStringResourceManagerAny <<= xStringResourceManager;
+ xDlgPSet->setPropertyValue( "ResourceResolver", aStringResourceManagerAny );
+ }
+
+ return xDialogModel;
+ }
+
+ // mutex
+
+
+ ::osl::Mutex& getMutex()
+ {
+ static ::osl::Mutex s_aMutex;
+
+ return s_aMutex;
+ }
+
+
+ // DialogProviderImpl
+
+
+ DialogProviderImpl::DialogProviderImpl( const Reference< XComponentContext >& rxContext )
+ :m_xContext( rxContext )
+ {
+ }
+
+
+ DialogProviderImpl::~DialogProviderImpl()
+ {
+ }
+
+
+ static Reference< resource::XStringResourceManager > getStringResourceFromDialogLibrary
+ ( const Reference< container::XNameContainer >& xDialogLib )
+ {
+ Reference< resource::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;
+ }
+
+ Reference< container::XNameContainer > DialogProviderImpl::createDialogModel(
+ const Reference< io::XInputStream >& xInput,
+ const Reference< resource::XStringResourceManager >& xStringResourceManager,
+ const Any &aDialogSourceURL)
+ {
+ return lcl_createDialogModel(m_xContext,xInput,m_xModel,xStringResourceManager,aDialogSourceURL);
+ }
+
+ Reference< XControlModel > DialogProviderImpl::createDialogModelForBasic()
+ {
+ if (!m_BasicInfo)
+ // shouldn't get here
+ throw RuntimeException("No information to create dialog" );
+ Reference< resource::XStringResourceManager > xStringResourceManager = getStringResourceFromDialogLibrary( m_BasicInfo->mxDlgLib );
+
+ Any aDialogSourceURL((OUString()));
+ Reference< XControlModel > xCtrlModel( createDialogModel( m_BasicInfo->mxInput, xStringResourceManager, aDialogSourceURL ), UNO_QUERY_THROW );
+ return xCtrlModel;
+ }
+
+ Reference< XControlModel > DialogProviderImpl::createDialogModel( const OUString& sURL )
+ {
+
+ OUString aURL( sURL );
+
+ // parse URL
+ // TODO: use URL parsing class
+ // TODO: decoding of location
+
+ Reference< uri::XUriReferenceFactory > xFac ( uri::UriReferenceFactory::create( m_xContext ) );
+
+ // i75778: Support non-script URLs
+ Reference< io::XInputStream > xInput;
+ Reference< container::XNameContainer > xDialogLib;
+
+ // Accept file URL to single dialog
+ bool bSingleDialog = false;
+
+ Reference< util::XMacroExpander > xMacroExpander =
+ util::theMacroExpander::get(m_xContext);
+
+ Reference< uri::XUriReference > uriRef;
+ for (;;)
+ {
+ uriRef = xFac->parse( aURL );
+ if ( !uriRef.is() )
+ {
+ OUString errorMsg = "DialogProviderImpl::getDialogModel: failed to parse URI: " + aURL;
+ throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 1 );
+ }
+ Reference < uri::XVndSunStarExpandUrl > sxUri( uriRef, UNO_QUERY );
+ if( !sxUri.is() )
+ break;
+
+ aURL = sxUri->expand( xMacroExpander );
+ }
+
+ Reference < uri::XVndSunStarScriptUrl > sfUri( uriRef, UNO_QUERY );
+ if( !sfUri.is() )
+ {
+ bSingleDialog = true;
+
+ // Try any other URL with SimpleFileAccess
+ Reference< ucb::XSimpleFileAccess3 > xSFI = ucb::SimpleFileAccess::create(m_xContext);
+
+ try
+ {
+ xInput = xSFI->openFileRead( aURL );
+ }
+ catch( Exception& )
+ {}
+ }
+ else
+ {
+ OUString sDescription = sfUri->getName();
+
+ sal_Int32 nIndex = 0;
+
+ OUString sLibName = sDescription.getToken( 0, '.', nIndex );
+ OUString sDlgName;
+ if ( nIndex != -1 )
+ sDlgName = sDescription.getToken( 0, '.', nIndex );
+
+ OUString sLocation = sfUri->getParameter( "location" );
+
+
+ // get dialog library container
+ // TODO: dialogs in packages
+ Reference< XLibraryContainer > xLibContainer;
+
+ if ( sLocation == "application" )
+ {
+ xLibContainer = SfxGetpApp()->GetDialogContainer();
+ }
+ else if ( sLocation == "document" )
+ {
+ Reference< XEmbeddedScripts > xDocumentScripts( m_xModel, UNO_QUERY );
+ if ( xDocumentScripts.is() )
+ {
+ xLibContainer = xDocumentScripts->getDialogLibraries();
+ OSL_ENSURE( xLibContainer.is(),
+ "DialogProviderImpl::createDialogModel: invalid dialog container!" );
+ }
+ }
+ else
+ {
+ const Sequence< OUString > aOpenDocsTdocURLs( MiscUtils::allOpenTDocUrls( m_xContext ) );
+ for ( auto const & tdocURL : aOpenDocsTdocURLs )
+ {
+ Reference< frame::XModel > xModel( MiscUtils::tDocUrlToModel( tdocURL ) );
+ OSL_ENSURE( xModel.is(), "DialogProviderImpl::createDialogModel: invalid document model!" );
+ if ( !xModel.is() )
+ continue;
+
+ OUString sDocURL = xModel->getURL();
+ if ( sDocURL.isEmpty() )
+ {
+ sDocURL = ::comphelper::NamedValueCollection::getOrDefault( xModel->getArgs(), u"Title", sDocURL );
+ }
+
+ if ( sLocation != sDocURL )
+ continue;
+
+ Reference< XEmbeddedScripts > xDocumentScripts( m_xModel, UNO_QUERY );
+ if ( !xDocumentScripts.is() )
+ continue;
+
+ xLibContainer = xDocumentScripts->getDialogLibraries();
+ OSL_ENSURE( xLibContainer.is(),
+ "DialogProviderImpl::createDialogModel: invalid dialog container!" );
+ }
+ }
+
+ // get input stream provider
+ Reference< io::XInputStreamProvider > xISP;
+ if ( !xLibContainer.is() )
+ {
+ throw IllegalArgumentException(
+ "DialogProviderImpl::getDialog: library container not found!",
+ Reference< XInterface >(), 1 );
+ }
+
+ // load dialog library
+ if ( !xLibContainer->isLibraryLoaded( sLibName ) )
+ xLibContainer->loadLibrary( sLibName );
+
+ // get dialog library
+ if ( xLibContainer->hasByName( sLibName ) )
+ {
+ Any aElement = xLibContainer->getByName( sLibName );
+ aElement >>= xDialogLib;
+ }
+
+ if ( !xDialogLib.is() )
+ {
+ throw IllegalArgumentException(
+ "DialogProviderImpl::getDialogModel: library not found!",
+ Reference< XInterface >(), 1 );
+ }
+
+ // get input stream provider
+ if ( xDialogLib->hasByName( sDlgName ) )
+ {
+ Any aElement = xDialogLib->getByName( sDlgName );
+ aElement >>= xISP;
+ }
+
+ if ( !xISP.is() )
+ {
+ throw IllegalArgumentException(
+ "DialogProviderImpl::getDialogModel: dialog not found!",
+ Reference< XInterface >(), 1 );
+ }
+
+
+
+ if ( xISP.is() )
+ xInput = xISP->createInputStream();
+ msDialogLibName = sLibName;
+ }
+
+ // import dialog model
+ Reference< XControlModel > xCtrlModel;
+ if ( xInput.is() && m_xContext.is() )
+ {
+ Reference< resource::XStringResourceManager > xStringResourceManager;
+ if( bSingleDialog )
+ {
+ xStringResourceManager = lcl_getStringResourceManager(m_xContext,aURL);
+ }
+ else if( xDialogLib.is() )
+ {
+ xStringResourceManager = getStringResourceFromDialogLibrary( xDialogLib );
+ }
+
+ Any aDialogSourceURLAny;
+ aDialogSourceURLAny <<= aURL;
+
+ Reference< container::XNameContainer > xDialogModel( createDialogModel( xInput , xStringResourceManager, aDialogSourceURLAny ), UNO_SET_THROW);
+
+ xCtrlModel.set( xDialogModel, UNO_QUERY );
+ }
+ return xCtrlModel;
+ }
+
+
+ Reference< XUnoControlDialog > DialogProviderImpl::createDialogControl
+ ( const Reference< XControlModel >& rxDialogModel, const Reference< XWindowPeer >& xParent )
+ {
+ OSL_ENSURE( rxDialogModel.is(), "DialogProviderImpl::getDialogControl: no dialog model" );
+
+ Reference< XUnoControlDialog > xDialogControl;
+
+ if ( m_xContext.is() )
+ {
+ xDialogControl = UnoControlDialog::create( m_xContext );
+
+ // set the model
+ if ( rxDialogModel.is() )
+ xDialogControl->setModel( rxDialogModel );
+
+ // set visible
+ xDialogControl->setVisible( false );
+
+ // get the parent of the dialog control
+ Reference< XWindowPeer > xPeer;
+ if( xParent.is() )
+ {
+ xPeer = xParent;
+ }
+ else if ( m_xModel.is() )
+ {
+ Reference< frame::XController > xController = m_xModel->getCurrentController();
+ if ( xController.is() )
+ {
+ Reference< frame::XFrame > xFrame = xController->getFrame();
+ if ( xFrame.is() )
+ xPeer.set( xFrame->getContainerWindow(), UNO_QUERY );
+ }
+ }
+
+ // create a peer
+ Reference< XToolkit> xToolkit( Toolkit::create( m_xContext ), UNO_QUERY_THROW );
+ xDialogControl->createPeer( xToolkit, xPeer );
+ }
+
+ return xDialogControl;
+ }
+
+
+ void DialogProviderImpl::attachControlEvents(
+ const Reference< XControl >& rxControl,
+ const Reference< XInterface >& rxHandler,
+ const Reference< XIntrospectionAccess >& rxIntrospectionAccess,
+ bool bDialogProviderMode )
+ {
+ if ( !rxControl.is() )
+ return;
+
+ Reference< XControlContainer > xControlContainer( rxControl, UNO_QUERY );
+
+ if ( !xControlContainer.is() )
+ return;
+
+ Sequence< Reference< XControl > > aControls = xControlContainer->getControls();
+ const Reference< XControl >* pControls = aControls.getConstArray();
+ sal_Int32 nControlCount = aControls.getLength();
+
+ Sequence< Reference< XInterface > > aObjects( nControlCount + 1 );
+ Reference< XInterface >* pObjects = aObjects.getArray();
+ for ( sal_Int32 i = 0; i < nControlCount; ++i )
+ {
+ pObjects[i].set( pControls[i], UNO_QUERY );
+ }
+
+ // also add the dialog control itself to the sequence
+ pObjects[nControlCount].set( rxControl, UNO_QUERY );
+
+ Reference<XScriptEventsAttacher> xScriptEventsAttacher
+ = new DialogEventsAttacherImpl(
+ m_xContext, m_xModel, rxControl, rxHandler, rxIntrospectionAccess,
+ bDialogProviderMode,
+ (m_BasicInfo ? m_BasicInfo->mxBasicRTLListener : nullptr), msDialogLibName);
+
+ Any aHelper;
+ xScriptEventsAttacher->attachEvents( aObjects, Reference< XScriptListener >(), aHelper );
+ }
+
+ Reference< XIntrospectionAccess > DialogProviderImpl::inspectHandler( const Reference< XInterface >& rxHandler )
+ {
+ Reference< XIntrospectionAccess > xIntrospectionAccess;
+ static Reference< XIntrospection > xIntrospection;
+
+ if( !rxHandler.is() )
+ return xIntrospectionAccess;
+
+ if( !xIntrospection.is() )
+ {
+ // Get introspection service
+ xIntrospection = theIntrospection::get( m_xContext );
+ }
+
+ // Do introspection
+ try
+ {
+ Any aHandlerAny;
+ aHandlerAny <<= rxHandler;
+ xIntrospectionAccess = xIntrospection->inspect( aHandlerAny );
+ }
+ catch( RuntimeException& )
+ {
+ xIntrospectionAccess.clear();
+ }
+ return xIntrospectionAccess;
+ }
+
+
+ // XServiceInfo
+
+
+ OUString DialogProviderImpl::getImplementationName( )
+ {
+ return "com.sun.star.comp.scripting.DialogProvider";
+ }
+
+ sal_Bool DialogProviderImpl::supportsService( const OUString& rServiceName )
+ {
+ return cppu::supportsService(this, rServiceName);
+ }
+
+ Sequence< OUString > DialogProviderImpl::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.awt.DialogProvider",
+ "com.sun.star.awt.DialogProvider2",
+ "com.sun.star.awt.ContainerWindowProvider" };
+ }
+
+
+ // XInitialization
+
+
+ void DialogProviderImpl::initialize( const Sequence< Any >& aArguments )
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( aArguments.getLength() == 1 )
+ {
+ aArguments[0] >>= m_xModel;
+
+ if ( !m_xModel.is() )
+ {
+ throw RuntimeException( "DialogProviderImpl::initialize: invalid argument format!" );
+ }
+ }
+ else if ( aArguments.getLength() == 4 )
+ {
+ // call from RTL_Impl_CreateUnoDialog
+ aArguments[0] >>= m_xModel;
+ m_BasicInfo.reset( new BasicRTLParams );
+ m_BasicInfo->mxInput.set( aArguments[ 1 ], UNO_QUERY_THROW );
+ // allow null mxDlgLib, a document dialog instantiated from
+ // from application basic is unable to provide ( or find ) it's
+ // Library
+ aArguments[ 2 ] >>= m_BasicInfo->mxDlgLib;
+ // leave the possibility to optionally allow the old dialog creation
+ // to use the new XScriptListener ( which converts the old style macro
+ // to a SF url )
+ m_BasicInfo->mxBasicRTLListener.set( aArguments[ 3 ], UNO_QUERY);
+ }
+ else if ( aArguments.getLength() > 4 )
+ {
+ throw RuntimeException( "DialogProviderImpl::initialize: invalid number of arguments!" );
+ }
+ }
+
+
+ // XDialogProvider
+
+
+ constexpr OUStringLiteral aDecorationPropName = u"Decoration";
+
+ Reference < XControl > DialogProviderImpl::createDialogImpl(
+ const OUString& URL, const Reference< XInterface >& xHandler,
+ const Reference< XWindowPeer >& xParent, bool bDialogProviderMode )
+ {
+ // if the dialog is located in a document, the document must already be open!
+
+ ::osl::MutexGuard aGuard( getMutex() );
+
+
+ // m_xHandler = xHandler;
+
+ //Reference< XDialog > xDialog;
+ Reference< XControl > xCtrl;
+ Reference< XControlModel > xCtrlMod;
+ try
+ {
+ // add support for basic RTL_FUNCTION
+ if (m_BasicInfo)
+ xCtrlMod = createDialogModelForBasic();
+ else
+ {
+ OSL_ENSURE( !URL.isEmpty(), "DialogProviderImpl::getDialog: no URL!" );
+ xCtrlMod = createDialogModel( URL );
+ }
+ }
+ catch ( const RuntimeException& ) { throw; }
+ catch ( const Exception& )
+ {
+ const Any aError( ::cppu::getCaughtException() );
+ throw WrappedTargetRuntimeException( OUString(), *this, aError );
+ }
+ if ( xCtrlMod.is() )
+ {
+ // i83963 Force decoration
+ if( bDialogProviderMode )
+ {
+ uno::Reference< beans::XPropertySet > xDlgModPropSet( xCtrlMod, uno::UNO_QUERY );
+ if( xDlgModPropSet.is() )
+ {
+ try
+ {
+ bool bDecoration = true;
+ Any aDecorationAny = xDlgModPropSet->getPropertyValue( aDecorationPropName );
+ aDecorationAny >>= bDecoration;
+ if( !bDecoration )
+ {
+ xDlgModPropSet->setPropertyValue( aDecorationPropName, Any( true ) );
+ xDlgModPropSet->setPropertyValue( "Title", Any( OUString() ) );
+ }
+ }
+ catch( UnknownPropertyException& )
+ {}
+ }
+ }
+
+ xCtrl.set( createDialogControl( xCtrlMod, xParent ) );
+ if ( xCtrl.is() )
+ {
+ Reference< XIntrospectionAccess > xIntrospectionAccess = inspectHandler( xHandler );
+ attachControlEvents( xCtrl, xHandler, xIntrospectionAccess, bDialogProviderMode );
+ }
+ }
+
+ return xCtrl;
+ }
+
+ Reference < XDialog > DialogProviderImpl::createDialog( const OUString& URL )
+ {
+ Reference< XInterface > xDummyHandler;
+ Reference< XWindowPeer > xDummyPeer;
+ Reference < XControl > xControl = DialogProviderImpl::createDialogImpl( URL, xDummyHandler, xDummyPeer, true );
+ Reference< XDialog > xDialog( xControl, UNO_QUERY );
+ return xDialog;
+ }
+
+ Reference < XDialog > DialogProviderImpl::createDialogWithHandler(
+ const OUString& URL, const Reference< XInterface >& xHandler )
+ {
+ if( !xHandler.is() )
+ {
+ throw IllegalArgumentException(
+ "DialogProviderImpl::createDialogWithHandler: Invalid xHandler!",
+ Reference< XInterface >(), 1 );
+ }
+ Reference< XWindowPeer > xDummyPeer;
+ Reference < XControl > xControl = DialogProviderImpl::createDialogImpl( URL, xHandler, xDummyPeer, true );
+ Reference< XDialog > xDialog( xControl, UNO_QUERY );
+ return xDialog;
+ }
+
+ Reference < XDialog > DialogProviderImpl::createDialogWithArguments(
+ const OUString& URL, const Sequence< NamedValue >& Arguments )
+ {
+ ::comphelper::NamedValueCollection aArguments( Arguments );
+
+ Reference< XWindowPeer > xParentPeer;
+ if ( aArguments.has( "ParentWindow" ) )
+ {
+ const Any& aParentWindow( aArguments.get( "ParentWindow" ) );
+ if ( !( aParentWindow >>= xParentPeer ) )
+ {
+ const Reference< XControl > xParentControl( aParentWindow, UNO_QUERY );
+ if ( xParentControl.is() )
+ xParentPeer = xParentControl->getPeer();
+ }
+ }
+
+ const Reference< XInterface > xHandler( aArguments.get( "EventHandler" ), UNO_QUERY );
+
+ Reference < XControl > xControl = DialogProviderImpl::createDialogImpl( URL, xHandler, xParentPeer, true );
+ Reference< XDialog > xDialog( xControl, UNO_QUERY );
+ return xDialog;
+ }
+
+ Reference< XWindow > DialogProviderImpl::createContainerWindow(
+ const OUString& URL, const OUString&,
+ const Reference< XWindowPeer >& xParent, const Reference< XInterface >& xHandler )
+ {
+ if( !xParent.is() )
+ {
+ throw IllegalArgumentException(
+ "DialogProviderImpl::createContainerWindow: Invalid xParent!",
+ Reference< XInterface >(), 1 );
+ }
+ Reference < XControl > xControl = DialogProviderImpl::createDialogImpl( URL, xHandler, xParent, false );
+ Reference< XWindow> xWindow( xControl, UNO_QUERY );
+ return xWindow;
+ }
+
+
+ // component operations
+
+
+ extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ scripting_DialogProviderImpl_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+ {
+ return cppu::acquire(new DialogProviderImpl(context));
+ }
+
+} // namespace dlgprov
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/dlgprov/dlgprov.hxx b/scripting/source/dlgprov/dlgprov.hxx
new file mode 100644
index 000000000..0a5d4483a
--- /dev/null
+++ b/scripting/source/dlgprov/dlgprov.hxx
@@ -0,0 +1,148 @@
+/* -*- 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/XControl.hpp>
+#include <com/sun/star/awt/XDialog.hpp>
+#include <com/sun/star/awt/XDialogProvider2.hpp>
+#include <com/sun/star/awt/XContainerWindowProvider.hpp>
+#include <com/sun/star/awt/XUnoControlDialog.hpp>
+#include <com/sun/star/beans/XIntrospectionAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/resource/XStringResourceManager.hpp>
+#include <com/sun/star/script/XScriptListener.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <osl/mutex.hxx>
+#include <memory>
+
+
+namespace dlgprov
+{
+
+
+ // mutex
+
+
+ ::osl::Mutex& getMutex();
+
+
+
+ css::uno::Reference< css::container::XNameContainer > lcl_createControlModel(const css::uno::Reference< css::uno::XComponentContext >& i_xContext);
+ css::uno::Reference< css::resource::XStringResourceManager > lcl_getStringResourceManager(const css::uno::Reference< css::uno::XComponentContext >& i_xContext, std::u16string_view i_sURL);
+ /// @throws css::uno::Exception
+ css::uno::Reference< css::container::XNameContainer > lcl_createDialogModel(
+ const css::uno::Reference< css::uno::XComponentContext >& i_xContext,
+ const css::uno::Reference< css::io::XInputStream >& xInput,
+ const css::uno::Reference< css::frame::XModel >& xModel,
+ const css::uno::Reference< css::resource::XStringResourceManager >& xStringResourceManager,
+ const css::uno::Any &aDialogSourceURL);
+
+ typedef ::cppu::WeakImplHelper<
+ css::lang::XServiceInfo,
+ css::lang::XInitialization,
+ css::awt::XDialogProvider2,
+ css::awt::XContainerWindowProvider > DialogProviderImpl_BASE;
+
+ class DialogProviderImpl : public DialogProviderImpl_BASE
+ {
+ private:
+ struct BasicRTLParams
+ {
+ css::uno::Reference< css::io::XInputStream > mxInput;
+ css::uno::Reference< css::container::XNameContainer > mxDlgLib;
+ css::uno::Reference< css::script::XScriptListener > mxBasicRTLListener;
+ };
+ std::unique_ptr< BasicRTLParams > m_BasicInfo;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::frame::XModel > m_xModel;
+
+ OUString msDialogLibName;
+ css::uno::Reference< css::awt::XControlModel > createDialogModel( const OUString& sURL );
+
+ css::uno::Reference< css::awt::XUnoControlDialog > createDialogControl(
+ const css::uno::Reference< css::awt::XControlModel >& rxDialogModel,
+ const css::uno::Reference< css::awt::XWindowPeer >& xParent );
+
+ void attachControlEvents( const css::uno::Reference< css::awt::XControl >& rxControlContainer,
+ const css::uno::Reference< css::uno::XInterface >& rxHandler,
+ const css::uno::Reference< css::beans::XIntrospectionAccess >& rxIntrospectionAccess,
+ bool bDialogProviderMode );
+ css::uno::Reference< css::beans::XIntrospectionAccess > inspectHandler(
+ const css::uno::Reference< css::uno::XInterface >& rxHandler );
+ // helper methods
+ /// @throws css::uno::Exception
+ css::uno::Reference< css::container::XNameContainer > createDialogModel(
+ const css::uno::Reference< css::io::XInputStream >& xInput,
+ const css::uno::Reference< css::resource::XStringResourceManager >& xStringResourceManager,
+ const css::uno::Any &aDialogSourceURL);
+ /// @throws css::uno::Exception
+ css::uno::Reference< css::awt::XControlModel > createDialogModelForBasic();
+
+ // XDialogProvider / XDialogProvider2 impl method
+ /// @throws css::lang::IllegalArgumentException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference < css::awt::XControl > createDialogImpl(
+ const OUString& URL,
+ const css::uno::Reference< css::uno::XInterface >& xHandler,
+ const css::uno::Reference< css::awt::XWindowPeer >& xParent,
+ bool bDialogProviderMode );
+
+ public:
+ explicit DialogProviderImpl(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+ virtual ~DialogProviderImpl() 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;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XDialogProvider
+ virtual css::uno::Reference < css::awt::XDialog > SAL_CALL createDialog(
+ const OUString& URL ) override;
+
+ // XDialogProvider2
+ virtual css::uno::Reference < css::awt::XDialog > SAL_CALL createDialogWithHandler(
+ const OUString& URL,
+ const css::uno::Reference< css::uno::XInterface >& xHandler ) override;
+
+ virtual css::uno::Reference < css::awt::XDialog > SAL_CALL createDialogWithArguments(
+ const OUString& URL,
+ const css::uno::Sequence< css::beans::NamedValue >& Arguments ) override;
+
+ virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createContainerWindow(
+ const OUString& URL, const OUString& WindowType,
+ const css::uno::Reference< css::awt::XWindowPeer >& xParent,
+ const css::uno::Reference< css::uno::XInterface >& xHandler ) override;
+ };
+
+
+} // namespace dlgprov
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/inc/bcholder.hxx b/scripting/source/inc/bcholder.hxx
new file mode 100644
index 000000000..9f8add31b
--- /dev/null
+++ b/scripting/source/inc/bcholder.hxx
@@ -0,0 +1,44 @@
+/* -*- 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 <osl/mutex.hxx>
+#include <cppuhelper/interfacecontainer.h>
+
+
+namespace scripting_helper
+{
+
+ class OBroadcastHelperHolder
+ {
+ ::cppu::OBroadcastHelper m_aBHelper;
+
+ public:
+ OBroadcastHelperHolder( ::osl::Mutex& rMutex ) : m_aBHelper( rMutex ) { }
+
+ ::cppu::OBroadcastHelper& GetBroadcastHelper() { return m_aBHelper; }
+ const ::cppu::OBroadcastHelper& GetBroadcastHelper() const { return m_aBHelper; }
+ };
+
+
+} // namespace scripting_helper
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/inc/util/MiscUtils.hxx b/scripting/source/inc/util/MiscUtils.hxx
new file mode 100644
index 000000000..2ba4492ab
--- /dev/null
+++ b/scripting/source/inc/util/MiscUtils.hxx
@@ -0,0 +1,138 @@
+/* -*- 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 <osl/diagnose.h>
+
+#include <ucbhelper/content.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/frame/XTransientDocumentsDocumentContentFactory.hpp>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <comphelper/processfactory.hxx>
+
+namespace sf_misc
+{
+
+class MiscUtils
+{
+public:
+
+static css::uno::Sequence< OUString > allOpenTDocUrls( const css::uno::Reference< css::uno::XComponentContext >& xCtx)
+{
+ css::uno::Sequence< OUString > result;
+ try
+ {
+ if ( !xCtx.is() )
+ {
+ return result;
+ }
+ css::uno::Reference < css::ucb::XSimpleFileAccess3 > xSFA( css::ucb::SimpleFileAccess::create(xCtx) );
+ result = xSFA->getFolderContents( "vnd.sun.star.tdoc:/", true );
+ }
+ catch ( css::uno::Exception& )
+ {
+ }
+ return result;
+}
+
+static OUString xModelToTdocUrl( const css::uno::Reference< css::frame::XModel >& xModel,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext )
+{
+ css::uno::Reference< css::lang::XMultiComponentFactory > xMCF(
+ xContext->getServiceManager() );
+ css::uno::Reference<
+ css::frame::XTransientDocumentsDocumentContentFactory > xDocFac;
+ try
+ {
+ xDocFac.set(xMCF->createInstanceWithContext(
+ "com.sun.star.frame.TransientDocumentsDocumentContentFactory",
+ xContext ),
+ css::uno::UNO_QUERY );
+ }
+ catch ( css::uno::Exception const & )
+ {
+ // handled below
+ }
+
+ if ( xDocFac.is() )
+ {
+ try
+ {
+ css::uno::Reference< css::ucb::XContent > xContent(
+ xDocFac->createDocumentContent( xModel ) );
+ return xContent->getIdentifier()->getContentIdentifier();
+ }
+ catch ( css::lang::IllegalArgumentException const & )
+ {
+ OSL_FAIL( "Invalid document model!" );
+ }
+ }
+
+ OSL_FAIL( "Unable to obtain URL for document model!" );
+ return OUString();
+}
+
+static css::uno::Reference< css::frame::XModel > tDocUrlToModel( const OUString& url )
+{
+ css::uno::Any result;
+
+ try
+ {
+ ::ucbhelper::Content root( url, nullptr, comphelper::getProcessComponentContext() );
+ result = getUCBProperty( root, "DocumentModel" );
+ }
+ catch ( css::ucb::ContentCreationException& )
+ {
+ // carry on, empty value will be returned
+ }
+ catch ( css::uno::RuntimeException& )
+ {
+ // carry on, empty value will be returned
+ }
+
+ css::uno::Reference< css::frame::XModel > xModel(
+ result, css::uno::UNO_QUERY );
+
+ return xModel;
+}
+
+
+static css::uno::Any getUCBProperty( ::ucbhelper::Content& content, OUString const & prop )
+{
+ css::uno::Any result;
+ try
+ {
+ result = content.getPropertyValue( prop );
+ }
+ catch ( css::uno::Exception& )
+ {
+ }
+ return result;
+}
+
+};
+} // namespace sf_misc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/protocolhandler/protocolhandler.component b/scripting/source/protocolhandler/protocolhandler.component
new file mode 100644
index 000000000..959c332c0
--- /dev/null
+++ b/scripting/source/protocolhandler/protocolhandler.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.ScriptProtocolHandler"
+ constructor="scripting_ScriptProtocolHandler_get_implementation">
+ <service name="com.sun.star.frame.ProtocolHandler"/>
+ </implementation>
+</component>
diff --git a/scripting/source/protocolhandler/scripthandler.cxx b/scripting/source/protocolhandler/scripthandler.cxx
new file mode 100644
index 000000000..08ec8d302
--- /dev/null
+++ b/scripting/source/protocolhandler/scripthandler.cxx
@@ -0,0 +1,436 @@
+/* -*- 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 "scripthandler.hxx"
+
+#include <com/sun/star/frame/DispatchResultEvent.hpp>
+#include <com/sun/star/frame/DispatchResultState.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+
+#include <com/sun/star/document/XEmbeddedScripts.hpp>
+#include <com/sun/star/document/XScriptInvocationContext.hpp>
+
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorException.hpp>
+#include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
+#include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
+
+#include <sfx2/objsh.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <framework/documentundoguard.hxx>
+#include <officecfg/Office/Common.hxx>
+
+#include <com/sun/star/uri/XUriReference.hpp>
+#include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::script::provider;
+using namespace ::com::sun::star::document;
+
+namespace scripting_protocolhandler
+{
+
+void SAL_CALL ScriptProtocolHandler::initialize(
+ const css::uno::Sequence < css::uno::Any >& aArguments )
+{
+ if ( m_bInitialised )
+ {
+ return ;
+ }
+
+ // first argument contains a reference to the frame (may be empty or the desktop,
+ // but usually it's a "real" frame)
+ if ( aArguments.hasElements() && !( aArguments[ 0 ] >>= m_xFrame ) )
+ {
+ throw RuntimeException( "ScriptProtocolHandler::initialize: could not extract reference to the frame" );
+ }
+
+ ENSURE_OR_THROW( m_xContext.is(), "ScriptProtocolHandler::initialize: No Service Manager available" );
+ m_bInitialised = true;
+}
+
+Reference< XDispatch > SAL_CALL ScriptProtocolHandler::queryDispatch(
+ const URL& aURL, const OUString&, sal_Int32 )
+{
+ Reference< XDispatch > xDispatcher;
+ // get scheme of url
+
+ Reference< uri::XUriReferenceFactory > xFac = uri::UriReferenceFactory::create( m_xContext );
+ Reference< uri::XUriReference > uriRef = xFac->parse( aURL.Complete );
+ if ( uriRef.is() )
+ {
+ if ( uriRef->getScheme() == "vnd.sun.star.script" )
+ {
+ xDispatcher = this;
+ }
+ }
+
+ return xDispatcher;
+}
+
+Sequence< Reference< XDispatch > > SAL_CALL
+ScriptProtocolHandler::queryDispatches(
+const Sequence < DispatchDescriptor >& seqDescriptor )
+{
+ sal_Int32 nCount = seqDescriptor.getLength();
+ Sequence< Reference< XDispatch > > lDispatcher( nCount );
+ std::transform(seqDescriptor.begin(), seqDescriptor.end(), lDispatcher.getArray(),
+ [this](const DispatchDescriptor& rDescr) -> Reference<XDispatch> {
+ return queryDispatch(rDescr.FeatureURL, rDescr.FrameName, rDescr.SearchFlags); });
+ return lDispatcher;
+}
+
+void SAL_CALL ScriptProtocolHandler::dispatchWithNotification(
+ const URL& aURL, const Sequence < PropertyValue >& lArgs,
+ const Reference< XDispatchResultListener >& xListener )
+{
+ if (officecfg::Office::Common::Security::Scripting::DisableMacrosExecution::get())
+ return;
+
+ bool bSuccess = false;
+ Any invokeResult;
+ bool bCaughtException = false;
+ Any aException;
+
+ if ( m_bInitialised )
+ {
+ try
+ {
+ css::uno::Reference<css::uri::XUriReferenceFactory> urifac(
+ css::uri::UriReferenceFactory::create(m_xContext));
+ css::uno::Reference<css::uri::XVndSunStarScriptUrlReference> uri(
+ urifac->parse(aURL.Complete), css::uno::UNO_QUERY_THROW);
+ auto const loc = uri->getParameter("location");
+ bool bIsDocumentScript = loc == "document";
+
+ if ( bIsDocumentScript )
+ {
+ // obtain the component for our security check
+ Reference< XEmbeddedScripts > xDocumentScripts;
+ if ( getScriptInvocation() )
+ xDocumentScripts.set( m_xScriptInvocation->getScriptContainer(), UNO_SET_THROW );
+
+ OSL_ENSURE( xDocumentScripts.is(), "ScriptProtocolHandler::dispatchWithNotification: can't do the security check!" );
+ if ( !xDocumentScripts.is() || !xDocumentScripts->getAllowMacroExecution() )
+ {
+ if ( xListener.is() )
+ {
+ css::frame::DispatchResultEvent aEvent(
+ static_cast< ::cppu::OWeakObject* >( this ),
+ css::frame::DispatchResultState::FAILURE,
+ invokeResult );
+ try
+ {
+ xListener->dispatchFinished( aEvent ) ;
+ }
+ catch(const RuntimeException &)
+ {
+ TOOLS_WARN_EXCEPTION("scripting",
+ "ScriptProtocolHandler::dispatchWithNotification: caught RuntimeException"
+ "while dispatchFinished with failure of the execution");
+ }
+ }
+ return;
+ }
+ }
+
+ // Creates a ScriptProvider ( if one is not created already )
+ createScriptProvider();
+
+ Reference< provider::XScript > xFunc =
+ m_xScriptProvider->getScript( aURL.Complete );
+ ENSURE_OR_THROW( xFunc.is(),
+ "ScriptProtocolHandler::dispatchWithNotification: validate xFunc - unable to obtain XScript interface" );
+
+
+ Sequence< Any > inArgs;
+ Sequence< Any > outArgs;
+ Sequence< sal_Int16 > outIndex;
+
+ if ( lArgs.hasElements() )
+ {
+ int argCount = 0;
+ for ( const auto& rArg : lArgs )
+ {
+ // Sometimes we get a propertyval with name = "Referer" or "SynchronMode". These
+ // are not actual arguments to be passed to script, but flags describing the
+ // call, so ignore. Who thought that passing such "meta-arguments" mixed in with
+ // real arguments was a good idea?
+ if ( (rArg.Name != "Referer" &&
+ rArg.Name != "SynchronMode") ||
+ rArg.Name.isEmpty() ) //TODO:???
+ {
+ inArgs.realloc( ++argCount );
+ inArgs.getArray()[ argCount - 1 ] = rArg.Value;
+ }
+ }
+ }
+
+ // attempt to protect the document against the script tampering with its Undo Context
+ std::unique_ptr< ::framework::DocumentUndoGuard > pUndoGuard;
+ if ( bIsDocumentScript )
+ pUndoGuard.reset( new ::framework::DocumentUndoGuard( m_xScriptInvocation ) );
+
+ bSuccess = false;
+ while ( !bSuccess )
+ {
+ std::exception_ptr aFirstCaughtException;
+ try
+ {
+ invokeResult = xFunc->invoke( inArgs, outIndex, outArgs );
+ bSuccess = true;
+ }
+ catch( const provider::ScriptFrameworkErrorException& se )
+ {
+ if (!aFirstCaughtException)
+ aFirstCaughtException = std::current_exception();
+
+ if ( se.errorType != provider::ScriptFrameworkErrorType::NO_SUCH_SCRIPT )
+ // the only condition which allows us to retry is if there is no method with the
+ // given name/signature
+ std::rethrow_exception(aFirstCaughtException);
+
+ if ( !inArgs.hasElements() )
+ // no chance to retry if we can't strip more in-args
+ std::rethrow_exception(aFirstCaughtException);
+
+ // strip one argument, then retry
+ inArgs.realloc( inArgs.getLength() - 1 );
+ }
+ }
+ }
+ // Office doesn't handle exceptions rethrown here very well, it cores,
+ // all we can is log them and then set fail for the dispatch event!
+ // (if there is a listener of course)
+ catch ( const Exception & e )
+ {
+ aException = ::cppu::getCaughtException();
+
+ invokeResult <<= "ScriptProtocolHandler::dispatch: caught "
+ + aException.getValueTypeName() + ": " + e.Message;
+
+ bCaughtException = true;
+ }
+ }
+ else
+ {
+ invokeResult <<= OUString(
+ "ScriptProtocolHandler::dispatchWithNotification failed, ScriptProtocolHandler not initialised"
+ );
+ }
+
+ if ( bCaughtException )
+ {
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ pFact->ShowAsyncScriptErrorDialog( nullptr, aException );
+ }
+
+ if ( !xListener.is() )
+ return;
+
+ // always call dispatchFinished(), because we didn't load a document but
+ // executed a macro instead!
+ css::frame::DispatchResultEvent aEvent;
+
+ aEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
+ aEvent.Result = invokeResult;
+ if ( bSuccess )
+ {
+ aEvent.State = css::frame::DispatchResultState::SUCCESS;
+ }
+ else
+ {
+ aEvent.State = css::frame::DispatchResultState::FAILURE;
+ }
+
+ try
+ {
+ xListener->dispatchFinished( aEvent ) ;
+ }
+ catch(const RuntimeException &)
+ {
+ TOOLS_WARN_EXCEPTION("scripting",
+ "ScriptProtocolHandler::dispatchWithNotification: caught RuntimeException"
+ "while dispatchFinished" );
+ }
+}
+
+void SAL_CALL ScriptProtocolHandler::dispatch(
+const URL& aURL, const Sequence< PropertyValue >& lArgs )
+{
+ dispatchWithNotification( aURL, lArgs, Reference< XDispatchResultListener >() );
+}
+
+void SAL_CALL ScriptProtocolHandler::addStatusListener(
+const Reference< XStatusListener >&, const URL& )
+{
+ // implement if status is supported
+}
+
+void SAL_CALL ScriptProtocolHandler::removeStatusListener(
+const Reference< XStatusListener >&, const URL& )
+{}
+
+bool
+ScriptProtocolHandler::getScriptInvocation()
+{
+ if ( !m_xScriptInvocation.is() && m_xFrame.is() )
+ {
+ Reference< XController > xController = m_xFrame->getController();
+ if ( xController .is() )
+ {
+ // try to obtain an XScriptInvocationContext interface, preferred from the
+ // mode, then from the controller
+ if ( !m_xScriptInvocation.set( xController->getModel(), UNO_QUERY ) )
+ m_xScriptInvocation.set( xController, UNO_QUERY );
+ }
+ else
+ {
+ if ( m_xFrame.is() )
+ {
+ SfxFrame* pFrame = nullptr;
+ for ( pFrame = SfxFrame::GetFirst(); pFrame; pFrame = SfxFrame::GetNext( *pFrame ) )
+ {
+ if ( pFrame->GetFrameInterface() == m_xFrame )
+ break;
+ }
+ if (SfxObjectShell* pDocShell = pFrame ? pFrame->GetCurrentDocument() : SfxObjectShell::Current())
+ {
+ Reference< XModel > xModel( pDocShell->GetModel() );
+ m_xScriptInvocation.set( xModel, UNO_QUERY );
+ }
+ }
+ }
+ }
+ return m_xScriptInvocation.is();
+}
+
+void ScriptProtocolHandler::createScriptProvider()
+{
+ if ( m_xScriptProvider.is() )
+ return;
+
+ try
+ {
+ // first, ask the component supporting the XScriptInvocationContext interface
+ // (if there is one) for a script provider
+ if ( getScriptInvocation() )
+ {
+ Reference< XScriptProviderSupplier > xSPS( m_xScriptInvocation, UNO_QUERY );
+ if ( xSPS.is() )
+ m_xScriptProvider = xSPS->getScriptProvider();
+ }
+
+ // second, ask the model in our frame
+ if ( !m_xScriptProvider.is() && m_xFrame.is() )
+ {
+ Reference< XController > xController = m_xFrame->getController();
+ if ( xController .is() )
+ {
+ Reference< XScriptProviderSupplier > xSPS( xController->getModel(), UNO_QUERY );
+ if ( xSPS.is() )
+ m_xScriptProvider = xSPS->getScriptProvider();
+ }
+ }
+
+
+ // as a fallback, ask the controller
+ if ( !m_xScriptProvider.is() && m_xFrame.is() )
+ {
+ Reference< XScriptProviderSupplier > xSPS( m_xFrame->getController(), UNO_QUERY );
+ if ( xSPS.is() )
+ m_xScriptProvider = xSPS->getScriptProvider();
+ }
+
+ // if nothing of this is successful, use the master script provider
+ if ( !m_xScriptProvider.is() )
+ {
+ Reference< provider::XScriptProviderFactory > xFac =
+ provider::theMasterScriptProviderFactory::get( m_xContext );
+
+ Any aContext;
+ if ( getScriptInvocation() )
+ aContext <<= m_xScriptInvocation;
+ m_xScriptProvider.set( xFac->createScriptProvider( aContext ), UNO_SET_THROW );
+ }
+ }
+ catch ( const Exception & e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "ScriptProtocolHandler::createScriptProvider: " + e.Message,
+ nullptr, anyEx );
+ }
+}
+
+ScriptProtocolHandler::ScriptProtocolHandler( const Reference< css::uno::XComponentContext > & xContext )
+ : m_bInitialised( false ), m_xContext( xContext )
+{
+}
+
+ScriptProtocolHandler::~ScriptProtocolHandler()
+{
+}
+
+/* XServiceInfo */
+OUString SAL_CALL ScriptProtocolHandler::getImplementationName( )
+{
+ return "com.sun.star.comp.ScriptProtocolHandler";
+}
+
+/* XServiceInfo */
+sal_Bool SAL_CALL ScriptProtocolHandler::supportsService(const OUString& sServiceName )
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+/* XServiceInfo */
+Sequence< OUString > SAL_CALL ScriptProtocolHandler::getSupportedServiceNames()
+{
+ return {"com.sun.star.frame.ProtocolHandler"};
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scripting_ScriptProtocolHandler_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ScriptProtocolHandler(context));
+}
+
+} // namespace scripting_protocolhandler
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/protocolhandler/scripthandler.hxx b/scripting/source/protocolhandler/scripthandler.hxx
new file mode 100644
index 000000000..74667b5a4
--- /dev/null
+++ b/scripting/source/protocolhandler/scripthandler.hxx
@@ -0,0 +1,114 @@
+/* -*- 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/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XNotifyingDispatch.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/script/provider/XScriptProvider.hpp>
+
+
+namespace com::sun::star {
+
+ namespace document {
+ class XScriptInvocationContext;
+ }
+ namespace uno {
+ class Any;
+ class XComponentContext;
+ }
+ namespace lang {
+ class XMultiServiceFactory;
+ class XSingleServiceFactory;
+ }
+ namespace frame {
+ class XFrame;
+ class XDispatch;
+ class XNotifyingDispatch;
+ class XDispatchResultListener;
+ struct DispatchDescriptor;
+ }
+ namespace beans {
+ struct PropertyValue;
+ }
+ namespace util {
+ struct URL;
+ }
+}
+
+namespace scripting_protocolhandler
+{
+
+class ScriptProtocolHandler :
+public ::cppu::WeakImplHelper< css::frame::XDispatchProvider,
+ css::frame::XNotifyingDispatch, css::lang::XServiceInfo, css::lang::XInitialization >
+{
+private:
+ bool m_bInitialised;
+ css::uno::Reference < css::uno::XComponentContext > m_xContext;
+ css::uno::Reference < css::frame::XFrame > m_xFrame;
+ css::uno::Reference < css::script::provider::XScriptProvider > m_xScriptProvider;
+ css::uno::Reference< css::document::XScriptInvocationContext > m_xScriptInvocation;
+
+ void createScriptProvider();
+ bool getScriptInvocation();
+
+public:
+ explicit ScriptProtocolHandler( const css::uno::Reference < css::uno::XComponentContext >& xContext );
+ virtual ~ScriptProtocolHandler() override;
+
+ /* XServiceInfo */
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& sServiceName ) override;
+ virtual css::uno::Sequence < OUString > SAL_CALL getSupportedServiceNames() override;
+
+ /* Implementation for XDispatchProvider */
+ virtual css::uno::Reference < css::frame::XDispatch > SAL_CALL
+ queryDispatch( const css::util::URL& aURL, const OUString& sTargetFrameName,
+ sal_Int32 eSearchFlags ) override ;
+ virtual css::uno::Sequence< css::uno::Reference < css::frame::XDispatch > > SAL_CALL
+ queryDispatches(
+ const css::uno::Sequence < css::frame::DispatchDescriptor >& seqDescriptor ) override;
+
+ /* Implementation for X(Notifying)Dispatch */
+ virtual void SAL_CALL dispatchWithNotification(
+ const css::util::URL& aURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArgs,
+ const css::uno::Reference< css::frame::XDispatchResultListener >& Listener ) override;
+ virtual void SAL_CALL dispatch(
+ const css::util::URL& aURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArgs ) override;
+ virtual void SAL_CALL addStatusListener(
+ const css::uno::Reference< css::frame::XStatusListener >& xControl,
+ const css::util::URL& aURL ) override;
+ virtual void SAL_CALL removeStatusListener(
+ const css::uno::Reference< css::frame::XStatusListener >& xControl,
+ const css::util::URL& aURL ) override;
+
+ /* Implementation for XInitialization */
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence < css::uno::Any >& aArguments ) override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/ActiveMSPList.cxx b/scripting/source/provider/ActiveMSPList.cxx
new file mode 100644
index 000000000..c073c73b7
--- /dev/null
+++ b/scripting/source/provider/ActiveMSPList.cxx
@@ -0,0 +1,297 @@
+/* -*- 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 <cppuhelper/exc_hlp.hxx>
+#include <util/MiscUtils.hxx>
+
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+
+#include "ActiveMSPList.hxx"
+
+#include <tools/diagnose_ex.h>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::script;
+using namespace ::sf_misc;
+
+namespace func_provider
+{
+
+ActiveMSPList::ActiveMSPList( const Reference< XComponentContext > & xContext ) : m_xContext( xContext )
+{
+ userDirString = "user";
+ shareDirString = "share";
+ bundledDirString = "bundled";
+}
+
+ActiveMSPList::~ActiveMSPList()
+{
+}
+
+Reference< provider::XScriptProvider >
+ActiveMSPList::createNewMSP( const uno::Any& context )
+{
+ Sequence< Any > args( &context, 1 );
+
+ Reference< provider::XScriptProvider > msp(
+ m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.script.provider.MasterScriptProvider", args, m_xContext ), UNO_QUERY );
+ return msp;
+}
+
+class NonDocMSPCreator
+{
+public:
+ explicit NonDocMSPCreator(ActiveMSPList *pList)
+ {
+ pList->createNonDocMSPs();
+ }
+};
+
+namespace
+{
+ //thread-safe double-locked class to ensure createNonDocMSPs is called once
+ class theNonDocMSPCreator : public rtl::StaticWithArg<NonDocMSPCreator, ActiveMSPList*, theNonDocMSPCreator> {};
+
+ void ensureNonDocMSPs(ActiveMSPList *pList)
+ {
+ theNonDocMSPCreator::get(pList);
+ }
+}
+
+Reference< provider::XScriptProvider >
+ActiveMSPList::getMSPFromAnyContext( const Any& aContext )
+{
+ Reference< provider::XScriptProvider > msp;
+ OUString sContext;
+ if ( aContext >>= sContext )
+ {
+ msp = getMSPFromStringContext( sContext );
+ return msp;
+ }
+
+ Reference< frame::XModel > xModel( aContext, UNO_QUERY );
+
+ Reference< document::XScriptInvocationContext > xScriptContext( aContext, UNO_QUERY );
+ if ( xScriptContext.is() )
+ {
+ try
+ {
+ // the component supports executing scripts embedded in a - possibly foreign document.
+ // Check whether this other document it's the component itself.
+ if ( !xModel.is() || ( xModel != xScriptContext->getScriptContainer() ) )
+ {
+ msp = getMSPFromInvocationContext( xScriptContext );
+ return msp;
+ }
+ }
+ catch( const lang::IllegalArgumentException& )
+ {
+ xModel.set( Reference< frame::XModel >() );
+ }
+ }
+
+ if ( xModel.is() )
+ {
+ sContext = MiscUtils::xModelToTdocUrl( xModel, m_xContext );
+ msp = getMSPFromStringContext( sContext );
+ return msp;
+ }
+
+ ensureNonDocMSPs(this);
+ return m_hMsps[ shareDirString ];
+}
+
+Reference< provider::XScriptProvider >
+ ActiveMSPList::getMSPFromInvocationContext( const Reference< document::XScriptInvocationContext >& xContext )
+{
+ Reference< provider::XScriptProvider > msp;
+
+ Reference< document::XEmbeddedScripts > xScripts;
+ if ( xContext.is() )
+ xScripts.set( xContext->getScriptContainer() );
+ if ( !xScripts.is() )
+ {
+ throw lang::IllegalArgumentException(
+ "Failed to create MasterScriptProvider for ScriptInvocationContext: "
+ "Component supporting XEmbeddScripts interface not found.",
+ nullptr, 1 );
+ }
+
+ ::osl::MutexGuard guard( m_mutex );
+
+ Reference< XInterface > xNormalized( xContext, UNO_QUERY );
+ ScriptComponent_map::const_iterator pos = m_mScriptComponents.find( xNormalized );
+ if ( pos == m_mScriptComponents.end() )
+ {
+ // TODO
+ msp = createNewMSP( uno::Any( xContext ) );
+ addActiveMSP( xNormalized, msp );
+ }
+ else
+ {
+ msp = pos->second;
+ }
+
+ return msp;
+}
+
+Reference< provider::XScriptProvider >
+ ActiveMSPList::getMSPFromStringContext( const OUString& context )
+{
+ Reference< provider::XScriptProvider > msp;
+ try
+ {
+ if ( context.startsWith( "vnd.sun.star.tdoc" ) )
+ {
+ Reference< frame::XModel > xModel( MiscUtils::tDocUrlToModel( context ) );
+
+ Reference< document::XEmbeddedScripts > xScripts( xModel, UNO_QUERY );
+ Reference< document::XScriptInvocationContext > xScriptsContext( xModel, UNO_QUERY );
+ if ( !xScripts.is() && !xScriptsContext.is() )
+ {
+ throw lang::IllegalArgumentException(
+ "Failed to create MasterScriptProvider for '"
+ + context +
+ "': Either XEmbeddScripts or XScriptInvocationContext need to be supported by the document.",
+ nullptr, 1 );
+ }
+
+ ::osl::MutexGuard guard( m_mutex );
+ Reference< XInterface > xNormalized( xModel, UNO_QUERY );
+ ScriptComponent_map::const_iterator pos = m_mScriptComponents.find( xNormalized );
+ if ( pos == m_mScriptComponents.end() )
+ {
+ msp = createNewMSP( context );
+ addActiveMSP( xNormalized, msp );
+ }
+ else
+ {
+ msp = pos->second;
+ }
+ }
+ else
+ {
+ ::osl::MutexGuard guard( m_mutex );
+ Msp_hash::iterator h_itEnd = m_hMsps.end();
+ Msp_hash::const_iterator itr = m_hMsps.find( context );
+ if ( itr == h_itEnd )
+ {
+ msp = createNewMSP( context );
+ m_hMsps[ context ] = msp;
+ }
+ else
+ {
+ msp = m_hMsps[ context ];
+ }
+ }
+ }
+ catch( const lang::IllegalArgumentException& )
+ {
+ // allowed to leave
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave
+ }
+ catch( const Exception& )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException(
+ "Failed to create MasterScriptProvider for context '"
+ + context + "'.",
+ *this, anyEx );
+ }
+ return msp;
+}
+
+void
+ActiveMSPList::addActiveMSP( const Reference< uno::XInterface >& xComponent,
+ const Reference< provider::XScriptProvider >& msp )
+{
+ ::osl::MutexGuard guard( m_mutex );
+ Reference< XInterface > xNormalized( xComponent, UNO_QUERY );
+ ScriptComponent_map::const_iterator pos = m_mScriptComponents.find( xNormalized );
+ if ( pos != m_mScriptComponents.end() )
+ return;
+
+ m_mScriptComponents[ xNormalized ] = msp;
+
+ // add self as listener for component disposal
+ // should probably throw from this method!!, reexamine
+ try
+ {
+ Reference< lang::XComponent > xBroadcaster( xComponent, UNO_QUERY_THROW );
+ xBroadcaster->addEventListener( this );
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+}
+
+
+void SAL_CALL ActiveMSPList::disposing( const css::lang::EventObject& Source )
+
+{
+ try
+ {
+ Reference< XInterface > xNormalized( Source.Source, UNO_QUERY );
+ if ( xNormalized.is() )
+ {
+ ::osl::MutexGuard guard( m_mutex );
+ ScriptComponent_map::iterator pos = m_mScriptComponents.find( xNormalized );
+ if ( pos != m_mScriptComponents.end() )
+ m_mScriptComponents.erase( pos );
+ }
+ }
+ catch ( const Exception& )
+ {
+ // if we get an exception here, there is not much we can do about
+ // it can't throw as it will screw up the model that is calling dispose
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+}
+
+void
+ActiveMSPList::createNonDocMSPs()
+{
+ // do creation of user and share MSPs here
+ OUString serviceName("com.sun.star.script.provider.MasterScriptProvider");
+
+ Sequence< Any > args{ Any(userDirString) };
+ Reference< provider::XScriptProvider > userMsp( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( serviceName, args, m_xContext ), UNO_QUERY );
+ // should check if provider reference is valid
+ m_hMsps[ userDirString ] = userMsp;
+
+ args = { Any(shareDirString) };
+ Reference< provider::XScriptProvider > shareMsp( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( serviceName, args, m_xContext ), UNO_QUERY );
+ // should check if provider reference is valid
+ m_hMsps[ shareDirString ] = shareMsp;
+
+ args = { Any(bundledDirString) };
+ Reference< provider::XScriptProvider > bundledMsp( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( serviceName, args, m_xContext ), UNO_QUERY );
+ // should check if provider reference is valid
+ m_hMsps[ bundledDirString ] = bundledMsp;
+}
+
+} // namespace func_provider
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/ActiveMSPList.hxx b/scripting/source/provider/ActiveMSPList.hxx
new file mode 100644
index 000000000..fb52629c1
--- /dev/null
+++ b/scripting/source/provider/ActiveMSPList.hxx
@@ -0,0 +1,94 @@
+/* -*- 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 <osl/mutex.hxx>
+#include <rtl/ustring.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/lang/XEventListener.hpp>
+
+#include <com/sun/star/script/provider/XScriptProvider.hpp>
+#include <com/sun/star/document/XScriptInvocationContext.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <map>
+#include <unordered_map>
+
+namespace func_provider
+{
+
+//Typedefs
+typedef std::map < css::uno::Reference< css::uno::XInterface >
+ , css::uno::Reference< css::script::provider::XScriptProvider >
+ > ScriptComponent_map;
+
+typedef std::unordered_map< OUString,
+ css::uno::Reference< css::script::provider::XScriptProvider > > Msp_hash;
+
+class NonDocMSPCreator;
+
+class ActiveMSPList : public ::cppu::WeakImplHelper< css::lang::XEventListener >
+{
+
+public:
+
+ explicit ActiveMSPList( const css::uno::Reference<
+ css::uno::XComponentContext > & xContext );
+ virtual ~ActiveMSPList() override;
+
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ getMSPFromStringContext( const OUString& context );
+
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ getMSPFromAnyContext( const css::uno::Any& context );
+
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ getMSPFromInvocationContext( const css::uno::Reference< css::document::XScriptInvocationContext >& context );
+
+ //XEventListener
+
+
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+private:
+ void addActiveMSP( const css::uno::Reference< css::uno::XInterface >& xComponent,
+ const css::uno::Reference< css::script::provider::XScriptProvider >& msp );
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ createNewMSP( const css::uno::Any& context );
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ createNewMSP( const OUString& context )
+ {
+ return createNewMSP( css::uno::Any( context ) );
+ }
+
+ friend class NonDocMSPCreator;
+ void createNonDocMSPs();
+
+ Msp_hash m_hMsps;
+ ScriptComponent_map m_mScriptComponents;
+ osl::Mutex m_mutex;
+ OUString userDirString;
+ OUString shareDirString;
+ OUString bundledDirString;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+};
+} // func_provider
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/BrowseNodeFactoryImpl.cxx b/scripting/source/provider/BrowseNodeFactoryImpl.cxx
new file mode 100644
index 000000000..9d070ab00
--- /dev/null
+++ b/scripting/source/provider/BrowseNodeFactoryImpl.cxx
@@ -0,0 +1,650 @@
+/* -*- 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 <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <unotools/mediadescriptor.hxx>
+
+#include <com/sun/star/document/XEmbeddedScripts.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/reflection/ProxyFactory.hpp>
+
+#include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
+#include <com/sun/star/script/browse/BrowseNodeFactoryViewTypes.hpp>
+#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
+
+#include <tools/diagnose_ex.h>
+
+#include "BrowseNodeFactoryImpl.hxx"
+#include <util/MiscUtils.hxx>
+
+#include <vector>
+#include <algorithm>
+#include <memory>
+#include <optional>
+#include <string_view>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::script;
+using namespace ::sf_misc;
+
+namespace browsenodefactory
+{
+namespace {
+class BrowseNodeAggregator :
+ public ::cppu::WeakImplHelper< browse::XBrowseNode >
+{
+private:
+ OUString m_Name;
+ std::vector< Reference< browse::XBrowseNode > > m_Nodes;
+
+public:
+
+ explicit BrowseNodeAggregator( const Reference< browse::XBrowseNode >& node )
+ : m_Name(node->getName())
+ {
+ m_Nodes.resize( 1 );
+ m_Nodes[ 0 ] = node;
+ }
+
+ void addBrowseNode( const Reference< browse::XBrowseNode>& node )
+ {
+ m_Nodes.push_back( node );
+ }
+
+ virtual OUString
+ SAL_CALL getName() override
+ {
+ return m_Name;
+ }
+
+ virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL
+ getChildNodes() override
+ {
+ std::vector< Sequence< Reference < browse::XBrowseNode > > > seqs;
+ seqs.reserve( m_Nodes.size() );
+
+ sal_Int32 numChildren = 0;
+
+ for (Reference<XBrowseNode> & xNode : m_Nodes)
+ {
+ Sequence< Reference < browse::XBrowseNode > > children;
+ try
+ {
+ children = xNode->getChildNodes();
+ seqs.push_back( children );
+ numChildren += children.getLength();
+ }
+ catch ( Exception& )
+ {
+ // some form of exception getting child nodes so they
+ // won't be displayed
+ }
+ }
+
+ Sequence< Reference < browse::XBrowseNode > > result( numChildren );
+ sal_Int32 index = 0;
+ for ( const Sequence< Reference < browse::XBrowseNode > >& children : seqs )
+ {
+ std::copy(children.begin(), children.end(), std::next(result.getArray(), index));
+ index += children.getLength();
+
+ if (index >= numChildren)
+ break;
+ }
+ return result;
+ }
+
+ virtual sal_Bool SAL_CALL
+ hasChildNodes() override
+ {
+ for (Reference<XBrowseNode> & xNode : m_Nodes)
+ {
+ try
+ {
+ if ( xNode->hasChildNodes() )
+ {
+ return true;
+ }
+ }
+ catch ( Exception& )
+ {
+ // some form of exception getting child nodes so move
+ // on to the next one
+ }
+ }
+
+ return false;
+ }
+
+ virtual sal_Int16 SAL_CALL getType() override
+ {
+ return browse::BrowseNodeTypes::CONTAINER;
+ }
+};
+
+struct alphaSort
+{
+ bool operator()( std::u16string_view a, std::u16string_view b )
+ {
+ return a.compare( b ) < 0;
+ }
+};
+class LocationBrowseNode :
+ public ::cppu::WeakImplHelper< browse::XBrowseNode >
+{
+private:
+ std::optional<std::unordered_map< OUString, Reference< browse::XBrowseNode > >> m_hBNA;
+ std::vector< OUString > m_vStr;
+ OUString m_sNodeName;
+ Reference< browse::XBrowseNode > m_origNode;
+
+public:
+
+ explicit LocationBrowseNode( const Reference< browse::XBrowseNode >& node )
+ : m_sNodeName(node->getName())
+ {
+ m_origNode.set( node );
+ }
+
+
+ // XBrowseNode
+
+ virtual OUString SAL_CALL getName() override
+ {
+ return m_sNodeName;
+ }
+
+ virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL
+ getChildNodes() override
+ {
+ if ( !m_hBNA )
+ {
+ loadChildNodes();
+ }
+
+ Sequence< Reference< browse::XBrowseNode > > children( m_hBNA->size() );
+ auto childrenRange = asNonConstRange(children);
+ sal_Int32 index = 0;
+
+ for ( const auto& str : m_vStr )
+ {
+ childrenRange[ index ].set( m_hBNA->find( str )->second );
+ ++index;
+ }
+
+ return children;
+ }
+
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return true;
+ }
+
+ virtual sal_Int16 SAL_CALL getType() override
+ {
+ return browse::BrowseNodeTypes::CONTAINER;
+ }
+
+private:
+
+ void loadChildNodes()
+ {
+ m_hBNA.emplace();
+
+ const Sequence< Reference< browse::XBrowseNode > > langNodes =
+ m_origNode->getChildNodes();
+
+ for ( const auto& rLangNode : langNodes )
+ {
+ Reference< browse::XBrowseNode > xbn;
+ if ( rLangNode->getName() == "uno_packages" )
+ {
+ xbn.set( new LocationBrowseNode( rLangNode ) );
+ }
+ else
+ {
+ xbn.set( rLangNode );
+ }
+
+ const Sequence< Reference< browse::XBrowseNode > > grandchildren =
+ xbn->getChildNodes();
+
+ for ( const Reference< browse::XBrowseNode >& grandchild : grandchildren )
+ {
+ auto h_it =
+ m_hBNA->find( grandchild->getName() );
+
+ if ( h_it != m_hBNA->end() )
+ {
+ BrowseNodeAggregator* bna = static_cast< BrowseNodeAggregator* >( h_it->second.get() );
+ bna->addBrowseNode( grandchild );
+ }
+ else
+ {
+ Reference< browse::XBrowseNode > bna(
+ new BrowseNodeAggregator( grandchild ) );
+ (*m_hBNA)[ grandchild->getName() ].set( bna );
+ m_vStr.push_back( grandchild->getName() );
+ }
+ }
+ }
+ // sort children alphabetically
+ ::std::sort( m_vStr.begin(), m_vStr.end(), alphaSort() );
+ }
+};
+
+std::vector< Reference< browse::XBrowseNode > > getAllBrowseNodes( const Reference< XComponentContext >& xCtx )
+{
+ const Sequence< OUString > openDocs =
+ MiscUtils::allOpenTDocUrls( xCtx );
+
+ Reference< provider::XScriptProviderFactory > xFac;
+ sal_Int32 initialSize = openDocs.getLength() + 2;
+ sal_Int32 mspIndex = 0;
+
+ std::vector< Reference < browse::XBrowseNode > > locnBNs( initialSize );
+ try
+ {
+ xFac = provider::theMasterScriptProviderFactory::get( xCtx );
+
+ locnBNs[ mspIndex++ ].set( xFac->createScriptProvider( Any( OUString("user") ) ), UNO_QUERY_THROW );
+ locnBNs[ mspIndex++ ].set( xFac->createScriptProvider( Any( OUString("share") ) ), UNO_QUERY_THROW );
+ }
+ // TODO proper exception handling, should throw
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("scripting", "Caught" );
+ locnBNs.resize( mspIndex );
+ return locnBNs;
+ }
+
+ for ( const auto& rDoc : openDocs )
+ {
+ try
+ {
+ Reference< frame::XModel > model( MiscUtils::tDocUrlToModel( rDoc ), UNO_SET_THROW );
+
+ // #i44599 Check if it's a real document or something special like Hidden/Preview
+ css::uno::Reference< css::frame::XController > xCurrentController = model->getCurrentController();
+ if( xCurrentController.is() )
+ {
+ utl::MediaDescriptor aMD( model->getArgs() );
+ bool bDefault = false;
+ bool bHidden = aMD.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_HIDDEN, bDefault );
+ bool bPreview = aMD.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_PREVIEW, bDefault );
+ if( !bHidden && !bPreview )
+ {
+ Reference< document::XEmbeddedScripts > xScripts( model, UNO_QUERY );
+ if ( xScripts.is() )
+ locnBNs[ mspIndex++ ].set( xFac->createScriptProvider( Any( model ) ), UNO_QUERY_THROW );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+
+ }
+
+ std::vector< Reference < browse::XBrowseNode > > locnBNs_Return( mspIndex );
+ for ( sal_Int32 j = 0; j < mspIndex; j++ )
+ locnBNs_Return[j] = locnBNs[j];
+
+ return locnBNs_Return;
+}
+
+} // namespace
+
+typedef ::std::vector< Reference< browse::XBrowseNode > > vXBrowseNodes;
+
+namespace {
+
+struct alphaSortForBNodes
+{
+ bool operator()( const Reference< browse::XBrowseNode >& a, const Reference< browse::XBrowseNode >& b )
+ {
+ return a->getName().compareTo( b->getName() ) < 0;
+ }
+};
+
+}
+
+typedef ::cppu::WeakImplHelper< browse::XBrowseNode > t_BrowseNodeBase;
+
+namespace {
+
+class DefaultBrowseNode :
+ public t_BrowseNodeBase
+{
+
+private:
+ Reference< browse::XBrowseNode > m_xWrappedBrowseNode;
+ Reference< lang::XTypeProvider > m_xWrappedTypeProv;
+ Reference< XAggregation > m_xAggProxy;
+ Reference< XComponentContext > m_xCtx;
+
+public:
+ DefaultBrowseNode( const Reference< XComponentContext >& xCtx, const Reference< browse::XBrowseNode>& xNode ) : m_xWrappedBrowseNode( xNode ), m_xWrappedTypeProv( xNode, UNO_QUERY ), m_xCtx( xCtx )
+ {
+ OSL_ENSURE( m_xWrappedBrowseNode.is(), "DefaultBrowseNode::DefaultBrowseNode(): No BrowseNode to wrap" );
+ OSL_ENSURE( m_xWrappedTypeProv.is(), "DefaultBrowseNode::DefaultBrowseNode(): No BrowseNode to wrap" );
+ OSL_ENSURE( m_xCtx.is(), "DefaultBrowseNode::DefaultBrowseNode(): No ComponentContext" );
+ // Use proxy factory service to create aggregatable proxy.
+ try
+ {
+ Reference< reflection::XProxyFactory > xProxyFac =
+ reflection::ProxyFactory::create( m_xCtx );
+ m_xAggProxy = xProxyFac->createProxy( m_xWrappedBrowseNode );
+ }
+ catch( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "scripting", "DefaultBrowseNode::DefaultBrowseNode" );
+ }
+ OSL_ENSURE( m_xAggProxy.is(),
+ "DefaultBrowseNode::DefaultBrowseNode: Wrapped BrowseNode cannot be aggregated!" );
+
+ if ( !m_xAggProxy.is() )
+ return;
+
+ osl_atomic_increment( &m_refCount );
+
+ /* i35609 - Fix crash on Solaris. The setDelegator call needs
+ to be in its own block to ensure that all temporary Reference
+ instances that are acquired during the call are released
+ before m_refCount is decremented again */
+ {
+ m_xAggProxy->setDelegator(
+ static_cast< cppu::OWeakObject * >( this ) );
+ }
+
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ virtual ~DefaultBrowseNode() override
+ {
+ if ( m_xAggProxy.is() )
+ {
+ m_xAggProxy->setDelegator( uno::Reference< uno::XInterface >() );
+ }
+ }
+
+ virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL
+ getChildNodes() override
+ {
+ if ( hasChildNodes() )
+ {
+ vXBrowseNodes aVNodes;
+ const Sequence < Reference< browse::XBrowseNode > > nodes =
+ m_xWrappedBrowseNode->getChildNodes();
+ for ( const Reference< browse::XBrowseNode >& xBrowseNode : nodes )
+ {
+ OSL_ENSURE( xBrowseNode.is(), "DefaultBrowseNode::getChildNodes(): Invalid BrowseNode" );
+ if( xBrowseNode.is() )
+ aVNodes.push_back( new DefaultBrowseNode( m_xCtx, xBrowseNode ) );
+ }
+
+ ::std::sort( aVNodes.begin(), aVNodes.end(), alphaSortForBNodes() );
+ Sequence < Reference< browse::XBrowseNode > > children( aVNodes.size() );
+ auto childrenRange = asNonConstRange(children);
+ sal_Int32 i = 0;
+ for ( const auto& rxNode : aVNodes )
+ {
+ childrenRange[ i ].set( rxNode );
+ i++;
+ }
+ return children;
+ }
+ else
+ {
+ // no nodes
+
+ Sequence < Reference< browse::XBrowseNode > > none;
+ return none;
+ }
+ }
+
+ virtual sal_Int16 SAL_CALL getType() override
+ {
+ return m_xWrappedBrowseNode->getType();
+ }
+
+ virtual OUString
+ SAL_CALL getName() override
+ {
+ return m_xWrappedBrowseNode->getName();
+ }
+
+ virtual sal_Bool SAL_CALL
+ hasChildNodes() override
+ {
+ return m_xWrappedBrowseNode->hasChildNodes();
+ }
+
+ // XInterface
+ virtual Any SAL_CALL queryInterface( const Type& aType ) override
+ {
+ Any aRet = t_BrowseNodeBase::queryInterface( aType );
+ if ( aRet.hasValue() )
+ {
+ return aRet;
+ }
+ if ( m_xAggProxy.is() )
+ {
+ return m_xAggProxy->queryAggregation( aType );
+ }
+ else
+ {
+ return Any();
+ }
+ }
+
+ // XTypeProvider (implemented by base, but needs to be overridden for
+ // delegating to aggregate)
+ virtual Sequence< Type > SAL_CALL getTypes() override
+ {
+ return m_xWrappedTypeProv->getTypes();
+ }
+ virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override
+ {
+ return css::uno::Sequence<sal_Int8>();
+ }
+};
+
+class DefaultRootBrowseNode :
+ public ::cppu::WeakImplHelper< browse::XBrowseNode >
+{
+
+private:
+ vXBrowseNodes m_vNodes;
+ OUString m_Name;
+
+public:
+ explicit DefaultRootBrowseNode( const Reference< XComponentContext >& xCtx )
+ {
+ std::vector< Reference< browse::XBrowseNode > > nodes =
+ getAllBrowseNodes( xCtx );
+
+ for (Reference< browse::XBrowseNode > & xNode : nodes)
+ {
+ m_vNodes.push_back( new DefaultBrowseNode( xCtx, xNode ) );
+ }
+ m_Name = "Root";
+ }
+
+ virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL
+ getChildNodes() override
+ {
+ // no need to sort user, share, doc1...docN
+ //::std::sort( m_vNodes.begin(), m_vNodes.end(), alphaSortForBNodes() );
+ Sequence < Reference< browse::XBrowseNode > > children( m_vNodes.size() );
+ auto childrenRange = asNonConstRange(children);
+ sal_Int32 i = 0;
+ for ( const auto& rxNode : m_vNodes )
+ {
+ childrenRange[ i ].set( rxNode );
+ i++;
+ }
+ return children;
+ }
+
+ virtual sal_Int16 SAL_CALL getType() override
+ {
+ return browse::BrowseNodeTypes::ROOT;
+ }
+
+ virtual OUString
+ SAL_CALL getName() override
+ {
+ return m_Name;
+ }
+
+ virtual sal_Bool SAL_CALL
+ hasChildNodes() override
+ {
+ bool result = true;
+ if ( m_vNodes.empty() )
+ {
+ result = false;
+ }
+ return result;
+ }
+};
+
+
+class SelectorBrowseNode :
+ public ::cppu::WeakImplHelper< browse::XBrowseNode >
+{
+private:
+ Reference< XComponentContext > m_xComponentContext;
+
+public:
+ explicit SelectorBrowseNode( const Reference< XComponentContext >& xContext )
+ : m_xComponentContext( xContext )
+ {
+ }
+
+ virtual OUString SAL_CALL getName() override
+ {
+ return "Root";
+ }
+
+ virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL
+ getChildNodes() override
+ {
+
+ std::vector< Reference < browse::XBrowseNode > > locnBNs = getAllBrowseNodes( m_xComponentContext );
+
+ Sequence< Reference< browse::XBrowseNode > > children(
+ locnBNs.size() );
+ auto childrenRange = asNonConstRange(children);
+
+ for ( size_t j = 0; j < locnBNs.size(); j++ )
+ {
+ childrenRange[j] = new LocationBrowseNode( locnBNs[j] );
+ }
+
+ return children;
+ }
+
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return true; // will always be user and share
+ }
+
+ virtual sal_Int16 SAL_CALL getType() override
+ {
+ return browse::BrowseNodeTypes::CONTAINER;
+ }
+};
+
+}
+
+BrowseNodeFactoryImpl::BrowseNodeFactoryImpl(
+ Reference< XComponentContext > const & xComponentContext )
+ : m_xComponentContext( xComponentContext )
+{
+}
+
+BrowseNodeFactoryImpl::~BrowseNodeFactoryImpl()
+{
+}
+
+
+// Implementation of XBrowseNodeFactory
+
+
+/*
+ * The selector hierarchy is the standard hierarchy for organizers with the
+ * language nodes removed.
+ */
+Reference< browse::XBrowseNode > SAL_CALL
+BrowseNodeFactoryImpl::createView( sal_Int16 viewType )
+{
+ switch( viewType )
+ {
+ case browse::BrowseNodeFactoryViewTypes::MACROSELECTOR:
+ return new SelectorBrowseNode( m_xComponentContext );
+ case browse::BrowseNodeFactoryViewTypes::MACROORGANIZER:
+ return getOrganizerHierarchy();
+ default:
+ throw RuntimeException( "Unknown view type" );
+ }
+}
+
+Reference< browse::XBrowseNode >
+BrowseNodeFactoryImpl::getOrganizerHierarchy() const
+{
+ Reference< browse::XBrowseNode > xRet = new DefaultRootBrowseNode( m_xComponentContext );
+ return xRet;
+}
+
+// Implementation of XServiceInfo
+
+
+OUString SAL_CALL
+BrowseNodeFactoryImpl::getImplementationName()
+{
+ return "com.sun.star.script.browse.BrowseNodeFactory";
+}
+
+Sequence< OUString > SAL_CALL
+BrowseNodeFactoryImpl::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.browse.BrowseNodeFactory" };
+}
+
+sal_Bool BrowseNodeFactoryImpl::supportsService(OUString const & serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scripting_BrowseNodeFactoryImpl_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new BrowseNodeFactoryImpl(context));
+}
+
+} // namespace browsenodefactory
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/BrowseNodeFactoryImpl.hxx b/scripting/source/provider/BrowseNodeFactoryImpl.hxx
new file mode 100644
index 000000000..908568021
--- /dev/null
+++ b/scripting/source/provider/BrowseNodeFactoryImpl.hxx
@@ -0,0 +1,70 @@
+/* -*- 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 <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <com/sun/star/script/browse/XBrowseNode.hpp>
+#include <com/sun/star/script/browse/XBrowseNodeFactory.hpp>
+
+namespace browsenodefactory
+{
+
+class BrowseNodeFactoryImpl :
+ public ::cppu::WeakImplHelper <
+ css::script::browse::XBrowseNodeFactory,
+ css::lang::XServiceInfo >
+{
+private:
+ css::uno::Reference< css::uno::XComponentContext > m_xComponentContext;
+
+protected:
+ virtual ~BrowseNodeFactoryImpl() override;
+
+public:
+ explicit BrowseNodeFactoryImpl(
+ css::uno::Reference< css::uno::XComponentContext > const & xComponentContext );
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL
+ supportsService( OUString const & serviceName ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL
+ getSupportedServiceNames() override;
+
+ // XBrowseNodeFactory
+ virtual css::uno::Reference< css::script::browse::XBrowseNode > SAL_CALL
+ createView( sal_Int16 viewType ) override;
+private:
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::script::browse::XBrowseNode >
+ getOrganizerHierarchy() const;
+};
+
+
+} // namespace browsenodefactory
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/MasterScriptProvider.cxx b/scripting/source/provider/MasterScriptProvider.cxx
new file mode 100644
index 000000000..93d6a60f3
--- /dev/null
+++ b/scripting/source/provider/MasterScriptProvider.cxx
@@ -0,0 +1,676 @@
+/* -*- 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 <comphelper/SetFlagContextHelper.hxx>
+#include <comphelper/documentinfo.hxx>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/urlobj.hxx>
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorException.hpp>
+#include <com/sun/star/uri/XUriReference.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
+
+#include <com/sun/star/deployment/XPackage.hpp>
+#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
+#include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
+
+#include <util/MiscUtils.hxx>
+#include <sal/log.hxx>
+
+#include "MasterScriptProvider.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::document;
+using namespace ::sf_misc;
+
+namespace func_provider
+{
+
+static bool endsWith( const OUString& target, const OUString& item )
+{
+ sal_Int32 index = target.indexOf( item );
+ return index != -1 &&
+ index == ( target.getLength() - item.getLength() );
+}
+
+/* should be available in some central location. */
+
+// XScriptProvider implementation
+
+
+MasterScriptProvider::MasterScriptProvider( const Reference< XComponentContext > & xContext ):
+ m_xContext( xContext ), m_bIsValid( false ), m_bInitialised( false ),
+ m_bIsPkgMSP( false )
+{
+ ENSURE_OR_THROW( m_xContext.is(), "MasterScriptProvider::MasterScriptProvider: No context available\n" );
+ m_xMgr = m_xContext->getServiceManager();
+ ENSURE_OR_THROW( m_xMgr.is(), "MasterScriptProvider::MasterScriptProvider: No service manager available\n" );
+ m_bIsValid = true;
+}
+
+
+MasterScriptProvider::~MasterScriptProvider()
+{
+}
+
+
+void SAL_CALL MasterScriptProvider::initialize( const Sequence < Any >& args )
+{
+ if ( m_bInitialised )
+ return;
+
+ m_bIsValid = false;
+
+ sal_Int32 len = args.getLength();
+ if ( len > 1 )
+ {
+ throw RuntimeException(
+ "MasterScriptProvider::initialize: invalid number of arguments" );
+ }
+
+ Sequence< Any > invokeArgs( len );
+
+ if ( len != 0 )
+ {
+ auto pinvokeArgs = invokeArgs.getArray();
+ // check if first parameter is a string
+ // if it is, this implies that this is a MSP created
+ // with a user or share ctx ( used for browse functionality )
+
+ if ( args[ 0 ] >>= m_sCtxString )
+ {
+ pinvokeArgs[ 0 ] = args[ 0 ];
+ if ( m_sCtxString.startsWith( "vnd.sun.star.tdoc" ) )
+ {
+ m_xModel = MiscUtils::tDocUrlToModel( m_sCtxString );
+ }
+ }
+ else if ( args[ 0 ] >>= m_xInvocationContext )
+ {
+ m_xModel.set( m_xInvocationContext->getScriptContainer(), UNO_QUERY_THROW );
+ }
+ else
+ {
+ args[ 0 ] >>= m_xModel;
+ }
+
+ if ( m_xModel.is() )
+ {
+ // from the arguments, we were able to deduce a model. That alone doesn't
+ // suffice, we also need an XEmbeddedScripts which actually indicates support
+ // for embedding scripts
+ Reference< XEmbeddedScripts > xScripts( m_xModel, UNO_QUERY );
+ if ( !xScripts.is() )
+ {
+ throw lang::IllegalArgumentException(
+ "The given document does not support embedding scripts into it, and cannot be associated with such a document.",
+ *this,
+ 1
+ );
+ }
+
+ try
+ {
+ m_sCtxString = MiscUtils::xModelToTdocUrl( m_xModel, m_xContext );
+ }
+ catch ( const Exception& )
+ {
+ Any aError( ::cppu::getCaughtException() );
+
+ Exception aException;
+ aError >>= aException;
+ OUString buf =
+ "MasterScriptProvider::initialize: caught " +
+ aError.getValueTypeName() +
+ ":" +
+ aException.Message;
+ throw lang::WrappedTargetException( buf, *this, aError );
+ }
+
+ if ( m_xInvocationContext.is() && m_xInvocationContext != m_xModel )
+ pinvokeArgs[ 0 ] <<= m_xInvocationContext;
+ else
+ pinvokeArgs[ 0 ] <<= m_sCtxString;
+ }
+
+ OUString pkgSpec = "uno_packages";
+ sal_Int32 indexOfPkgSpec = m_sCtxString.lastIndexOf( pkgSpec );
+
+ // if context string ends with "uno_packages"
+ if ( indexOfPkgSpec > -1 && m_sCtxString.match( pkgSpec, indexOfPkgSpec ) )
+ {
+ m_bIsPkgMSP = true;
+ }
+ else
+ {
+ m_bIsPkgMSP = false;
+ }
+ }
+ else // no args
+ {
+ // use either scripting context or maybe zero args?
+ invokeArgs = Sequence< Any >( 0 ); // no arguments
+ }
+ m_sAargs = invokeArgs;
+ // don't create pkg mgr MSP for documents, not supported
+ if ( !m_bIsPkgMSP && !m_xModel.is() )
+ {
+ createPkgProvider();
+ }
+
+ m_bInitialised = true;
+ m_bIsValid = true;
+}
+
+
+void MasterScriptProvider::createPkgProvider()
+{
+ try
+ {
+ Any location;
+ location <<= m_sCtxString + ":uno_packages";
+
+ Reference< provider::XScriptProviderFactory > xFac =
+ provider::theMasterScriptProviderFactory::get( m_xContext );
+
+ m_xMSPPkg.set(
+ xFac->createScriptProvider( location ), UNO_SET_THROW );
+
+ }
+ catch ( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("scripting.provider", "Exception creating MasterScriptProvider for uno_packages in context "
+ << m_sCtxString );
+ }
+}
+
+
+Reference< provider::XScript >
+MasterScriptProvider::getScript( const OUString& scriptURI )
+{
+ if ( !m_bIsValid )
+ {
+ throw provider::ScriptFrameworkErrorException(
+ "MasterScriptProvider not initialised", Reference< XInterface >(),
+ scriptURI, "",
+ provider::ScriptFrameworkErrorType::UNKNOWN );
+ }
+
+ // need to get the language from the string
+
+ Reference< uri::XUriReferenceFactory > xFac ( uri::UriReferenceFactory::create( m_xContext ) );
+
+ Reference< uri::XUriReference > uriRef = xFac->parse( scriptURI );
+
+ Reference < uri::XVndSunStarScriptUrl > sfUri( uriRef, UNO_QUERY );
+
+ if ( !uriRef.is() || !sfUri.is() )
+ {
+ throw provider::ScriptFrameworkErrorException(
+ "Incorrect format for Script URI: " + scriptURI,
+ Reference< XInterface >(),
+ scriptURI, "",
+ provider::ScriptFrameworkErrorType::UNKNOWN );
+ }
+
+ OUString langKey("language");
+ OUString locKey("location");
+
+ if ( !sfUri->hasParameter( langKey ) ||
+ !sfUri->hasParameter( locKey ) ||
+ ( sfUri->getName().isEmpty() ) )
+ {
+ throw provider::ScriptFrameworkErrorException(
+ "Incorrect format for Script URI: " + scriptURI,
+ Reference< XInterface >(),
+ scriptURI, "",
+ provider::ScriptFrameworkErrorType::UNKNOWN );
+ }
+
+ OUString language = sfUri->getParameter( langKey );
+ OUString location = sfUri->getParameter( locKey );
+
+ // if script us located in uno pkg
+ sal_Int32 index = -1;
+ OUString pkgTag(":uno_packages");
+ // for languages other than basic, scripts located in uno packages
+ // are merged into the user/share location context.
+ // For other languages the location attribute in script url has the form
+ // location = [user|share]:uno_packages or location :uno_packages/xxxx.uno.pkg
+ // we need to extract the value of location part from the
+ // location attribute of the script, if the script is located in an
+ // uno package then that is the location part up to and including
+ // ":uno_packages", if the script is not in a uno package then the
+ // normal value is used e.g. user or share.
+ // The value extracted will be used to determine if the script is
+ // located in the same location context as this MSP.
+ // For Basic, the language script provider can handle the execution of a
+ // script in any location context
+ if ( ( index = location.indexOf( pkgTag ) ) > -1 )
+ {
+ location = location.copy( 0, index + pkgTag.getLength() );
+ }
+
+ Reference< provider::XScript > xScript;
+
+ // If the script location is in the same location context as this
+ // MSP then delete to the language provider controlled by this MSP
+ // ** Special case is BASIC, all calls to getScript will be handled
+ // by the language script provider in the current location context
+ // even if it's different
+ if ( ( location == "document"
+ && m_xModel.is()
+ )
+ || ( endsWith( m_sCtxString, location ) )
+ || ( language == "Basic" )
+ )
+ {
+ Reference< provider::XScriptProvider > xScriptProvider;
+ OUString serviceName = "com.sun.star.script.provider.ScriptProviderFor" + language;
+ if ( !providerCache() )
+ {
+ throw provider::ScriptFrameworkErrorException(
+ "No LanguageProviders detected",
+ Reference< XInterface >(),
+ sfUri->getName(), language,
+ provider::ScriptFrameworkErrorType::NOTSUPPORTED );
+ }
+
+ try
+ {
+ xScriptProvider.set(
+ providerCache()->getProvider( serviceName ),
+ UNO_SET_THROW );
+ }
+ catch( const Exception& e )
+ {
+ throw provider::ScriptFrameworkErrorException(
+ e.Message, Reference< XInterface >(),
+ sfUri->getName(), language,
+ provider::ScriptFrameworkErrorType::NOTSUPPORTED );
+ }
+
+ xScript=xScriptProvider->getScript( scriptURI );
+ }
+ else
+ {
+ Reference< provider::XScriptProviderFactory > xFac_ =
+ provider::theMasterScriptProviderFactory::get( m_xContext );
+
+ Reference< provider::XScriptProvider > xSP(
+ xFac_->createScriptProvider( Any( location ) ), UNO_SET_THROW );
+ xScript = xSP->getScript( scriptURI );
+ }
+
+ return xScript;
+}
+
+
+ProviderCache*
+MasterScriptProvider::providerCache()
+{
+ if ( !m_pPCache )
+ {
+ std::scoped_lock aGuard( m_mutex );
+ if ( !m_pPCache )
+ {
+ Sequence<OUString> denylist { "com.sun.star.script.provider.ScriptProviderForBasic" };
+
+ if ( !m_bIsPkgMSP )
+ {
+ m_pPCache.reset( new ProviderCache( m_xContext, m_sAargs ) );
+ }
+ else
+ {
+ m_pPCache.reset( new ProviderCache( m_xContext, m_sAargs, denylist ) );
+ }
+ }
+ }
+ return m_pPCache.get();
+}
+
+
+OUString SAL_CALL
+MasterScriptProvider::getName()
+{
+ if ( !m_bIsPkgMSP )
+ {
+ OUString sCtx = getContextString();
+ if ( sCtx.startsWith( "vnd.sun.star.tdoc" ) )
+ {
+ Reference< frame::XModel > xModel = m_xModel;
+ if ( !xModel.is() )
+ {
+ xModel = MiscUtils::tDocUrlToModel( sCtx );
+ }
+
+ m_sNodeName = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
+ }
+ else
+ {
+ m_sNodeName = parseLocationName( getContextString() );
+ }
+ }
+ else
+ {
+ m_sNodeName = "uno_packages";
+ }
+ return m_sNodeName;
+}
+
+
+Sequence< Reference< browse::XBrowseNode > > SAL_CALL
+MasterScriptProvider::getChildNodes()
+{
+ Sequence< Reference< provider::XScriptProvider > > providers = providerCache()->getAllProviders();
+
+ sal_Int32 size = providers.getLength();
+ bool hasPkgs = m_xMSPPkg.is();
+ if ( hasPkgs )
+ {
+ size++;
+ }
+ Sequence< Reference< browse::XBrowseNode > > children( size );
+ auto childrenRange = asNonConstRange(children);
+ sal_Int32 provIndex = 0;
+ for ( ; provIndex < providers.getLength(); provIndex++ )
+ {
+ childrenRange[ provIndex ].set( providers[ provIndex ], UNO_QUERY );
+ }
+
+ if ( hasPkgs )
+ {
+ childrenRange[ provIndex ].set( m_xMSPPkg, UNO_QUERY );
+
+ }
+
+ return children;
+}
+
+
+sal_Bool SAL_CALL
+MasterScriptProvider::hasChildNodes()
+{
+ return true;
+}
+
+
+sal_Int16 SAL_CALL
+MasterScriptProvider::getType()
+{
+ return browse::BrowseNodeTypes::CONTAINER;
+}
+
+
+OUString
+MasterScriptProvider::parseLocationName( const OUString& location )
+{
+ // strip out the last leaf of location name
+ // e.g. file://dir1/dir2/Blah.sxw - > Blah.sxw
+ OUString temp = location;
+ INetURLObject aURLObj( temp );
+ if ( !aURLObj.HasError() )
+ temp = aURLObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
+ return temp;
+}
+
+namespace
+{
+template <typename Proc> bool FindProviderAndApply(ProviderCache& rCache, Proc p)
+{
+ auto pass = [&rCache, &p]() -> bool
+ {
+ bool bResult = false;
+ const Sequence<Reference<provider::XScriptProvider>> aAllProviders = rCache.getAllProviders();
+ for (const auto& rProv : aAllProviders)
+ {
+ Reference<container::XNameContainer> xCont(rProv, UNO_QUERY);
+ if (!xCont.is())
+ {
+ continue;
+ }
+ try
+ {
+ bResult = p(xCont);
+ if (bResult)
+ break;
+ }
+ catch (const Exception&)
+ {
+ TOOLS_INFO_EXCEPTION("scripting.provider", "ignoring");
+ }
+ }
+ return bResult;
+ };
+ bool bSuccess = false;
+ // 1. Try to perform the operation without trying to enable JVM (if disabled)
+ // This allows us to avoid useless user interaction in case when other provider
+ // (not JVM) actually handles the operation.
+ {
+ css::uno::ContextLayer layer(comphelper::NoEnableJavaInteractionContext());
+ bSuccess = pass();
+ }
+ // 2. Now retry asking to enable JVM in case we didn't succeed first time
+ if (!bSuccess)
+ {
+ bSuccess = pass();
+ }
+ return bSuccess;
+}
+} // namespace
+
+// Register Package
+void SAL_CALL
+MasterScriptProvider::insertByName( const OUString& aName, const Any& aElement )
+{
+ if ( !m_bIsPkgMSP )
+ {
+ if ( !m_xMSPPkg.is() )
+ {
+ throw RuntimeException( "PackageMasterScriptProvider is unitialised" );
+ }
+
+ Reference< container::XNameContainer > xCont( m_xMSPPkg, UNO_QUERY_THROW );
+ xCont->insertByName( aName, aElement );
+ }
+ else
+ {
+ Reference< deployment::XPackage > xPkg( aElement, UNO_QUERY );
+ if ( !xPkg.is() )
+ {
+ throw lang::IllegalArgumentException( "Couldn't convert to XPackage",
+ Reference < XInterface > (), 2 );
+ }
+ if ( aName.isEmpty() )
+ {
+ throw lang::IllegalArgumentException( "Name not set!!",
+ Reference < XInterface > (), 1 );
+ }
+ // TODO for library package parse the language, for the moment will try
+ // to get each provider to process the new Package, the first one the succeeds
+ // will terminate processing
+ const bool bSuccess = FindProviderAndApply(
+ *providerCache(), [&aName, &aElement](Reference<container::XNameContainer>& xCont) {
+ xCont->insertByName(aName, aElement);
+ return true;
+ });
+ if (!bSuccess)
+ {
+ // No script providers could process the package
+ throw lang::IllegalArgumentException( "Failed to register package for " + aName,
+ Reference < XInterface > (), 2 );
+ }
+ }
+}
+
+
+// Revoke Package
+void SAL_CALL
+MasterScriptProvider::removeByName( const OUString& Name )
+{
+ if ( !m_bIsPkgMSP )
+ {
+ if ( !m_xMSPPkg.is() )
+ {
+ throw RuntimeException( "PackageMasterScriptProvider is unitialised" );
+ }
+
+ Reference< container::XNameContainer > xCont( m_xMSPPkg, UNO_QUERY_THROW );
+ xCont->removeByName( Name );
+ }
+ else
+ {
+ if ( Name.isEmpty() )
+ {
+ throw lang::IllegalArgumentException( "Name not set!!",
+ Reference < XInterface > (), 1 );
+ }
+ // TODO for Script library package url parse the language,
+ // for the moment will just try to get each provider to process remove/revoke
+ // request, the first one the succeeds will terminate processing
+ const bool bSuccess = FindProviderAndApply(
+ *providerCache(), [&Name](Reference<container::XNameContainer>& xCont) {
+ xCont->removeByName(Name);
+ return true;
+ });
+ if (!bSuccess)
+ {
+ // No script providers could process the package
+ throw lang::IllegalArgumentException( "Failed to revoke package for " + Name,
+ Reference < XInterface > (), 1 );
+ }
+
+ }
+}
+
+
+void SAL_CALL
+MasterScriptProvider::replaceByName( const OUString& /*aName*/, const Any& /*aElement*/ )
+{
+ // TODO needs implementing
+ throw RuntimeException( "replaceByName not implemented!!!!" );
+}
+
+Any SAL_CALL
+MasterScriptProvider::getByName( const OUString& /*aName*/ )
+{
+ // TODO needs to be implemented
+ throw RuntimeException( "getByName not implemented!!!!" );
+}
+
+sal_Bool SAL_CALL
+MasterScriptProvider::hasByName( const OUString& aName )
+{
+ bool result = false;
+ if ( !m_bIsPkgMSP )
+ {
+ if ( m_xMSPPkg.is() )
+ {
+ Reference< container::XNameContainer > xCont( m_xMSPPkg, UNO_QUERY_THROW );
+ result = xCont->hasByName( aName );
+ }
+ // If this is a document provider then we shouldn't
+ // have a PackageProvider
+ else if (!m_xModel.is())
+ {
+ throw RuntimeException( "PackageMasterScriptProvider is unitialised" );
+ }
+
+ }
+ else
+ {
+ if ( aName.isEmpty() )
+ {
+ throw lang::IllegalArgumentException( "Name not set!!",
+ Reference < XInterface > (), 1 );
+ }
+ // TODO for Script library package url parse the language,
+ // for the moment will just try to get each provider to see if the
+ // package exists in any provider, first one that succeed will
+ // terminate the loop
+ result = FindProviderAndApply(
+ *providerCache(), [&aName](Reference<container::XNameContainer>& xCont) {
+ return xCont->hasByName(aName);
+ });
+ }
+ return result;
+}
+
+
+Sequence< OUString > SAL_CALL
+MasterScriptProvider::getElementNames( )
+{
+ // TODO needs implementing
+ throw RuntimeException( "getElementNames not implemented!!!!" );
+}
+
+Type SAL_CALL
+MasterScriptProvider::getElementType( )
+{
+ // TODO needs implementing
+ Type t;
+ return t;
+}
+
+sal_Bool SAL_CALL MasterScriptProvider::hasElements( )
+{
+ // TODO needs implementing
+ throw RuntimeException( "hasElements not implemented!!!!" );
+}
+
+
+OUString SAL_CALL MasterScriptProvider::getImplementationName( )
+{
+ return "com.sun.star.script.provider.MasterScriptProvider";
+}
+
+sal_Bool SAL_CALL MasterScriptProvider::supportsService( const OUString& serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+
+Sequence< OUString > SAL_CALL MasterScriptProvider::getSupportedServiceNames( )
+{
+ return {
+ "com.sun.star.script.provider.MasterScriptProvider",
+ "com.sun.star.script.browse.BrowseNode",
+ "com.sun.star.script.provider.ScriptProvider" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scripting_MasterScriptProvider_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new MasterScriptProvider(context));
+}
+
+} // namespace func_provider
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/MasterScriptProvider.hxx b/scripting/source/provider/MasterScriptProvider.hxx
new file mode 100644
index 000000000..0e6c40f5f
--- /dev/null
+++ b/scripting/source/provider/MasterScriptProvider.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/document/XScriptInvocationContext.hpp>
+
+#include <com/sun/star/lang/XInitialization.hpp>
+
+#include <com/sun/star/script/provider/XScriptProvider.hpp>
+#include <com/sun/star/script/browse/XBrowseNode.hpp>
+
+#include "ProviderCache.hxx"
+#include <memory>
+#include <mutex>
+
+namespace func_provider
+{
+
+ typedef ::cppu::WeakImplHelper<
+ css::script::provider::XScriptProvider,
+ css::script::browse::XBrowseNode, css::lang::XServiceInfo,
+ css::lang::XInitialization,
+ css::container::XNameContainer > t_helper;
+
+class MasterScriptProvider :
+ public t_helper
+{
+public:
+ /// @throws css::uno::RuntimeException
+ explicit MasterScriptProvider(
+ const css::uno::Reference< css::uno::XComponentContext >
+ & xContext );
+ virtual ~MasterScriptProvider() override;
+
+ // XServiceInfo implementation
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ // XBrowseNode implementation
+ virtual OUString SAL_CALL getName() override;
+ virtual css::uno::Sequence< css::uno::Reference< css::script::browse::XBrowseNode > > SAL_CALL getChildNodes() override;
+ virtual sal_Bool SAL_CALL hasChildNodes() override;
+ virtual sal_Int16 SAL_CALL getType() override;
+ // XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& aName, const css::uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByName( const OUString& Name ) override;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XScriptProvider implementation
+ virtual css::uno::Reference < css::script::provider::XScript > SAL_CALL
+ getScript( const OUString& scriptURI ) override;
+
+ /**
+ * XInitialise implementation
+ *
+ * @param args expected to contain a single OUString
+ * containing the URI
+ */
+ virtual void SAL_CALL initialize( const css::uno::Sequence < css::uno::Any > & args ) override;
+
+ // returns context string for this provider, eg
+ const OUString& getContextString() const { return m_sCtxString; }
+
+private:
+ static OUString parseLocationName( const OUString& location );
+ void createPkgProvider();
+
+ ProviderCache* providerCache();
+ /* to obtain other services if needed */
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::lang::XMultiComponentFactory > m_xMgr;
+ css::uno::Reference< css::frame::XModel > m_xModel;
+ css::uno::Reference< css::document::XScriptInvocationContext > m_xInvocationContext;
+ css::uno::Sequence< css::uno::Any > m_sAargs;
+ OUString m_sNodeName;
+
+ // This component supports XInitialization, it can be created
+ // using createInstanceXXX() or createInstanceWithArgumentsXXX using
+ // the service Manager.
+ // Need to detect proper initialisation and validity
+ // for the object, so m_bIsValid indicates that the object is valid is set in ctor
+ // in case of createInstanceWithArgumentsXXX() called m_bIsValid is set to reset
+ // and then set to true when initialisation is complete
+ bool m_bIsValid;
+ // m_bInitialised ensure initialisation only takes place once.
+ bool m_bInitialised;
+ bool m_bIsPkgMSP;
+ css::uno::Reference< css::script::provider::XScriptProvider > m_xMSPPkg;
+ std::unique_ptr<ProviderCache> m_pPCache;
+ std::mutex m_mutex;
+ OUString m_sCtxString;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/MasterScriptProviderFactory.cxx b/scripting/source/provider/MasterScriptProviderFactory.cxx
new file mode 100644
index 000000000..acdb8f8da
--- /dev/null
+++ b/scripting/source/provider/MasterScriptProviderFactory.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 <cppuhelper/supportsservice.hxx>
+
+#include "MasterScriptProviderFactory.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::script;
+
+namespace func_provider
+{
+
+MasterScriptProviderFactory::MasterScriptProviderFactory(
+ Reference< XComponentContext > const & xComponentContext )
+ : m_xComponentContext( xComponentContext )
+{
+}
+
+MasterScriptProviderFactory::~MasterScriptProviderFactory()
+{
+}
+
+Reference< provider::XScriptProvider > SAL_CALL
+MasterScriptProviderFactory::createScriptProvider( const Any& context )
+{
+ Reference< provider::XScriptProvider > xMsp( getActiveMSPList() ->getMSPFromAnyContext( context ), UNO_SET_THROW );
+ return xMsp;
+}
+
+const rtl::Reference< ActiveMSPList > &
+MasterScriptProviderFactory::getActiveMSPList() const
+{
+ if ( !m_MSPList.is() )
+ {
+ ::osl::MutexGuard guard( ::osl::Mutex::getGlobalMutex() );
+ if ( !m_MSPList.is() )
+ m_MSPList = new ActiveMSPList( m_xComponentContext );
+ }
+ return m_MSPList;
+}
+
+OUString SAL_CALL MasterScriptProviderFactory::getImplementationName()
+{
+ return "com.sun.star.script.provider.MasterScriptProviderFactory";
+}
+
+Sequence< OUString > SAL_CALL MasterScriptProviderFactory::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.provider.MasterScriptProviderFactory" };
+}
+
+sal_Bool MasterScriptProviderFactory::supportsService(
+ OUString const & serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+} // namespace func_provider
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scripting_MasterScriptProviderFactory_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new func_provider::MasterScriptProviderFactory(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/MasterScriptProviderFactory.hxx b/scripting/source/provider/MasterScriptProviderFactory.hxx
new file mode 100644
index 000000000..9fbc8705d
--- /dev/null
+++ b/scripting/source/provider/MasterScriptProviderFactory.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 <rtl/ustring.hxx>
+#include <rtl/ref.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <com/sun/star/script/provider/XScriptProviderFactory.hpp>
+#include <com/sun/star/script/provider/XScriptProvider.hpp>
+
+#include "ActiveMSPList.hxx"
+
+namespace func_provider
+{
+
+class MasterScriptProviderFactory :
+ public ::cppu::WeakImplHelper <
+ css::script::provider::XScriptProviderFactory,
+ css::lang::XServiceInfo >
+{
+private:
+
+ mutable rtl::Reference< ActiveMSPList > m_MSPList;
+
+ const css::uno::Reference< css::uno::XComponentContext > m_xComponentContext;
+
+ const rtl::Reference< ActiveMSPList > & getActiveMSPList() const;
+
+protected:
+ virtual ~MasterScriptProviderFactory() override;
+
+public:
+ explicit MasterScriptProviderFactory(
+ css::uno::Reference< css::uno::XComponentContext > const & xComponentContext );
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL
+ supportsService( OUString const & serviceName ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL
+ getSupportedServiceNames() override;
+
+ // XScriptProviderFactory
+ virtual css::uno::Reference< css::script::provider::XScriptProvider >
+ SAL_CALL createScriptProvider( const css::uno::Any& context ) override;
+};
+
+
+} // namespace func_provider
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/ProviderCache.cxx b/scripting/source/provider/ProviderCache.cxx
new file mode 100644
index 000000000..8533fc384
--- /dev/null
+++ b/scripting/source/provider/ProviderCache.cxx
@@ -0,0 +1,203 @@
+/* -*- 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 <comphelper/sequence.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include "ProviderCache.hxx"
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::script;
+
+namespace func_provider
+{
+
+ProviderCache::ProviderCache( const Reference< XComponentContext >& xContext, const Sequence< Any >& scriptContext ) : m_Sctx( scriptContext ), m_xContext( xContext )
+{
+ // initialise m_hProviderDetailsCache with details of ScriptProviders
+ // will use createContentEnumeration
+
+ m_xMgr = m_xContext->getServiceManager();
+ ENSURE_OR_THROW( m_xMgr.is(), "ProviderCache::ProviderCache() failed to obtain ServiceManager" );
+ populateCache();
+}
+
+
+ProviderCache::ProviderCache( const Reference< XComponentContext >& xContext, const Sequence< Any >& scriptContext, const Sequence< OUString >& denyList ) : m_sDenyList( denyList ), m_Sctx( scriptContext ), m_xContext( xContext )
+
+{
+ // initialise m_hProviderDetailsCache with details of ScriptProviders
+ // will use createContentEnumeration
+
+ m_xMgr = m_xContext->getServiceManager();
+ ENSURE_OR_THROW( m_xMgr.is(), "ProviderCache::ProviderCache() failed to obtain ServiceManager" );
+ populateCache();
+}
+
+ProviderCache::~ProviderCache()
+{
+}
+
+Reference< provider::XScriptProvider >
+ProviderCache::getProvider( const OUString& providerName )
+{
+ std::scoped_lock aGuard( m_mutex );
+ Reference< provider::XScriptProvider > provider;
+ ProviderDetails_hash::iterator h_it = m_hProviderDetailsCache.find( providerName );
+ if ( h_it != m_hProviderDetailsCache.end() )
+ {
+ if ( h_it->second.provider.is() )
+ {
+ provider = h_it->second.provider;
+ }
+ else
+ {
+ // need to create provider and insert into hash
+ provider = createProvider( h_it->second );
+ }
+ }
+ return provider;
+}
+
+Sequence < Reference< provider::XScriptProvider > >
+ProviderCache::getAllProviders()
+{
+ // need to create providers that haven't been created already
+ // so check what providers exist and what ones don't
+
+ std::scoped_lock aGuard( m_mutex );
+ Sequence < Reference< provider::XScriptProvider > > providers ( m_hProviderDetailsCache.size() );
+ // should assert if size !> 0
+ if ( !m_hProviderDetailsCache.empty() )
+ {
+ auto pproviders = providers.getArray();
+ sal_Int32 providerIndex = 0;
+ for (auto& rDetail : m_hProviderDetailsCache)
+ {
+ Reference<provider::XScriptProvider> xScriptProvider = rDetail.second.provider;
+ if ( xScriptProvider.is() )
+ {
+ pproviders[ providerIndex++ ] = xScriptProvider;
+ }
+ else
+ {
+ // create provider
+ try
+ {
+ xScriptProvider = createProvider(rDetail.second);
+ pproviders[ providerIndex++ ] = xScriptProvider;
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+ }
+ }
+
+ if (providerIndex < providers.getLength())
+ {
+ providers.realloc( providerIndex );
+ }
+
+ }
+ else
+ {
+ SAL_WARN("scripting", "no available providers, something very wrong!!!");
+ }
+ return providers;
+}
+
+void
+ProviderCache::populateCache()
+{
+ // wrong name in services.rdb
+ OUString serviceName;
+ std::scoped_lock aGuard( m_mutex );
+ try
+ {
+ Reference< container::XContentEnumerationAccess > xEnumAccess( m_xMgr, UNO_QUERY_THROW );
+ Reference< container::XEnumeration > xEnum = xEnumAccess->createContentEnumeration ( "com.sun.star.script.provider.LanguageScriptProvider" );
+
+ while ( xEnum->hasMoreElements() )
+ {
+
+ Reference< lang::XSingleComponentFactory > factory( xEnum->nextElement(), UNO_QUERY_THROW );
+ Reference< lang::XServiceInfo > xServiceInfo( factory, UNO_QUERY_THROW );
+
+ const Sequence< OUString > serviceNames = xServiceInfo->getSupportedServiceNames();
+
+ if ( serviceNames.hasElements() )
+ {
+ auto pName = std::find_if(serviceNames.begin(), serviceNames.end(),
+ [this](const OUString& rName) {
+ return rName.startsWith("com.sun.star.script.provider.ScriptProviderFor")
+ && !isInDenyList(rName);
+ });
+ if (pName != serviceNames.end())
+ {
+ serviceName = *pName;
+ ProviderDetails details;
+ details.factory = factory;
+ m_hProviderDetailsCache[ serviceName ] = details;
+ }
+ }
+ }
+ }
+ catch ( const Exception &e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "ProviderCache::populateCache: couldn't obtain XSingleComponentFactory for " + serviceName
+ + " " + e.Message,
+ nullptr, anyEx );
+ }
+}
+
+Reference< provider::XScriptProvider >
+ProviderCache::createProvider( ProviderDetails& details )
+{
+ try
+ {
+ details.provider.set(
+ details.factory->createInstanceWithArgumentsAndContext( m_Sctx, m_xContext ), UNO_QUERY_THROW );
+ }
+ catch ( const Exception& e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "ProviderCache::createProvider() Error creating provider from factory. " + e.Message,
+ nullptr, anyEx );
+ }
+
+ return details.provider;
+}
+
+bool
+ProviderCache::isInDenyList( const OUString& serviceName ) const
+{
+ return comphelper::findValue(m_sDenyList, serviceName) != -1;
+}
+} //end namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/ProviderCache.hxx b/scripting/source/provider/ProviderCache.hxx
new file mode 100644
index 000000000..b565d1d08
--- /dev/null
+++ b/scripting/source/provider/ProviderCache.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 <rtl/ustring.hxx>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+
+#include <com/sun/star/script/provider/XScriptProvider.hpp>
+
+#include <mutex>
+#include <unordered_map>
+
+namespace func_provider
+{
+
+//Typedefs
+
+
+struct ProviderDetails
+{
+ //css::uno::Reference< css::lang::XSingleServiceFactory > factory;
+ css::uno::Reference< css::lang::XSingleComponentFactory > factory;
+ css::uno::Reference< css::script::provider::XScriptProvider > provider;
+};
+typedef std::unordered_map < OUString, ProviderDetails > ProviderDetails_hash;
+
+
+class ProviderCache
+{
+
+public:
+ /// @throws css::uno::RuntimeException
+ ProviderCache( const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Sequence< css::uno::Any >& scriptContext );
+ /// @throws css::uno::RuntimeException
+ ProviderCache( const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Sequence< css::uno::Any >& scriptContext,
+ const css::uno::Sequence< OUString >& denyList );
+ ~ProviderCache();
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ getProvider( const OUString& providerName );
+ /// @throws css::uno::RuntimeException
+ css::uno::Sequence < css::uno::Reference< css::script::provider::XScriptProvider > >
+ getAllProviders();
+private:
+ /// @throws css::uno::RuntimeException
+ void populateCache();
+
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ createProvider( ProviderDetails& details );
+ bool isInDenyList( const OUString& serviceName ) const;
+ css::uno::Sequence< OUString > m_sDenyList;
+ ProviderDetails_hash m_hProviderDetailsCache;
+ std::mutex m_mutex;
+ css::uno::Sequence< css::uno::Any > m_Sctx;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::lang::XMultiComponentFactory > m_xMgr;
+
+
+};
+} // func_provider
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/URIHelper.cxx b/scripting/source/provider/URIHelper.cxx
new file mode 100644
index 000000000..5333bee34
--- /dev/null
+++ b/scripting/source/provider/URIHelper.cxx
@@ -0,0 +1,256 @@
+/* -*- 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_folders.h>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <osl/diagnose.h>
+#include "URIHelper.hxx"
+
+namespace func_provider
+{
+
+namespace uno = ::com::sun::star::uno;
+namespace ucb = ::com::sun::star::ucb;
+namespace lang = ::com::sun::star::lang;
+namespace uri = ::com::sun::star::uri;
+
+constexpr OUStringLiteral SHARE = u"share";
+
+constexpr OUStringLiteral SHARE_UNO_PACKAGES_URI =
+ u"vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE";
+
+constexpr OUStringLiteral USER = u"user";
+constexpr OUStringLiteral USER_URI =
+ u"vnd.sun.star.expand:${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}";
+
+
+
+ScriptingFrameworkURIHelper::ScriptingFrameworkURIHelper(
+ const uno::Reference< uno::XComponentContext >& xContext)
+{
+ try
+ {
+ m_xSimpleFileAccess = ucb::SimpleFileAccess::create(xContext);
+ }
+ catch (uno::Exception&)
+ {
+ OSL_FAIL("Scripting Framework error initialising XSimpleFileAccess");
+ }
+
+ try
+ {
+ m_xUriReferenceFactory = uri::UriReferenceFactory::create( xContext );
+ }
+ catch (uno::Exception&)
+ {
+ OSL_FAIL("Scripting Framework error initialising XUriReferenceFactory");
+ }
+}
+
+ScriptingFrameworkURIHelper::~ScriptingFrameworkURIHelper()
+{
+ // currently does nothing
+}
+
+void SAL_CALL
+ScriptingFrameworkURIHelper::initialize(
+ const uno::Sequence < uno::Any >& args )
+{
+ if ( args.getLength() != 2 ||
+ args[0].getValueType() != ::cppu::UnoType<OUString>::get() ||
+ args[1].getValueType() != ::cppu::UnoType<OUString>::get() )
+ {
+ throw uno::RuntimeException( "ScriptingFrameworkURIHelper got invalid argument list" );
+ }
+
+ if ( !(args[0] >>= m_sLanguage) || !(args[1] >>= m_sLocation) )
+ {
+ throw uno::RuntimeException( "ScriptingFrameworkURIHelper error parsing args" );
+ }
+
+ SCRIPTS_PART = "/Scripts/" + m_sLanguage.toAsciiLowerCase();
+
+ if ( !initBaseURI() )
+ {
+ throw uno::RuntimeException( "ScriptingFrameworkURIHelper cannot find script directory" );
+ }
+}
+
+bool
+ScriptingFrameworkURIHelper::initBaseURI()
+{
+ OUString uri, test;
+ bool bAppendScriptsPart = false;
+
+ if ( m_sLocation == USER )
+ {
+ test = USER;
+ uri = USER_URI;
+ bAppendScriptsPart = true;
+ }
+ else if ( m_sLocation == "user:uno_packages" )
+ {
+ test = "uno_packages";
+ uri = USER_URI + "/user/uno_packages/cache";
+ }
+ else if (m_sLocation == SHARE)
+ {
+ test = SHARE;
+ uri = "vnd.sun.star.expand:$BRAND_BASE_DIR";
+ bAppendScriptsPart = true;
+ }
+ else if (m_sLocation == "share:uno_packages")
+ {
+ test = "uno_packages";
+ uri = SHARE_UNO_PACKAGES_URI;
+ }
+ else if (m_sLocation.startsWith("vnd.sun.star.tdoc"))
+ {
+ m_sBaseURI = m_sLocation + SCRIPTS_PART;
+ m_sLocation = "document";
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+ if ( !m_xSimpleFileAccess->exists( uri ) ||
+ !m_xSimpleFileAccess->isFolder( uri ) )
+ {
+ return false;
+ }
+
+ const uno::Sequence< OUString > children =
+ m_xSimpleFileAccess->getFolderContents( uri, true );
+
+ auto pChild = std::find_if(children.begin(), children.end(), [&test](const OUString& child) {
+ sal_Int32 idx = child.lastIndexOf(test);
+ return idx != -1 && (idx + test.getLength()) == child.getLength();
+ });
+ if (pChild != children.end())
+ {
+ if ( bAppendScriptsPart )
+ {
+ m_sBaseURI = *pChild + SCRIPTS_PART;
+ }
+ else
+ {
+ m_sBaseURI = *pChild;
+ }
+ return true;
+ }
+ return false;
+}
+
+OUString
+ScriptingFrameworkURIHelper::getLanguagePart(std::u16string_view rStorageURI)
+{
+ OUString result;
+
+ size_t idx = rStorageURI.find(m_sBaseURI);
+ sal_Int32 len = m_sBaseURI.getLength() + 1;
+
+ if ( idx != std::u16string_view::npos )
+ {
+ result = rStorageURI.substr(idx + len);
+ result = result.replace('/', '|');
+ }
+ return result;
+}
+
+OUString
+ScriptingFrameworkURIHelper::getLanguagePath(const OUString& rLanguagePart)
+{
+ OUString result = rLanguagePart.replace('|', '/');
+ return result;
+}
+
+OUString SAL_CALL
+ScriptingFrameworkURIHelper::getScriptURI(const OUString& rStorageURI)
+{
+ return
+ "vnd.sun.star.script:" +
+ getLanguagePart(rStorageURI) +
+ "?language=" +
+ m_sLanguage +
+ "&location=" +
+ m_sLocation;
+}
+
+OUString SAL_CALL
+ScriptingFrameworkURIHelper::getStorageURI(const OUString& rScriptURI)
+{
+ OUString sLanguagePart;
+ try
+ {
+ uno::Reference < uri::XVndSunStarScriptUrl > xURI(
+ m_xUriReferenceFactory->parse( rScriptURI ), uno::UNO_QUERY_THROW );
+ sLanguagePart = xURI->getName();
+ }
+ catch ( uno::Exception& )
+ {
+ throw lang::IllegalArgumentException(
+ "Script URI not valid",
+ uno::Reference< uno::XInterface >(), 1 );
+ }
+
+ return m_sBaseURI + "/" + getLanguagePath(sLanguagePart);
+}
+
+OUString SAL_CALL
+ScriptingFrameworkURIHelper::getRootStorageURI()
+{
+ return m_sBaseURI;
+}
+
+OUString SAL_CALL
+ScriptingFrameworkURIHelper::getImplementationName()
+{
+ return
+ "com.sun.star.script.provider.ScriptURIHelper";
+}
+
+sal_Bool SAL_CALL
+ScriptingFrameworkURIHelper::supportsService( const OUString& serviceName )
+{
+ return cppu::supportsService( this, serviceName );
+}
+
+uno::Sequence< OUString > SAL_CALL
+ScriptingFrameworkURIHelper::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.provider.ScriptURIHelper" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scripting_ScriptingFrameworkURIHelper_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ScriptingFrameworkURIHelper(context));
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/URIHelper.hxx b/scripting/source/provider/URIHelper.hxx
new file mode 100644
index 000000000..9d200a1a3
--- /dev/null
+++ b/scripting/source/provider/URIHelper.hxx
@@ -0,0 +1,87 @@
+/* -*- 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/provider/XScriptURIHelper.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
+#include <com/sun/star/uri/XUriReferenceFactory.hpp>
+
+#include <rtl/ustring.hxx>
+#include <cppuhelper/implbase.hxx>
+
+namespace func_provider
+{
+
+class ScriptingFrameworkURIHelper :
+ public ::cppu::WeakImplHelper<
+ css::script::provider::XScriptURIHelper,
+ css::lang::XServiceInfo,
+ css::lang::XInitialization >
+{
+private:
+
+ css::uno::Reference< css::ucb::XSimpleFileAccess3 > m_xSimpleFileAccess;
+ css::uno::Reference<css::uri::XUriReferenceFactory> m_xUriReferenceFactory;
+
+ OUString m_sLanguage;
+ OUString m_sLocation;
+ OUString m_sBaseURI;
+
+ OUString SCRIPTS_PART;
+
+ bool initBaseURI();
+ OUString getLanguagePart(std::u16string_view rStorageURI);
+ static OUString getLanguagePath(const OUString& rLanguagePart);
+
+public:
+ /// @throws css::uno::RuntimeException
+ explicit ScriptingFrameworkURIHelper(
+ const css::uno::Reference< css::uno::XComponentContext >& xContext );
+
+ virtual ~ScriptingFrameworkURIHelper() override;
+
+ virtual void SAL_CALL
+ initialize( const css::uno::Sequence < css::uno::Any > & args ) override;
+
+ virtual OUString SAL_CALL
+ getRootStorageURI() override;
+
+ virtual OUString SAL_CALL
+ getScriptURI( const OUString& rStorageURI ) override;
+
+ virtual OUString SAL_CALL
+ getStorageURI( const OUString& rScriptURI ) override;
+
+ 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;
+};
+
+} // namespace func_provider
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/pyprov/mailmerge.README b/scripting/source/pyprov/mailmerge.README
new file mode 100644
index 000000000..6b4fb5ba4
--- /dev/null
+++ b/scripting/source/pyprov/mailmerge.README
@@ -0,0 +1,18 @@
+Easiest way I find to test this is to...
+
+1)
+
+a) install fakemail and run it
+b) tools->options->writer->mail merge email
+c) localhost 8025
+
+2)
+
+a) type some text into writer that will exercise utf-8, e.g. "Caolán's test"
+b) tools->mail merge wizard->next->email message->select address book
+c) create, add one user with your own email address, ok
+d) next, next, text, send merged document as email
+e) and test all of plain text, html and the various attachment options
+
+fake mail will dump the mail it gets into its pwd, if all that works, you can
+then try with your own normal mail server.
diff --git a/scripting/source/pyprov/mailmerge.component b/scripting/source/pyprov/mailmerge.component
new file mode 100644
index 000000000..8a9325341
--- /dev/null
+++ b/scripting/source/pyprov/mailmerge.component
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.Python"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="org.openoffice.pyuno.MailMessage">
+ <service name="com.sun.star.mail.MailMessage"/>
+ </implementation>
+ <implementation name="org.openoffice.pyuno.MailServiceProvider">
+ <service name="com.sun.star.mail.MailServiceProvider"/>
+ </implementation>
+</component>
diff --git a/scripting/source/pyprov/mailmerge.py b/scripting/source/pyprov/mailmerge.py
new file mode 100644
index 000000000..0ef37b477
--- /dev/null
+++ b/scripting/source/pyprov/mailmerge.py
@@ -0,0 +1,503 @@
+# Caolan McNamara caolanm@redhat.com
+# a simple email mailmerge component
+
+# manual installation for hackers, not necessary for users
+# cp mailmerge.py /usr/lib/libreoffice/program
+# cd /usr/lib/libreoffice/program
+# ./unopkg add --shared mailmerge.py
+# edit ~/.openoffice.org2/user/registry/data/org/openoffice/Office/Writer.xcu
+# and change EMailSupported to as follows...
+# <prop oor:name="EMailSupported" oor:type="xs:boolean">
+# <value>true</value>
+# </prop>
+
+import unohelper
+import uno
+import re
+import os
+import encodings.idna
+
+#to implement com::sun::star::mail::XMailServiceProvider
+#and
+#to implement com.sun.star.mail.XMailMessage
+
+from com.sun.star.mail import XMailServiceProvider
+from com.sun.star.mail import XMailService
+from com.sun.star.mail import XSmtpService
+from com.sun.star.mail import XConnectionListener
+from com.sun.star.mail import XAuthenticator
+from com.sun.star.mail import XMailMessage
+from com.sun.star.mail.MailServiceType import SMTP
+from com.sun.star.mail.MailServiceType import POP3
+from com.sun.star.mail.MailServiceType import IMAP
+from com.sun.star.uno import XCurrentContext
+from com.sun.star.lang import IllegalArgumentException
+from com.sun.star.lang import EventObject
+from com.sun.star.lang import XServiceInfo
+from com.sun.star.mail import SendMailMessageFailedException
+
+from email.mime.base import MIMEBase
+from email.message import Message
+from email.charset import Charset
+from email.charset import QP
+from email.encoders import encode_base64
+from email.header import Header
+from email.mime.multipart import MIMEMultipart
+from email.utils import formatdate
+from email.utils import parseaddr
+from socket import _GLOBAL_DEFAULT_TIMEOUT
+
+import sys, smtplib, imaplib, poplib
+dbg = False
+
+# pythonloader looks for a static g_ImplementationHelper variable
+g_ImplementationHelper = unohelper.ImplementationHelper()
+g_providerImplName = "org.openoffice.pyuno.MailServiceProvider"
+g_messageImplName = "org.openoffice.pyuno.MailMessage"
+
+class PyMailSMTPService(unohelper.Base, XSmtpService):
+ def __init__( self, ctx ):
+ self.ctx = ctx
+ self.listeners = []
+ self.supportedtypes = ('Insecure', 'Ssl')
+ self.server = None
+ self.connectioncontext = None
+ self.notify = EventObject(self)
+ if dbg:
+ print("PyMailSMTPService init", file=sys.stderr)
+ print("python version is: " + sys.version, file=sys.stderr)
+ def addConnectionListener(self, xListener):
+ if dbg:
+ print("PyMailSMTPService addConnectionListener", file=sys.stderr)
+ self.listeners.append(xListener)
+ def removeConnectionListener(self, xListener):
+ if dbg:
+ print("PyMailSMTPService removeConnectionListener", file=sys.stderr)
+ self.listeners.remove(xListener)
+ def getSupportedConnectionTypes(self):
+ if dbg:
+ print("PyMailSMTPService getSupportedConnectionTypes", file=sys.stderr)
+ return self.supportedtypes
+ def connect(self, xConnectionContext, xAuthenticator):
+ self.connectioncontext = xConnectionContext
+ if dbg:
+ print("PyMailSMTPService connect", file=sys.stderr)
+ server = xConnectionContext.getValueByName("ServerName").strip()
+ if dbg:
+ print("ServerName: " + server, file=sys.stderr)
+ port = int(xConnectionContext.getValueByName("Port"))
+ if dbg:
+ print("Port: " + str(port), file=sys.stderr)
+ tout = xConnectionContext.getValueByName("Timeout")
+ if dbg:
+ print(isinstance(tout,int), file=sys.stderr)
+ if not isinstance(tout,int):
+ tout = _GLOBAL_DEFAULT_TIMEOUT
+ if dbg:
+ print("Timeout: " + str(tout), file=sys.stderr)
+ if port == 465:
+ self.server = smtplib.SMTP_SSL(server, port,timeout=tout)
+ else:
+ self.server = smtplib.SMTP(server, port,timeout=tout)
+
+ if dbg:
+ self.server.set_debuglevel(1)
+
+ connectiontype = xConnectionContext.getValueByName("ConnectionType")
+ if dbg:
+ print("ConnectionType: " + connectiontype, file=sys.stderr)
+ if connectiontype.upper() == 'SSL' and port != 465:
+ self.server.ehlo()
+ self.server.starttls()
+ self.server.ehlo()
+
+ user = xAuthenticator.getUserName()
+ password = xAuthenticator.getPassword()
+ if user != '':
+ if dbg:
+ print("Logging in, username of: " + user, file=sys.stderr)
+ self.server.login(user, password)
+
+ for listener in self.listeners:
+ listener.connected(self.notify)
+ def disconnect(self):
+ if dbg:
+ print("PyMailSMTPService disconnect", file=sys.stderr)
+ if self.server:
+ self.server.quit()
+ self.server = None
+ for listener in self.listeners:
+ listener.disconnected(self.notify)
+ def isConnected(self):
+ if dbg:
+ print("PyMailSMTPService isConnected", file=sys.stderr)
+ return self.server != None
+ def getCurrentConnectionContext(self):
+ if dbg:
+ print("PyMailSMTPService getCurrentConnectionContext", file=sys.stderr)
+ return self.connectioncontext
+ def sendMailMessage(self, xMailMessage):
+ COMMASPACE = ', '
+
+ if dbg:
+ print("PyMailSMTPService sendMailMessage", file=sys.stderr)
+ recipients = xMailMessage.getRecipients()
+ sendermail = xMailMessage.SenderAddress
+ sendername = xMailMessage.SenderName
+ subject = xMailMessage.Subject
+ ccrecipients = xMailMessage.getCcRecipients()
+ bccrecipients = xMailMessage.getBccRecipients()
+ if dbg:
+ print("PyMailSMTPService subject: " + subject, file=sys.stderr)
+ print("PyMailSMTPService from: " + sendername, file=sys.stderr)
+ print("PyMailSMTPService from: " + sendermail, file=sys.stderr)
+ print("PyMailSMTPService send to: %s" % (recipients,), file=sys.stderr)
+
+ attachments = xMailMessage.getAttachments()
+
+ textmsg = Message()
+
+ content = xMailMessage.Body
+ flavors = content.getTransferDataFlavors()
+ if dbg:
+ print("PyMailSMTPService flavors len: %d" % (len(flavors),), file=sys.stderr)
+
+ #Use first flavor that's sane for an email body
+ for flavor in flavors:
+ if flavor.MimeType.find('text/html') != -1 or flavor.MimeType.find('text/plain') != -1:
+ if dbg:
+ print("PyMailSMTPService mimetype is: " + flavor.MimeType, file=sys.stderr)
+ textbody = content.getTransferData(flavor)
+
+ if len(textbody):
+ mimeEncoding = re.sub("charset=.*", "charset=UTF-8", flavor.MimeType)
+ if mimeEncoding.find('charset=UTF-8') == -1:
+ mimeEncoding = mimeEncoding + "; charset=UTF-8"
+ textmsg['Content-Type'] = mimeEncoding
+ textmsg['MIME-Version'] = '1.0'
+
+ try:
+ #it's a string, get it as utf-8 bytes
+ textbody = textbody.encode('utf-8')
+ except:
+ #it's a bytesequence, get raw bytes
+ textbody = textbody.value
+ textbody = textbody.decode('utf-8')
+ c = Charset('utf-8')
+ c.body_encoding = QP
+ textmsg.set_payload(textbody, c)
+
+ break
+
+ if (len(attachments)):
+ msg = MIMEMultipart()
+ msg.epilogue = ''
+ msg.attach(textmsg)
+ else:
+ msg = textmsg
+
+ hdr = Header(sendername, 'utf-8')
+ hdr.append('<'+sendermail+'>','us-ascii')
+ msg['Subject'] = subject
+ msg['From'] = hdr
+ msg['To'] = COMMASPACE.join(recipients)
+ if len(ccrecipients):
+ msg['Cc'] = COMMASPACE.join(ccrecipients)
+ if xMailMessage.ReplyToAddress != '':
+ msg['Reply-To'] = xMailMessage.ReplyToAddress
+
+ mailerstring = "LibreOffice via Caolan's mailmerge component"
+ try:
+ ctx = uno.getComponentContext()
+ aConfigProvider = ctx.ServiceManager.createInstance("com.sun.star.configuration.ConfigurationProvider")
+ prop = uno.createUnoStruct('com.sun.star.beans.PropertyValue')
+ prop.Name = "nodepath"
+ prop.Value = "/org.openoffice.Setup/Product"
+ aSettings = aConfigProvider.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess",
+ (prop,))
+ mailerstring = aSettings.getByName("ooName") + " " + \
+ aSettings.getByName("ooSetupVersion") + " via Caolan's mailmerge component"
+ except:
+ pass
+
+ msg['X-Mailer'] = mailerstring
+ msg['Date'] = formatdate(localtime=True)
+
+ for attachment in attachments:
+ content = attachment.Data
+ flavors = content.getTransferDataFlavors()
+ flavor = flavors[0]
+ ctype = flavor.MimeType
+ maintype, subtype = ctype.split('/', 1)
+ msgattachment = MIMEBase(maintype, subtype)
+ data = content.getTransferData(flavor)
+ msgattachment.set_payload(data.value)
+ encode_base64(msgattachment)
+ fname = attachment.ReadableName
+ try:
+ msgattachment.add_header('Content-Disposition', 'attachment', \
+ filename=fname)
+ except:
+ msgattachment.add_header('Content-Disposition', 'attachment', \
+ filename=('utf-8','',fname))
+ if dbg:
+ print(("PyMailSMTPService attachmentheader: ", str(msgattachment)), file=sys.stderr)
+
+ msg.attach(msgattachment)
+
+ uniquer = {}
+ for key in recipients:
+ uniquer[key] = True
+ if len(ccrecipients):
+ for key in ccrecipients:
+ uniquer[key] = True
+ if len(bccrecipients):
+ for key in bccrecipients:
+ uniquer[key] = True
+ truerecipients = uniquer.keys()
+
+ if dbg:
+ print(("PyMailSMTPService recipients are: ", truerecipients), file=sys.stderr)
+
+ self.server.sendmail(sendermail, truerecipients, msg.as_string())
+
+class PyMailIMAPService(unohelper.Base, XMailService):
+ def __init__( self, ctx ):
+ self.ctx = ctx
+ self.listeners = []
+ self.supportedtypes = ('Insecure', 'Ssl')
+ self.server = None
+ self.connectioncontext = None
+ self.notify = EventObject(self)
+ if dbg:
+ print("PyMailIMAPService init", file=sys.stderr)
+ def addConnectionListener(self, xListener):
+ if dbg:
+ print("PyMailIMAPService addConnectionListener", file=sys.stderr)
+ self.listeners.append(xListener)
+ def removeConnectionListener(self, xListener):
+ if dbg:
+ print("PyMailIMAPService removeConnectionListener", file=sys.stderr)
+ self.listeners.remove(xListener)
+ def getSupportedConnectionTypes(self):
+ if dbg:
+ print("PyMailIMAPService getSupportedConnectionTypes", file=sys.stderr)
+ return self.supportedtypes
+ def connect(self, xConnectionContext, xAuthenticator):
+ if dbg:
+ print("PyMailIMAPService connect", file=sys.stderr)
+
+ self.connectioncontext = xConnectionContext
+ server = xConnectionContext.getValueByName("ServerName")
+ if dbg:
+ print(server, file=sys.stderr)
+ port = int(xConnectionContext.getValueByName("Port"))
+ if dbg:
+ print(port, file=sys.stderr)
+ connectiontype = xConnectionContext.getValueByName("ConnectionType")
+ if dbg:
+ print(connectiontype, file=sys.stderr)
+ print("BEFORE", file=sys.stderr)
+ if connectiontype.upper() == 'SSL':
+ self.server = imaplib.IMAP4_SSL(server, port)
+ else:
+ self.server = imaplib.IMAP4(server, port)
+ print("AFTER", file=sys.stderr)
+
+ user = xAuthenticator.getUserName()
+ password = xAuthenticator.getPassword()
+ if user != '':
+ if dbg:
+ print("Logging in, username of: " + user, file=sys.stderr)
+ self.server.login(user, password)
+
+ for listener in self.listeners:
+ listener.connected(self.notify)
+ def disconnect(self):
+ if dbg:
+ print("PyMailIMAPService disconnect", file=sys.stderr)
+ if self.server:
+ self.server.logout()
+ self.server = None
+ for listener in self.listeners:
+ listener.disconnected(self.notify)
+ def isConnected(self):
+ if dbg:
+ print("PyMailIMAPService isConnected", file=sys.stderr)
+ return self.server != None
+ def getCurrentConnectionContext(self):
+ if dbg:
+ print("PyMailIMAPService getCurrentConnectionContext", file=sys.stderr)
+ return self.connectioncontext
+
+class PyMailPOP3Service(unohelper.Base, XMailService):
+ def __init__( self, ctx ):
+ self.ctx = ctx
+ self.listeners = []
+ self.supportedtypes = ('Insecure', 'Ssl')
+ self.server = None
+ self.connectioncontext = None
+ self.notify = EventObject(self)
+ if dbg:
+ print("PyMailPOP3Service init", file=sys.stderr)
+ def addConnectionListener(self, xListener):
+ if dbg:
+ print("PyMailPOP3Service addConnectionListener", file=sys.stderr)
+ self.listeners.append(xListener)
+ def removeConnectionListener(self, xListener):
+ if dbg:
+ print("PyMailPOP3Service removeConnectionListener", file=sys.stderr)
+ self.listeners.remove(xListener)
+ def getSupportedConnectionTypes(self):
+ if dbg:
+ print("PyMailPOP3Service getSupportedConnectionTypes", file=sys.stderr)
+ return self.supportedtypes
+ def connect(self, xConnectionContext, xAuthenticator):
+ if dbg:
+ print("PyMailPOP3Service connect", file=sys.stderr)
+
+ self.connectioncontext = xConnectionContext
+ server = xConnectionContext.getValueByName("ServerName")
+ if dbg:
+ print(server, file=sys.stderr)
+ port = int(xConnectionContext.getValueByName("Port"))
+ if dbg:
+ print(port, file=sys.stderr)
+ connectiontype = xConnectionContext.getValueByName("ConnectionType")
+ if dbg:
+ print(connectiontype, file=sys.stderr)
+ print("BEFORE", file=sys.stderr)
+ if connectiontype.upper() == 'SSL':
+ self.server = poplib.POP3_SSL(server, port)
+ else:
+ tout = xConnectionContext.getValueByName("Timeout")
+ if dbg:
+ print(isinstance(tout,int), file=sys.stderr)
+ if not isinstance(tout,int):
+ tout = _GLOBAL_DEFAULT_TIMEOUT
+ if dbg:
+ print("Timeout: " + str(tout), file=sys.stderr)
+ self.server = poplib.POP3(server, port, timeout=tout)
+ print("AFTER", file=sys.stderr)
+
+ user = xAuthenticator.getUserName()
+ password = xAuthenticator.getPassword()
+ if dbg:
+ print("Logging in, username of: " + user, file=sys.stderr)
+ self.server.user(user)
+ self.server.pass_(password)
+
+ for listener in self.listeners:
+ listener.connected(self.notify)
+ def disconnect(self):
+ if dbg:
+ print("PyMailPOP3Service disconnect", file=sys.stderr)
+ if self.server:
+ self.server.quit()
+ self.server = None
+ for listener in self.listeners:
+ listener.disconnected(self.notify)
+ def isConnected(self):
+ if dbg:
+ print("PyMailPOP3Service isConnected", file=sys.stderr)
+ return self.server != None
+ def getCurrentConnectionContext(self):
+ if dbg:
+ print("PyMailPOP3Service getCurrentConnectionContext", file=sys.stderr)
+ return self.connectioncontext
+
+class PyMailServiceProvider(unohelper.Base, XMailServiceProvider, XServiceInfo):
+ def __init__( self, ctx ):
+ if dbg:
+ print("PyMailServiceProvider init", file=sys.stderr)
+ self.ctx = ctx
+ def create(self, aType):
+ if dbg:
+ print("PyMailServiceProvider create with", aType, file=sys.stderr)
+ if aType == SMTP:
+ return PyMailSMTPService(self.ctx);
+ elif aType == POP3:
+ return PyMailPOP3Service(self.ctx);
+ elif aType == IMAP:
+ return PyMailIMAPService(self.ctx);
+ else:
+ print("PyMailServiceProvider, unknown TYPE " + aType, file=sys.stderr)
+
+ def getImplementationName(self):
+ return g_providerImplName
+
+ def supportsService(self, ServiceName):
+ return g_ImplementationHelper.supportsService(g_providerImplName, ServiceName)
+
+ def getSupportedServiceNames(self):
+ return g_ImplementationHelper.getSupportedServiceNames(g_providerImplName)
+
+class PyMailMessage(unohelper.Base, XMailMessage):
+ def __init__( self, ctx, sTo='', sFrom='', Subject='', Body=None, aMailAttachment=None ):
+ if dbg:
+ print("PyMailMessage init", file=sys.stderr)
+ self.ctx = ctx
+
+ self.recipients = [sTo]
+ self.ccrecipients = []
+ self.bccrecipients = []
+ self.aMailAttachments = []
+ if aMailAttachment != None:
+ self.aMailAttachments.append(aMailAttachment)
+
+ self.SenderName, self.SenderAddress = parseaddr(sFrom)
+ self.ReplyToAddress = sFrom
+ self.Subject = Subject
+ self.Body = Body
+ if dbg:
+ print("post PyMailMessage init", file=sys.stderr)
+ def addRecipient( self, recipient ):
+ if dbg:
+ print("PyMailMessage.addRecipient: " + recipient, file=sys.stderr)
+ self.recipients.append(recipient)
+ def addCcRecipient( self, ccrecipient ):
+ if dbg:
+ print("PyMailMessage.addCcRecipient: " + ccrecipient, file=sys.stderr)
+ self.ccrecipients.append(ccrecipient)
+ def addBccRecipient( self, bccrecipient ):
+ if dbg:
+ print("PyMailMessage.addBccRecipient: " + bccrecipient, file=sys.stderr)
+ self.bccrecipients.append(bccrecipient)
+ def getRecipients( self ):
+ if dbg:
+ print("PyMailMessage.getRecipients: " + str(self.recipients), file=sys.stderr)
+ return tuple(self.recipients)
+ def getCcRecipients( self ):
+ if dbg:
+ print("PyMailMessage.getCcRecipients: " + str(self.ccrecipients), file=sys.stderr)
+ return tuple(self.ccrecipients)
+ def getBccRecipients( self ):
+ if dbg:
+ print("PyMailMessage.getBccRecipients: " + str(self.bccrecipients), file=sys.stderr)
+ return tuple(self.bccrecipients)
+ def addAttachment( self, aMailAttachment ):
+ if dbg:
+ print("PyMailMessage.addAttachment", file=sys.stderr)
+ self.aMailAttachments.append(aMailAttachment)
+ def getAttachments( self ):
+ if dbg:
+ print("PyMailMessage.getAttachments", file=sys.stderr)
+ return tuple(self.aMailAttachments)
+
+ def getImplementationName(self):
+ return g_messageImplName
+
+ def supportsService(self, ServiceName):
+ return g_ImplementationHelper.supportsService(g_messageImplName, ServiceName)
+
+ def getSupportedServiceNames(self):
+ return g_ImplementationHelper.getSupportedServiceNames(g_messageImplName)
+
+g_ImplementationHelper.addImplementation( \
+ PyMailServiceProvider, g_providerImplName,
+ ("com.sun.star.mail.MailServiceProvider",),)
+g_ImplementationHelper.addImplementation( \
+ PyMailMessage, g_messageImplName,
+ ("com.sun.star.mail.MailMessage",),)
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/scripting/source/pyprov/msgbox.py b/scripting/source/pyprov/msgbox.py
new file mode 100644
index 000000000..f9c93df17
--- /dev/null
+++ b/scripting/source/pyprov/msgbox.py
@@ -0,0 +1,241 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-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/.
+#
+
+# prepare Python environment - Add the path of this class
+from os import path
+from sys import modules
+from sys import path as syspath
+
+# pyUNO program itself
+import uno, unohelper
+
+# UNO GUI toolkit
+from com.sun.star.awt.WindowClass import TOP, SIMPLE
+from com.sun.star.awt.PushButtonType import STANDARD as standard
+from com.sun.star.awt.PushButtonType import OK as ok
+from com.sun.star.awt.PushButtonType import CANCEL as cancel
+from com.sun.star.awt.PushButtonType import HELP as help
+from com.sun.star.awt.TextAlign import CENTER as center
+from com.sun.star.awt.TextAlign import LEFT as left
+from com.sun.star.awt.TextAlign import RIGHT as right
+
+# used UNO listeners
+from com.sun.star.awt import XActionListener
+
+class MsgBox(unohelper.Base):
+ """Inspect UNO object, link to sdk and recursive calls"""
+
+ def __init__(self, aContext):
+ """acontext : a Valid UNO context
+ """
+
+ self.VERSION = '0.1'
+ self.ctx = aContext
+ self.smgr = aContext.ServiceManager
+ # UI Dialog object
+ self.dialog=None
+ # List of opened Listeners
+ self.lst_listeners={}
+ #UI parameters
+ self.ButtonSize = 50
+ self.boxSize = 200
+ self.lineHeight = 10
+ self.fromBroxSize = False
+ self.numberOfLines = -1
+
+ self.Buttons = []
+ self.Response = ''
+
+ return
+
+ #####################################################
+ # GUI definition #
+ #####################################################
+ def _createBox(self):
+ """Create the Box"""
+
+ # computes parameters of the message dialog
+ if self.numberOfLines == -1:
+ #calculate
+ numberOfLines = len(self.message.split(chr(10)))
+ else:
+ numberOfLines = self.numberOfLines
+
+ numberOfButtons = len(self.Buttons)
+ self.ButtonSpace = self.ButtonSize/2
+ if self.fromBroxSize:
+ # button size is calculated from boxsize
+ size = (2 * self.boxSize) / (3 * numberOfButtons + 1)
+ self.ButtonSize = size
+ self.ButtonSpace = self.ButtonSize/2
+ else:
+ # boxsize is calculated from buttonsize
+ self.boxSize = numberOfButtons * (self.ButtonSize +
+ self.ButtonSpace) + self.ButtonSpace
+
+ # create the dialog model and set the properties
+ dialog_model = self.smgr.createInstanceWithContext(
+ 'com.sun.star.awt.UnoControlDialogModel',
+ self.ctx)
+ dialog_model.PositionX = 50
+ dialog_model.Step = 1
+ dialog_model.TabIndex = 7
+ dialog_model.Width = self.boxSize#numberOfButtons * (self.ButtonSize +
+ # self.ButtonSpace) + 25
+ dialog_model.Height = 10 + self.lineHeight * numberOfLines + 10 + 12 + 10
+ dialog_model.PositionY = 63
+ dialog_model.Sizeable = True
+ dialog_model.Closeable = False
+
+ dialog = self.smgr.createInstanceWithContext(
+ 'com.sun.star.awt.UnoControlDialog', self.ctx)
+
+ # label Label0
+ label = dialog_model.createInstance(
+ 'com.sun.star.awt.UnoControlFixedTextModel')
+ label.PositionX = 10
+ label.TabIndex = 9
+ label.Width = dialog_model.Width - label.PositionX
+ label.Height = self.lineHeight* numberOfLines
+ label.PositionY = 10
+ label.Align = left
+ label.MultiLine = True
+ label.Label = self.message
+ dialog_model.insertByName('Label0', label)
+
+ nb = 0
+ for buttonName in self.Buttons:
+ nb +=1
+ button = dialog_model.createInstance(
+ 'com.sun.star.awt.UnoControlButtonModel')
+ button.PositionX = nb * self.ButtonSpace + (nb-1)* self.ButtonSize
+ button.TabIndex = 8
+ button.Height = 12
+ button.Width = self.ButtonSize
+ button.PositionY = 10 + label.Height + 10
+ button.PushButtonType = standard
+ if nb == 1:
+ button.DefaultButton = True
+ else:
+ button.DefaultButton = False
+ button.Label = buttonName
+ dialog_model.insertByName('Btn' + str(nb), button )
+
+ if not dialog.getModel():
+ dialog.setModel(dialog_model)
+
+ # UNO toolkit definition
+ toolkit = self.smgr.createInstanceWithContext('com.sun.star.awt.Toolkit', self.ctx)
+ a_rect = uno.createUnoStruct( 'com.sun.star.awt.Rectangle' )
+ a_rect.X = 50
+ dialog.setTitle ( self.title )
+ a_rect.Width = 270
+ a_rect.Height = 261
+ a_rect.Y = 63
+ win_descriptor = uno.createUnoStruct('com.sun.star.awt.WindowDescriptor')
+ win_descriptor.Type = TOP
+ win_descriptor.ParentIndex = -1
+ win_descriptor.Bounds = a_rect
+ peer = toolkit.createWindow( win_descriptor )
+ dialog.createPeer( toolkit, peer )
+
+ return dialog
+
+ def _addListeners(self):
+ """Add listeners to dialog"""
+ nb = 0
+ for buttonName in self.Buttons:
+ nb +=1
+ a_control = self.dialog.getControl('Btn'+str(nb))
+ the_listener = ButtonListener(self)
+ a_control.addActionListener(the_listener)
+ self.lst_listeners['Btn'+str(nb)] = the_listener
+ return
+
+ def _removeListeners(self):
+ """ remove listeners on exiting"""
+ nb = 0
+ for buttonName in self.Buttons:
+ nb +=1
+ a_control = self.dialog.getControl('Btn'+str(nb))
+ a_control.removeActionListener(self.lst_listeners['Btn'+str(nb)])
+ return
+
+ def show(self, message, decoration, title):
+ self.message = message
+ self.decoration = decoration
+ self.title = title
+ # Create GUI
+ self.dialog = self._createBox()
+ self._addListeners()
+ #execute the dialog --> blocking call
+ self.dialog.execute()
+ #end --> release listeners and dispose dialog
+ self._removeListeners()
+ self.dialog.dispose()
+ return self.Response
+
+ def addButton(self, caption):
+ self.Buttons.append(caption)
+ return
+
+ def renderFromBoxSize(self, size = 150):
+ self.boxSize = size
+ self.fromBroxSize = True
+ return
+
+ def renderFromButtonSize(self, size = 50):
+ self.ButtonSize = size
+ self.fromBroxSize = False
+ return
+
+class ButtonListener(unohelper.Base, XActionListener):
+ """Stops the MessageBox, sets the button label as returned value"""
+ def __init__(self, caller):
+ self.caller = caller
+
+ def disposing(self, eventObject):
+ pass
+
+ def actionPerformed(self, actionEvent):
+ button = actionEvent.Source
+ self.caller.Response = button.Model.Label
+ self.caller.dialog.endExecute()
+ return
+
+### TEST
+if __name__ == '__main__':
+ # get the uno component context from the PyUNO runtime
+ localContext = uno.getComponentContext()
+
+ # create the UnoUrlResolver
+ resolver = localContext.ServiceManager.createInstanceWithContext(
+ "com.sun.star.bridge.UnoUrlResolver", localContext )
+
+ # connect to the running office
+ # LibO has to be launched in listen mode as
+ # ./soffice "--accept=socket,host=localhost,port=2002;urp;"
+ ctx = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" )
+ myBox = MsgBox(ctx)
+ myBox.addButton("Yes")
+ myBox.addButton("No")
+ myBox.addButton("May be")
+ myBox.renderFromBoxSize(150)
+ myBox.numberOflines = 2
+
+ print(myBox.show("A very long message A very long message A very long message A very long message A very long message A very long message A very long message A very long message A very long message A very long message " + chr(10)+chr(10)+"Do you agree ?",0,"Dialog title"))
+
+ myBox = MsgBox(ctx)
+ myBox.addButton("oK")
+ myBox.renderFromButtonSize()
+ myBox.numberOflines = 2
+
+ print(myBox.show("A small message",0,"Dialog title"))
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/scripting/source/pyprov/pythonscript.py b/scripting/source/pyprov/pythonscript.py
new file mode 100644
index 000000000..4955c8c54
--- /dev/null
+++ b/scripting/source/pyprov/pythonscript.py
@@ -0,0 +1,1145 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-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 .
+#
+# XScript implementation for python
+import uno
+import unohelper
+import sys
+import os
+import types
+import time
+import ast
+import platform
+from com.sun.star.uri.RelativeUriExcessParentSegments import RETAIN
+
+class LogLevel:
+ NONE = 0 # production level
+ ERROR = 1 # for script developers
+ DEBUG = 2 # for script framework developers
+
+PYSCRIPT_LOG_ENV = "PYSCRIPT_LOG_LEVEL"
+PYSCRIPT_LOG_STDOUT_ENV = "PYSCRIPT_LOG_STDOUT"
+
+# Configuration ----------------------------------------------------
+LogLevel.use = LogLevel.NONE
+if os.environ.get(PYSCRIPT_LOG_ENV) == "ERROR":
+ LogLevel.use = LogLevel.ERROR
+elif os.environ.get(PYSCRIPT_LOG_ENV) == "DEBUG":
+ LogLevel.use = LogLevel.DEBUG
+
+# True, writes to stdout (difficult on windows)
+# False, writes to user/Scripts/python/log.txt
+LOG_STDOUT = os.environ.get(PYSCRIPT_LOG_STDOUT_ENV, "1") != "0"
+
+ENABLE_EDIT_DIALOG=False # offers a minimal editor for editing.
+#-------------------------------------------------------------------
+
+def encfile(uni):
+ return uni.encode( sys.getfilesystemencoding())
+
+def lastException2String():
+ (excType,excInstance,excTraceback) = sys.exc_info()
+ ret = str(excType) + ": "+str(excInstance) + "\n" + \
+ uno._uno_extract_printable_stacktrace( excTraceback )
+ return ret
+
+def logLevel2String( level ):
+ ret = " NONE"
+ if level == LogLevel.ERROR:
+ ret = "ERROR"
+ elif level >= LogLevel.DEBUG:
+ ret = "DEBUG"
+ return ret
+
+def getLogTarget():
+ ret = sys.stdout
+ if not LOG_STDOUT:
+ try:
+ pathSubst = uno.getComponentContext().ServiceManager.createInstance(
+ "com.sun.star.util.PathSubstitution" )
+ userInstallation = pathSubst.getSubstituteVariableValue( "user" )
+ if len( userInstallation ) > 0:
+ systemPath = uno.fileUrlToSystemPath( userInstallation + "/Scripts/python/log.txt" )
+ ret = open( systemPath , "a" )
+ except:
+ print("Exception during creation of pythonscript logfile: "+ lastException2String() + "\n, delegating log to stdout\n")
+ return ret
+
+class Logger(LogLevel):
+ def __init__(self , target ):
+ self.target = target
+
+ def isDebugLevel( self ):
+ return self.use >= self.DEBUG
+
+ def debug( self, msg ):
+ if self.isDebugLevel():
+ self.log( self.DEBUG, msg )
+
+ def isErrorLevel( self ):
+ return self.use >= self.ERROR
+
+ def error( self, msg ):
+ if self.isErrorLevel():
+ self.log( self.ERROR, msg )
+
+ def log( self, level, msg ):
+ if self.use >= level:
+ try:
+ self.target.write(
+ time.asctime() +
+ " [" +
+ logLevel2String( level ) +
+ "] " +
+ msg +
+ "\n" )
+ self.target.flush()
+ except:
+ print("Error during writing to stdout: " +lastException2String() + "\n")
+
+log = Logger( getLogTarget() )
+
+log.debug( "pythonscript loading" )
+
+#from com.sun.star.lang import typeOfXServiceInfo, typeOfXTypeProvider
+from com.sun.star.uno import RuntimeException
+from com.sun.star.lang import IllegalArgumentException
+from com.sun.star.container import NoSuchElementException
+from com.sun.star.lang import XServiceInfo
+from com.sun.star.io import IOException
+from com.sun.star.ucb import CommandAbortedException, XCommandEnvironment, XProgressHandler, Command
+from com.sun.star.task import XInteractionHandler
+from com.sun.star.beans import XPropertySet, Property
+from com.sun.star.container import XNameContainer
+from com.sun.star.xml.sax import XDocumentHandler, InputSource
+from com.sun.star.uno import Exception as UnoException
+from com.sun.star.script import XInvocation
+from com.sun.star.awt import XActionListener
+
+from com.sun.star.script.provider import XScriptProvider, XScript, XScriptContext, ScriptFrameworkErrorException
+from com.sun.star.script.browse import XBrowseNode
+from com.sun.star.script.browse.BrowseNodeTypes import SCRIPT, CONTAINER, ROOT
+from com.sun.star.util import XModifyListener
+
+LANGUAGENAME = "Python"
+GLOBAL_SCRIPTCONTEXT_NAME = "XSCRIPTCONTEXT"
+CALLABLE_CONTAINER_NAME = "g_exportedScripts"
+
+# pythonloader looks for a static g_ImplementationHelper variable
+g_ImplementationHelper = unohelper.ImplementationHelper()
+g_implName = "org.libreoffice.pyuno.LanguageScriptProviderFor"+LANGUAGENAME
+
+
+
+BLOCK_SIZE = 65536
+def readTextFromStream( inputStream ):
+ # read the file
+ code = uno.ByteSequence( b"" )
+ while True:
+ read,out = inputStream.readBytes( None , BLOCK_SIZE )
+ code = code + out
+ if read < BLOCK_SIZE:
+ break
+ return code.value
+
+def toIniName( str ):
+ if platform.system() == "Windows":
+ return str + ".ini"
+ else:
+ return str + "rc"
+
+
+""" definition: storageURI is the system dependent, absolute file url, where the script is stored on disk
+ scriptURI is the system independent uri
+"""
+class MyUriHelper:
+
+ def __init__( self, ctx, location ):
+ self.ctx = ctx
+ self.s_UriMap = \
+ { "share" : "vnd.sun.star.expand:$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR/Scripts/python" , \
+ "share:uno_packages" : "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/uno_packages", \
+ "user" : "vnd.sun.star.expand:${$BRAND_INI_DIR/" + toIniName( "bootstrap") + "::UserInstallation}/user/Scripts/python" , \
+ "user:uno_packages" : "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages" }
+ self.m_uriRefFac = ctx.ServiceManager.createInstanceWithContext("com.sun.star.uri.UriReferenceFactory",ctx)
+ if location.startswith( "vnd.sun.star.tdoc" ):
+ self.m_baseUri = location + "/Scripts/python"
+ self.m_scriptUriLocation = "document"
+ else:
+ self.m_baseUri = expandUri( self.s_UriMap[location] )
+ self.m_scriptUriLocation = location
+ log.debug( "initialized urihelper with baseUri="+self.m_baseUri + ",m_scriptUriLocation="+self.m_scriptUriLocation )
+
+ def getRootStorageURI( self ):
+ return self.m_baseUri
+
+ def getStorageURI( self, scriptURI ):
+ return self.scriptURI2StorageUri(scriptURI)
+
+ def getScriptURI( self, storageURI ):
+ return self.storageURI2ScriptUri(storageURI)
+
+ def storageURI2ScriptUri( self, storageURI ):
+ if not storageURI.startswith( self.m_baseUri ):
+ message = "pythonscript: storage uri '" + storageURI + "' not in base uri '" + self.m_baseUri + "'"
+ log.debug( message )
+ raise RuntimeException( message, self.ctx )
+
+ ret = "vnd.sun.star.script:" + \
+ storageURI[len(self.m_baseUri)+1:].replace("/","|") + \
+ "?language=" + LANGUAGENAME + "&location=" + self.m_scriptUriLocation
+ log.debug( "converting storageURI="+storageURI + " to scriptURI=" + ret )
+ return ret
+
+ def scriptURI2StorageUri( self, scriptURI ):
+ try:
+ # base path to the python script location
+ sBaseUri = self.m_baseUri + "/"
+ xBaseUri = self.m_uriRefFac.parse(sBaseUri)
+
+ # path to the .py file + "$functionname, arguments, etc
+ xStorageUri = self.m_uriRefFac.parse(scriptURI)
+ # getName will apply url-decoding to the name, so encode back
+ sStorageUri = xStorageUri.getName().replace("%", "%25")
+ sStorageUri = sStorageUri.replace( "|", "/" )
+
+ # path to the .py file, relative to the base
+ funcNameStart = sStorageUri.find("$")
+ if funcNameStart != -1:
+ sFileUri = sStorageUri[0:funcNameStart]
+ sFuncName = sStorageUri[funcNameStart+1:]
+ else:
+ sFileUri = sStorageUri
+
+ xFileUri = self.m_uriRefFac.parse(sFileUri)
+ if not xFileUri:
+ message = "pythonscript: invalid relative uri '" + sFileUri+ "'"
+ log.debug( message )
+ raise RuntimeException( message, self.ctx )
+
+ if not xFileUri.hasRelativePath():
+ message = "pythonscript: an absolute uri is invalid '" + sFileUri+ "'"
+ log.debug( message )
+ raise RuntimeException( message, self.ctx )
+
+ # absolute path to the .py file
+ xAbsScriptUri = self.m_uriRefFac.makeAbsolute(xBaseUri, xFileUri, True, RETAIN)
+ sAbsScriptUri = xAbsScriptUri.getUriReference()
+
+ # ensure py file is under the base path
+ if not sAbsScriptUri.startswith(sBaseUri):
+ message = "pythonscript: storage uri '" + sAbsScriptUri + "' not in base uri '" + self.m_baseUri + "'"
+ log.debug( message )
+ raise RuntimeException( message, self.ctx )
+
+ ret = sAbsScriptUri
+ if funcNameStart != -1:
+ ret = ret + "$" + sFuncName
+ log.debug( "converting scriptURI="+scriptURI + " to storageURI=" + ret )
+ return ret
+ except UnoException as e:
+ log.error( "error during converting scriptURI="+scriptURI + ": " + e.Message)
+ raise RuntimeException( "pythonscript:scriptURI2StorageUri: " + e.Message, self.ctx )
+ except Exception as e:
+ log.error( "error during converting scriptURI="+scriptURI + ": " + str(e))
+ raise RuntimeException( "pythonscript:scriptURI2StorageUri: " + str(e), self.ctx )
+
+
+class ModuleEntry:
+ def __init__( self, lastRead, module ):
+ self.lastRead = lastRead
+ self.module = module
+
+def hasChanged( oldDate, newDate ):
+ return newDate.Year > oldDate.Year or \
+ newDate.Month > oldDate.Month or \
+ newDate.Day > oldDate.Day or \
+ newDate.Hours > oldDate.Hours or \
+ newDate.Minutes > oldDate.Minutes or \
+ newDate.Seconds > oldDate.Seconds or \
+ newDate.NanoSeconds > oldDate.NanoSeconds
+
+def ensureSourceState( code ):
+ if code.endswith(b"\n"):
+ code = code + b"\n"
+ code = code.replace(b"\r", b"")
+ return code
+
+
+def checkForPythonPathBesideScript( url ):
+ if url.startswith( "file:" ):
+ path = unohelper.fileUrlToSystemPath( url+"/pythonpath.zip" );
+ log.log( LogLevel.DEBUG, "checking for existence of " + path )
+ if 1 == os.access( encfile(path), os.F_OK) and not path in sys.path:
+ log.log( LogLevel.DEBUG, "adding " + path + " to sys.path" )
+ sys.path.append( path )
+
+ path = unohelper.fileUrlToSystemPath( url+"/pythonpath" );
+ log.log( LogLevel.DEBUG, "checking for existence of " + path )
+ if 1 == os.access( encfile(path), os.F_OK) and not path in sys.path:
+ log.log( LogLevel.DEBUG, "adding " + path + " to sys.path" )
+ sys.path.append( path )
+
+
+class ScriptContext(unohelper.Base):
+ def __init__( self, ctx, doc, inv ):
+ self.ctx = ctx
+ self.doc = doc
+ self.inv = inv
+
+ # XScriptContext
+ def getDocument(self):
+ if self.doc:
+ return self.doc
+ return self.getDesktop().getCurrentComponent()
+
+ def getDesktop(self):
+ return self.ctx.ServiceManager.createInstanceWithContext(
+ "com.sun.star.frame.Desktop", self.ctx )
+
+ def getComponentContext(self):
+ return self.ctx
+
+ def getInvocationContext(self):
+ return self.inv
+
+#----------------------------------
+# Global Module Administration
+# does not fit together with script
+# engine lifetime management
+#----------------------------------
+#g_scriptContext = ScriptContext( uno.getComponentContext(), None )
+#g_modules = {}
+#def getModuleByUrl( url, sfa ):
+# entry = g_modules.get(url)
+# load = True
+# lastRead = sfa.getDateTimeModified( url )
+# if entry:
+# if hasChanged( entry.lastRead, lastRead ):
+# log.debug("file " + url + " has changed, reloading")
+# else:
+# load = False
+#
+# if load:
+# log.debug( "opening >" + url + "<" )
+#
+# code = readTextFromStream( sfa.openFileRead( url ) )
+
+ # execute the module
+# entry = ModuleEntry( lastRead, types.ModuleType("ooo_script_framework") )
+# entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = g_scriptContext
+# entry.module.__file__ = url
+# exec code in entry.module.__dict__
+# g_modules[ url ] = entry
+# log.debug( "mapped " + url + " to " + str( entry.module ) )
+# return entry.module
+
+class ProviderContext:
+ def __init__( self, storageType, sfa, uriHelper, scriptContext ):
+ self.storageType = storageType
+ self.sfa = sfa
+ self.uriHelper = uriHelper
+ self.scriptContext = scriptContext
+ self.modules = {}
+ self.rootUrl = None
+ self.mapPackageName2Path = None
+
+ def getTransientPartFromUrl( self, url ):
+ rest = url.replace( self.rootUrl , "",1 ).replace( "/","",1)
+ return rest[0:rest.find("/")]
+
+ def getPackageNameFromUrl( self, url ):
+ rest = url.replace( self.rootUrl , "",1 ).replace( "/","",1)
+ start = rest.find("/") +1
+ return rest[start:rest.find("/",start)]
+
+
+ def removePackageByUrl( self, url ):
+ items = self.mapPackageName2Path.items()
+ for i in items:
+ if url in i[1].paths:
+ self.mapPackageName2Path.pop(i[0])
+ break
+
+ def addPackageByUrl( self, url ):
+ packageName = self.getPackageNameFromUrl( url )
+ transientPart = self.getTransientPartFromUrl( url )
+ log.debug( "addPackageByUrl : " + packageName + ", " + transientPart + "("+url+")" + ", rootUrl="+self.rootUrl )
+ if packageName in self.mapPackageName2Path:
+ package = self.mapPackageName2Path[ packageName ]
+ package.paths = package.paths + (url, )
+ else:
+ package = Package( (url,), transientPart)
+ self.mapPackageName2Path[ packageName ] = package
+
+ def isUrlInPackage( self, url ):
+ values = self.mapPackageName2Path.values()
+ for i in values:
+# print ("checking " + url + " in " + str(i.paths))
+ if url in i.paths:
+ return True
+# print ("false")
+ return False
+
+ def setPackageAttributes( self, mapPackageName2Path, rootUrl ):
+ self.mapPackageName2Path = mapPackageName2Path
+ self.rootUrl = rootUrl
+
+ def getPersistentUrlFromStorageUrl( self, url ):
+ # package name is the second directory
+ ret = url
+ if self.rootUrl:
+ pos = len( self.rootUrl) +1
+ ret = url[0:pos]+url[url.find("/",pos)+1:len(url)]
+ log.debug( "getPersistentUrlFromStorageUrl " + url + " -> "+ ret)
+ return ret
+
+ def getStorageUrlFromPersistentUrl( self, url):
+ ret = url
+ if self.rootUrl:
+ pos = len(self.rootUrl)+1
+ packageName = url[pos:url.find("/",pos+1)]
+ package = self.mapPackageName2Path[ packageName ]
+ ret = url[0:pos]+ package.transientPathElement + "/" + url[pos:len(url)]
+ log.debug( "getStorageUrlFromPersistentUrl " + url + " -> "+ ret)
+ return ret
+
+ def getFuncsByUrl( self, url ):
+ src = readTextFromStream( self.sfa.openFileRead( url ) )
+ checkForPythonPathBesideScript( url[0:url.rfind('/')] )
+ src = ensureSourceState( src )
+
+ try:
+ code = ast.parse( src )
+ except:
+ log.isDebugLevel() and log.debug( "pythonscript: getFuncsByUrl: exception while parsing: " + lastException2String())
+ raise
+
+ allFuncs = []
+
+ if code is None:
+ return allFuncs
+
+ g_exportedScripts = []
+ for node in ast.iter_child_nodes(code):
+ if isinstance(node, ast.FunctionDef):
+ allFuncs.append(node.name)
+ elif isinstance(node, ast.Assign):
+ for target in node.targets:
+ try:
+ identifier = target.id
+ except AttributeError:
+ identifier = ""
+ pass
+ if identifier == "g_exportedScripts":
+ for value in node.value.elts:
+ g_exportedScripts.append(value.id)
+ return g_exportedScripts
+
+# Python 2 only
+# for node in code.node.nodes:
+# if node.__class__.__name__ == 'Function':
+# allFuncs.append(node.name)
+# elif node.__class__.__name__ == 'Assign':
+# for assignee in node.nodes:
+# if assignee.name == 'g_exportedScripts':
+# for item in node.expr.nodes:
+# if item.__class__.__name__ == 'Name':
+# g_exportedScripts.append(item.name)
+# return g_exportedScripts
+
+ return allFuncs
+
+ def getModuleByUrl( self, url ):
+ entry = self.modules.get(url)
+ load = True
+ lastRead = self.sfa.getDateTimeModified( url )
+ if entry:
+ if hasChanged( entry.lastRead, lastRead ):
+ log.debug( "file " + url + " has changed, reloading" )
+ else:
+ load = False
+
+ if load:
+ log.debug( "opening >" + url + "<" )
+
+ src = readTextFromStream( self.sfa.openFileRead( url ) )
+ checkForPythonPathBesideScript( url[0:url.rfind('/')] )
+ src = ensureSourceState( src )
+
+ # execute the module
+ entry = ModuleEntry( lastRead, types.ModuleType("ooo_script_framework") )
+ entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = self.scriptContext
+
+ code = None
+ if url.startswith( "file:" ):
+ code = compile( src, encfile(uno.fileUrlToSystemPath( url ) ), "exec" )
+ else:
+ code = compile( src, url, "exec" )
+ exec(code, entry.module.__dict__)
+ entry.module.__file__ = url
+ self.modules[ url ] = entry
+ log.debug( "mapped " + url + " to " + str( entry.module ) )
+ return entry.module
+
+#--------------------------------------------------
+def isScript( candidate ):
+ ret = False
+ if isinstance( candidate, type(isScript) ):
+ ret = True
+ return ret
+
+#-------------------------------------------------------
+class ScriptBrowseNode( unohelper.Base, XBrowseNode , XPropertySet, XInvocation, XActionListener ):
+ def __init__( self, provCtx, uri, fileName, funcName ):
+ self.fileName = fileName
+ self.funcName = funcName
+ self.provCtx = provCtx
+ self.uri = uri
+
+ def getName( self ):
+ return self.funcName
+
+ def getChildNodes(self):
+ return ()
+
+ def hasChildNodes(self):
+ return False
+
+ def getType( self):
+ return SCRIPT
+
+ def getPropertyValue( self, name ):
+ ret = None
+ try:
+ if name == "URI":
+ ret = self.provCtx.uriHelper.getScriptURI(
+ self.provCtx.getPersistentUrlFromStorageUrl( self.uri + "$" + self.funcName ) )
+ elif name == "Editable" and ENABLE_EDIT_DIALOG:
+ ret = not self.provCtx.sfa.isReadOnly( self.uri )
+
+ log.debug( "ScriptBrowseNode.getPropertyValue called for " + name + ", returning " + str(ret) )
+ except:
+ log.error( "ScriptBrowseNode.getPropertyValue error " + lastException2String())
+ raise
+
+ return ret
+ def setPropertyValue( self, name, value ):
+ log.debug( "ScriptBrowseNode.setPropertyValue called " + name + "=" +str(value ) )
+ def getPropertySetInfo( self ):
+ log.debug( "ScriptBrowseNode.getPropertySetInfo called " )
+ return None
+
+ def getIntrospection( self ):
+ return None
+
+ def invoke( self, name, params, outparamindex, outparams ):
+ if name == "Editable":
+ servicename = "com.sun.star.awt.DialogProvider"
+ ctx = self.provCtx.scriptContext.getComponentContext()
+ dlgprov = ctx.ServiceManager.createInstanceWithContext(
+ servicename, ctx )
+
+ self.editor = dlgprov.createDialog(
+ "vnd.sun.star.script:" +
+ "ScriptBindingLibrary.MacroEditor?location=application")
+
+ code = readTextFromStream(self.provCtx.sfa.openFileRead(self.uri))
+ code = ensureSourceState( code )
+ self.editor.getControl("EditorTextField").setText(code)
+
+ self.editor.getControl("RunButton").setActionCommand("Run")
+ self.editor.getControl("RunButton").addActionListener(self)
+ self.editor.getControl("SaveButton").setActionCommand("Save")
+ self.editor.getControl("SaveButton").addActionListener(self)
+
+ self.editor.execute()
+
+ return None
+
+ def actionPerformed( self, event ):
+ try:
+ if event.ActionCommand == "Run":
+ code = self.editor.getControl("EditorTextField").getText()
+ code = ensureSourceState( code )
+ mod = types.ModuleType("ooo_script_framework")
+ mod.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = self.provCtx.scriptContext
+ exec(code, mod.__dict__)
+ values = mod.__dict__.get( CALLABLE_CONTAINER_NAME , None )
+ if not values:
+ values = mod.__dict__.values()
+
+ for i in values:
+ if isScript( i ):
+ i()
+ break
+
+ elif event.ActionCommand == "Save":
+ toWrite = uno.ByteSequence(
+ self.editor.getControl("EditorTextField").getText().encode(
+ sys.getdefaultencoding()) )
+ copyUrl = self.uri + ".orig"
+ self.provCtx.sfa.move( self.uri, copyUrl )
+ out = self.provCtx.sfa.openFileWrite( self.uri )
+ out.writeBytes( toWrite )
+ out.close()
+ self.provCtx.sfa.kill( copyUrl )
+# log.debug("Save is not implemented yet")
+# text = self.editor.getControl("EditorTextField").getText()
+# log.debug("Would save: " + text)
+ except:
+ # TODO: add an error box here!
+ log.error( lastException2String() )
+
+
+ def setValue( self, name, value ):
+ return None
+
+ def getValue( self, name ):
+ return None
+
+ def hasMethod( self, name ):
+ return False
+
+ def hasProperty( self, name ):
+ return False
+
+
+#-------------------------------------------------------
+class FileBrowseNode( unohelper.Base, XBrowseNode ):
+ def __init__( self, provCtx, uri , name ):
+ self.provCtx = provCtx
+ self.uri = uri
+ self.name = name
+ self.funcnames = None
+
+ def getName( self ):
+ return self.name
+
+ def getChildNodes(self):
+ ret = ()
+ try:
+ self.funcnames = self.provCtx.getFuncsByUrl( self.uri )
+
+ scriptNodeList = []
+ for i in self.funcnames:
+ scriptNodeList.append(
+ ScriptBrowseNode(
+ self.provCtx, self.uri, self.name, i ))
+ ret = tuple( scriptNodeList )
+ log.debug( "returning " +str(len(ret)) + " ScriptChildNodes on " + self.uri )
+ except:
+ text = lastException2String()
+ log.error( "Error while evaluating " + self.uri + ":" + text )
+ raise
+ return ret
+
+ def hasChildNodes(self):
+ try:
+ return len(self.getChildNodes()) > 0
+ except:
+ return False
+
+ def getType( self):
+ return CONTAINER
+
+
+
+class DirBrowseNode( unohelper.Base, XBrowseNode ):
+ def __init__( self, provCtx, name, rootUrl ):
+ self.provCtx = provCtx
+ self.name = name
+ self.rootUrl = rootUrl
+
+ def getName( self ):
+ return self.name
+
+ def getChildNodes( self ):
+ try:
+ log.debug( "DirBrowseNode.getChildNodes called for " + self.rootUrl )
+ contents = self.provCtx.sfa.getFolderContents( self.rootUrl, True )
+ browseNodeList = []
+ for i in contents:
+ if i.endswith( ".py" ):
+ log.debug( "adding filenode " + i )
+ browseNodeList.append(
+ FileBrowseNode( self.provCtx, i, i[i.rfind("/")+1:len(i)-3] ) )
+ elif self.provCtx.sfa.isFolder( i ) and not i.endswith("/pythonpath"):
+ log.debug( "adding DirBrowseNode " + i )
+ browseNodeList.append( DirBrowseNode( self.provCtx, i[i.rfind("/")+1:len(i)],i))
+ return tuple( browseNodeList )
+ except Exception as e:
+ text = lastException2String()
+ log.error( "DirBrowseNode error: " + str(e) + " while evaluating " + self.rootUrl)
+ log.error( text)
+ return ()
+
+ def hasChildNodes( self ):
+ return True
+
+ def getType( self ):
+ return CONTAINER
+
+ def getScript( self, uri ):
+ log.debug( "DirBrowseNode getScript " + uri + " invoked" )
+ raise IllegalArgumentException( "DirBrowseNode couldn't instantiate script " + uri , self , 0 )
+
+
+class ManifestHandler( XDocumentHandler, unohelper.Base ):
+ def __init__( self, rootUrl ):
+ self.rootUrl = rootUrl
+
+ def startDocument( self ):
+ self.urlList = []
+
+ def endDocument( self ):
+ pass
+
+ def startElement( self , name, attlist):
+ if name == "manifest:file-entry":
+ if attlist.getValueByName( "manifest:media-type" ) == "application/vnd.sun.star.framework-script":
+ self.urlList.append(
+ self.rootUrl + "/" + attlist.getValueByName( "manifest:full-path" ) )
+
+ def endElement( self, name ):
+ pass
+
+ def characters ( self, chars ):
+ pass
+
+ def ignoreableWhitespace( self, chars ):
+ pass
+
+ def setDocumentLocator( self, locator ):
+ pass
+
+def isPyFileInPath( sfa, path ):
+ ret = False
+ contents = sfa.getFolderContents( path, True )
+ for i in contents:
+ if sfa.isFolder(i):
+ ret = isPyFileInPath(sfa,i)
+ else:
+ if i.endswith(".py"):
+ ret = True
+ if ret:
+ break
+ return ret
+
+# extracts META-INF directory from
+def getPathsFromPackage( rootUrl, sfa ):
+ ret = ()
+ try:
+ fileUrl = rootUrl + "/META-INF/manifest.xml"
+ inputStream = sfa.openFileRead( fileUrl )
+ parser = uno.getComponentContext().ServiceManager.createInstance( "com.sun.star.xml.sax.Parser" )
+ handler = ManifestHandler( rootUrl )
+ parser.setDocumentHandler( handler )
+ parser.parseStream( InputSource( inputStream , "", fileUrl, fileUrl ) )
+ for i in tuple(handler.urlList):
+ if not isPyFileInPath( sfa, i ):
+ handler.urlList.remove(i)
+ ret = tuple( handler.urlList )
+ except UnoException:
+ text = lastException2String()
+ log.debug( "getPathsFromPackage " + fileUrl + " Exception: " +text )
+ pass
+ return ret
+
+
+class Package:
+ def __init__( self, paths, transientPathElement ):
+ self.paths = paths
+ self.transientPathElement = transientPathElement
+
+class DummyInteractionHandler( unohelper.Base, XInteractionHandler ):
+ def __init__( self ):
+ pass
+ def handle( self, event):
+ log.debug( "pythonscript: DummyInteractionHandler.handle " + str( event ) )
+
+class DummyProgressHandler( unohelper.Base, XProgressHandler ):
+ def __init__( self ):
+ pass
+
+ def push( self,status ):
+ log.debug( "pythonscript: DummyProgressHandler.push " + str( status ) )
+ def update( self,status ):
+ log.debug( "pythonscript: DummyProgressHandler.update " + str( status ) )
+ def pop( self, event ):
+ log.debug( "pythonscript: DummyProgressHandler.push " + str( event ) )
+
+class CommandEnvironment(unohelper.Base, XCommandEnvironment):
+ def __init__( self ):
+ self.progressHandler = DummyProgressHandler()
+ self.interactionHandler = DummyInteractionHandler()
+ def getInteractionHandler( self ):
+ return self.interactionHandler
+ def getProgressHandler( self ):
+ return self.progressHandler
+
+#maybe useful for debugging purposes
+#class ModifyListener( unohelper.Base, XModifyListener ):
+# def __init__( self ):
+# pass
+# def modified( self, event ):
+# log.debug( "pythonscript: ModifyListener.modified " + str( event ) )
+# def disposing( self, event ):
+# log.debug( "pythonscript: ModifyListener.disposing " + str( event ) )
+
+def getModelFromDocUrl(ctx, url):
+ """Get document model from document url."""
+ doc = None
+ args = ("Local", "Office")
+ ucb = ctx.getServiceManager().createInstanceWithArgumentsAndContext(
+ "com.sun.star.ucb.UniversalContentBroker", args, ctx)
+ identifier = ucb.createContentIdentifier(url)
+ content = ucb.queryContent(identifier)
+ p = Property()
+ p.Name = "DocumentModel"
+ p.Handle = -1
+
+ c = Command()
+ c.Handle = -1
+ c.Name = "getPropertyValues"
+ c.Argument = uno.Any("[]com.sun.star.beans.Property", (p,))
+
+ env = CommandEnvironment()
+ try:
+ ret = content.execute(c, 0, env)
+ doc = ret.getObject(1, None)
+ except Exception as e:
+ log.isErrorLevel() and log.error("getModelFromDocUrl: %s" % url)
+ return doc
+
+def mapStorageType2PackageContext( storageType ):
+ ret = storageType
+ if( storageType == "share:uno_packages" ):
+ ret = "shared"
+ if( storageType == "user:uno_packages" ):
+ ret = "user"
+ return ret
+
+def getPackageName2PathMap( sfa, storageType ):
+ ret = {}
+ packageManagerFactory = uno.getComponentContext().getValueByName(
+ "/singletons/com.sun.star.deployment.thePackageManagerFactory" )
+ packageManager = packageManagerFactory.getPackageManager(
+ mapStorageType2PackageContext(storageType))
+# packageManager.addModifyListener( ModifyListener() )
+ log.debug( "pythonscript: getPackageName2PathMap start getDeployedPackages" )
+ packages = packageManager.getDeployedPackages(
+ packageManager.createAbortChannel(), CommandEnvironment( ) )
+ log.debug( "pythonscript: getPackageName2PathMap end getDeployedPackages (" + str(len(packages))+")" )
+
+ for i in packages:
+ log.debug( "inspecting package " + i.Name + "("+i.Identifier.Value+")" )
+ transientPathElement = penultimateElement( i.URL )
+ j = expandUri( i.URL )
+ paths = getPathsFromPackage( j, sfa )
+ if len( paths ) > 0:
+ # map package name to url, we need this later
+ log.isErrorLevel() and log.error( "adding Package " + transientPathElement + " " + str( paths ) )
+ ret[ lastElement( j ) ] = Package( paths, transientPathElement )
+ return ret
+
+def penultimateElement( aStr ):
+ lastSlash = aStr.rindex("/")
+ penultimateSlash = aStr.rindex("/",0,lastSlash-1)
+ return aStr[ penultimateSlash+1:lastSlash ]
+
+def lastElement( aStr):
+ return aStr[ aStr.rfind( "/" )+1:len(aStr)]
+
+class PackageBrowseNode( unohelper.Base, XBrowseNode ):
+ def __init__( self, provCtx, name, rootUrl ):
+ self.provCtx = provCtx
+ self.name = name
+ self.rootUrl = rootUrl
+
+ def getName( self ):
+ return self.name
+
+ def getChildNodes( self ):
+ items = self.provCtx.mapPackageName2Path.items()
+ browseNodeList = []
+ for i in items:
+ if len( i[1].paths ) == 1:
+ browseNodeList.append(
+ DirBrowseNode( self.provCtx, i[0], i[1].paths[0] ))
+ else:
+ for j in i[1].paths:
+ browseNodeList.append(
+ DirBrowseNode( self.provCtx, i[0]+"."+lastElement(j), j ) )
+ return tuple( browseNodeList )
+
+ def hasChildNodes( self ):
+ return len( self.provCtx.mapPackageName2Path ) > 0
+
+ def getType( self ):
+ return CONTAINER
+
+ def getScript( self, uri ):
+ log.debug( "PackageBrowseNode getScript " + uri + " invoked" )
+ raise IllegalArgumentException( "PackageBrowseNode couldn't instantiate script " + uri , self , 0 )
+
+
+
+
+class PythonScript( unohelper.Base, XScript ):
+ def __init__( self, func, mod, args ):
+ self.func = func
+ self.mod = mod
+ self.args = args
+
+ def invoke(self, args, out, outindex ):
+ log.debug( "PythonScript.invoke " + str( args ) )
+ try:
+ if (self.args):
+ args += self.args
+ ret = self.func( *args )
+ except UnoException as e:
+ # UNO Exception continue to fly ...
+ text = lastException2String()
+ complete = "Error during invoking function " + \
+ str(self.func.__name__) + " in module " + \
+ self.mod.__file__ + " (" + text + ")"
+ log.debug( complete )
+ # some people may beat me up for modifying the exception text,
+ # but otherwise office just shows
+ # the type name and message text with no more information,
+ # this is really bad for most users.
+ e.Message = e.Message + " (" + complete + ")"
+ raise
+ except Exception as e:
+ # General python exception are converted to uno RuntimeException
+ text = lastException2String()
+ complete = "Error during invoking function " + \
+ str(self.func.__name__) + " in module " + \
+ self.mod.__file__ + " (" + text + ")"
+ log.debug( complete )
+ raise RuntimeException( complete , self )
+ log.debug( "PythonScript.invoke ret = " + str( ret ) )
+ return ret, (), ()
+
+def expandUri( uri ):
+ if uri.startswith( "vnd.sun.star.expand:" ):
+ uri = uri.replace( "vnd.sun.star.expand:", "",1)
+ uri = uno.getComponentContext().getByName(
+ "/singletons/com.sun.star.util.theMacroExpander" ).expandMacros( uri )
+ if uri.startswith( "file:" ):
+ uri = uno.absolutize("",uri) # necessary to get rid of .. in uri
+ return uri
+
+#--------------------------------------------------------------
+class PythonScriptProvider( unohelper.Base, XBrowseNode, XScriptProvider, XNameContainer):
+ def __init__( self, ctx, *args ):
+ if log.isDebugLevel():
+ mystr = ""
+ for i in args:
+ if len(mystr) > 0:
+ mystr = mystr +","
+ mystr = mystr + str(i)
+ log.debug( "Entering PythonScriptProvider.ctor" + mystr )
+
+ doc = None
+ inv = None
+ storageType = ""
+
+ if isinstance(args[0], str):
+ storageType = args[0]
+ if storageType.startswith( "vnd.sun.star.tdoc" ):
+ doc = getModelFromDocUrl(ctx, storageType)
+ else:
+ inv = args[0]
+ try:
+ doc = inv.ScriptContainer
+ content = ctx.getServiceManager().createInstanceWithContext(
+ "com.sun.star.frame.TransientDocumentsDocumentContentFactory",
+ ctx).createDocumentContent(doc)
+ storageType = content.getIdentifier().getContentIdentifier()
+ except Exception as e:
+ text = lastException2String()
+ log.error( text )
+
+ isPackage = storageType.endswith( ":uno_packages" )
+
+ try:
+# urlHelper = ctx.ServiceManager.createInstanceWithArgumentsAndContext(
+# "com.sun.star.script.provider.ScriptURIHelper", (LANGUAGENAME, storageType), ctx)
+ urlHelper = MyUriHelper( ctx, storageType )
+ log.debug( "got urlHelper " + str( urlHelper ) )
+
+ rootUrl = expandUri( urlHelper.getRootStorageURI() )
+ log.debug( storageType + " transformed to " + rootUrl )
+
+ ucbService = "com.sun.star.ucb.SimpleFileAccess"
+ sfa = ctx.ServiceManager.createInstanceWithContext( ucbService, ctx )
+ if not sfa:
+ log.debug("PythonScriptProvider couldn't instantiate " +ucbService)
+ raise RuntimeException(
+ "PythonScriptProvider couldn't instantiate " +ucbService, self)
+ self.provCtx = ProviderContext(
+ storageType, sfa, urlHelper, ScriptContext( uno.getComponentContext(), doc, inv ) )
+ if isPackage:
+ mapPackageName2Path = getPackageName2PathMap( sfa, storageType )
+ self.provCtx.setPackageAttributes( mapPackageName2Path , rootUrl )
+ self.dirBrowseNode = PackageBrowseNode( self.provCtx, LANGUAGENAME, rootUrl )
+ else:
+ self.dirBrowseNode = DirBrowseNode( self.provCtx, LANGUAGENAME, rootUrl )
+
+ except Exception as e:
+ text = lastException2String()
+ log.debug( "PythonScriptProvider could not be instantiated because of : " + text )
+ raise e
+
+ def getName( self ):
+ return self.dirBrowseNode.getName()
+
+ def getChildNodes( self ):
+ return self.dirBrowseNode.getChildNodes()
+
+ def hasChildNodes( self ):
+ return self.dirBrowseNode.hasChildNodes()
+
+ def getType( self ):
+ return self.dirBrowseNode.getType()
+
+ # retrieve function args in parenthesis
+ def getFunctionArguments(self, func_signature):
+ nOpenParenthesis = func_signature.find( "(" )
+ if -1 == nOpenParenthesis:
+ function_name = func_signature
+ arguments = None
+ else:
+ function_name = func_signature[0:nOpenParenthesis]
+ arg_part = func_signature[nOpenParenthesis+1:len(func_signature)]
+ nCloseParenthesis = arg_part.find( ")" )
+ if -1 == nCloseParenthesis:
+ raise IllegalArgumentException( "PythonLoader: mismatch parenthesis " + func_signature, self, 0 )
+ arguments = arg_part[0:nCloseParenthesis].strip()
+ if arguments == "":
+ arguments = None
+ else:
+ arguments = tuple([x.strip().strip('"') for x in arguments.split(",")])
+ return function_name, arguments
+
+ def getScript( self, scriptUri ):
+ try:
+ log.debug( "getScript " + scriptUri + " invoked")
+
+ storageUri = self.provCtx.getStorageUrlFromPersistentUrl(
+ self.provCtx.uriHelper.getStorageURI(scriptUri) );
+ log.debug( "getScript: storageUri = " + storageUri)
+ fileUri = storageUri[0:storageUri.find( "$" )]
+ funcName = storageUri[storageUri.find( "$" )+1:len(storageUri)]
+
+ # retrieve arguments in parenthesis
+ funcName, funcArgs = self.getFunctionArguments(funcName)
+ log.debug( " getScript : parsed funcname " + str(funcName) )
+ log.debug( " getScript : func args " + str(funcArgs) )
+
+ mod = self.provCtx.getModuleByUrl( fileUri )
+ log.debug( " got mod " + str(mod) )
+
+ func = mod.__dict__[ funcName ]
+
+ log.debug( "got func " + str( func ) )
+ return PythonScript( func, mod, funcArgs )
+ except:
+ text = lastException2String()
+ log.error( text )
+ raise ScriptFrameworkErrorException( text, self, scriptUri, LANGUAGENAME, 0 )
+
+
+ # XServiceInfo
+ def getSupportedServices( self ):
+ return g_ImplementationHelper.getSupportedServices(g_implName)
+
+ def supportsService( self, ServiceName ):
+ return g_ImplementationHelper.supportsService( g_implName, ServiceName )
+
+ def getImplementationName(self):
+ return g_implName
+
+ def getByName( self, name ):
+ log.debug( "getByName called" + str( name ))
+ return None
+
+
+ def getElementNames( self ):
+ log.debug( "getElementNames called")
+ return ()
+
+ def hasByName( self, name ):
+ try:
+ log.debug( "hasByName called " + str( name ))
+ uri = expandUri(name)
+ ret = self.provCtx.isUrlInPackage( uri )
+ log.debug( "hasByName " + uri + " " +str( ret ) )
+ return ret
+ except:
+ text = lastException2String()
+ log.debug( "Error in hasByName:" + text )
+ return False
+
+ def removeByName( self, name ):
+ log.debug( "removeByName called" + str( name ))
+ uri = expandUri( name )
+ if self.provCtx.isUrlInPackage( uri ):
+ self.provCtx.removePackageByUrl( uri )
+ else:
+ log.debug( "removeByName unknown uri " + str( name ) + ", ignoring" )
+ raise NoSuchElementException( uri + "is not in package" , self )
+ log.debug( "removeByName called" + str( uri ) + " successful" )
+
+ def insertByName( self, name, value ):
+ log.debug( "insertByName called " + str( name ) + " " + str( value ))
+ uri = expandUri( name )
+ if isPyFileInPath( self.provCtx.sfa, uri ):
+ self.provCtx.addPackageByUrl( uri )
+ else:
+ # package is no python package ...
+ log.debug( "insertByName: no python files in " + str( uri ) + ", ignoring" )
+ raise IllegalArgumentException( uri + " does not contain .py files", self, 1 )
+ log.debug( "insertByName called " + str( uri ) + " successful" )
+
+ def replaceByName( self, name, value ):
+ log.debug( "replaceByName called " + str( name ) + " " + str( value ))
+ uri = expandUri( name )
+ self.removeByName( name )
+ self.insertByName( name, value )
+ log.debug( "replaceByName called" + str( uri ) + " successful" )
+
+ def getElementType( self ):
+ log.debug( "getElementType called" )
+ return uno.getTypeByName( "void" )
+
+ def hasElements( self ):
+ log.debug( "hasElements got called")
+ return False
+
+g_ImplementationHelper.addImplementation( \
+ PythonScriptProvider,g_implName, \
+ ("com.sun.star.script.provider.LanguageScriptProvider",
+ "com.sun.star.script.provider.ScriptProviderFor"+ LANGUAGENAME,),)
+
+
+log.debug( "pythonscript finished initializing" )
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/scripting/source/pyprov/scriptproviderforpython.rdb b/scripting/source/pyprov/scriptproviderforpython.rdb
new file mode 100644
index 000000000..09a37e4da
--- /dev/null
+++ b/scripting/source/pyprov/scriptproviderforpython.rdb
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!--
+ * 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 .
+-->
+<components xmlns="http://openoffice.org/2010/uno-components">
+ <component loader="com.sun.star.loader.Python"
+ uri="vnd.openoffice.pymodule:pythonscript">
+ <implementation
+ name="org.libreoffice.pyuno.LanguageScriptProviderForPython">
+ <service name="com.sun.star.script.provider.ScriptProviderForPython"/>
+ <service name="com.sun.star.script.provider.LanguageScriptProvider"/>
+ </implementation>
+ </component>
+</components>
diff --git a/scripting/source/stringresource/stringresource.component b/scripting/source/stringresource/stringresource.component
new file mode 100644
index 000000000..a2b2a24f3
--- /dev/null
+++ b/scripting/source/stringresource/stringresource.component
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.scripting.StringResource"
+ constructor="scripting_StringResourcePersistenceImpl_implementation">
+ <service name="com.sun.star.resource.StringResource"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.scripting.StringResourceWithLocation"
+ constructor="scripting_StringResourceWithLocationImpl_get_implementation">
+ <service name="com.sun.star.resource.StringResourceWithLocation"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.scripting.StringResourceWithStorage"
+ constructor="scripting_StringResourceWithStorageImpl_get_implementation">
+ <service name="com.sun.star.resource.StringResourceWithStorage"/>
+ </implementation>
+</component>
diff --git a/scripting/source/stringresource/stringresource.cxx b/scripting/source/stringresource/stringresource.cxx
new file mode 100644
index 000000000..06b52b037
--- /dev/null
+++ b/scripting/source/stringresource/stringresource.cxx
@@ -0,0 +1,2598 @@
+/* -*- 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 "stringresource.hxx"
+#include <com/sun/star/io/TempFile.hpp>
+#include <com/sun/star/io/TextInputStream.hpp>
+#include <com/sun/star/io/TextOutputStream.hpp>
+#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/resource/MissingResourceException.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+
+#include <osl/diagnose.h>
+#include <rtl/tencinfo.h>
+#include <rtl/ustrbuf.hxx>
+#include <tools/urlobj.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::container;
+
+
+namespace stringresource
+{
+
+// StringResourceImpl
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scripting_StringResourcePersistenceImpl_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new StringResourcePersistenceImpl(context));
+}
+
+
+StringResourceImpl::StringResourceImpl( const Reference< XComponentContext >& rxContext )
+ : m_xContext( rxContext )
+ , m_pCurrentLocaleItem( nullptr )
+ , m_pDefaultLocaleItem( nullptr )
+ , m_bDefaultModified( false )
+ , m_bModified( false )
+ , m_bReadOnly( false )
+ , m_nNextUniqueNumericId( UNIQUE_NUMBER_NEEDS_INITIALISATION )
+{
+}
+
+
+StringResourceImpl::~StringResourceImpl()
+{
+}
+
+
+// XServiceInfo
+
+OUString StringResourceImpl::getImplementationName( )
+{
+ return "com.sun.star.comp.scripting.StringResource";
+}
+
+sal_Bool StringResourceImpl::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence< OUString > StringResourceImpl::getSupportedServiceNames( )
+{
+ return { "com.sun.star.resource.StringResource" };
+}
+
+
+// XModifyBroadcaster
+
+void StringResourceImpl::addModifyListener( const Reference< XModifyListener >& aListener )
+{
+ if( !aListener.is() )
+ throw RuntimeException();
+
+ std::unique_lock aGuard( m_aMutex );
+ m_aListenerContainer.addInterface( aGuard, aListener );
+}
+
+void StringResourceImpl::removeModifyListener( const Reference< XModifyListener >& aListener )
+{
+ if( !aListener.is() )
+ throw RuntimeException();
+
+ std::unique_lock aGuard( m_aMutex );
+ m_aListenerContainer.removeInterface( aGuard, aListener );
+}
+
+
+// XStringResourceResolver
+
+OUString StringResourceImpl::implResolveString
+ ( const OUString& ResourceID, LocaleItem* pLocaleItem )
+{
+ OUString aRetStr;
+ bool bSuccess = false;
+ if( pLocaleItem != nullptr && loadLocale( pLocaleItem ) )
+ {
+ IdToStringMap::iterator it = pLocaleItem->m_aIdToStringMap.find( ResourceID );
+ if( it != pLocaleItem->m_aIdToStringMap.end() )
+ {
+ aRetStr = (*it).second;
+ bSuccess = true;
+ }
+ }
+ if( !bSuccess )
+ {
+ throw css::resource::MissingResourceException( "StringResourceImpl: No entry for ResourceID: " + ResourceID );
+ }
+ return aRetStr;
+}
+
+OUString StringResourceImpl::resolveString( const OUString& ResourceID )
+{
+ std::unique_lock aGuard( m_aMutex );
+ return implResolveString( ResourceID, m_pCurrentLocaleItem );
+}
+
+OUString StringResourceImpl::resolveStringForLocale( const OUString& ResourceID, const Locale& locale )
+{
+ std::unique_lock aGuard( m_aMutex );
+ LocaleItem* pLocaleItem = getItemForLocale( locale, false );
+ return implResolveString( ResourceID, pLocaleItem );
+}
+
+bool StringResourceImpl::implHasEntryForId( const OUString& ResourceID, LocaleItem* pLocaleItem )
+{
+ bool bSuccess = false;
+ if( pLocaleItem != nullptr && loadLocale( pLocaleItem ) )
+ {
+ IdToStringMap::iterator it = pLocaleItem->m_aIdToStringMap.find( ResourceID );
+ if( it != pLocaleItem->m_aIdToStringMap.end() )
+ bSuccess = true;
+ }
+ return bSuccess;
+}
+
+sal_Bool StringResourceImpl::hasEntryForId( const OUString& ResourceID )
+{
+ std::unique_lock aGuard( m_aMutex );
+ return implHasEntryForId( ResourceID, m_pCurrentLocaleItem );
+}
+
+sal_Bool StringResourceImpl::hasEntryForIdAndLocale( const OUString& ResourceID,
+ const Locale& locale )
+{
+ std::unique_lock aGuard( m_aMutex );
+ LocaleItem* pLocaleItem = getItemForLocale( locale, false );
+ return implHasEntryForId( ResourceID, pLocaleItem );
+}
+
+Sequence< OUString > StringResourceImpl::implGetResourceIDs( LocaleItem* pLocaleItem )
+{
+ Sequence< OUString > aIDSeq( 0 );
+ if( pLocaleItem && loadLocale( pLocaleItem ) )
+ {
+ const IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap;
+ sal_Int32 nResourceIDCount = rHashMap.size();
+ aIDSeq.realloc( nResourceIDCount );
+ OUString* pStrings = aIDSeq.getArray();
+
+ int iTarget = 0;
+ for( const auto& rEntry : rHashMap )
+ {
+ OUString aStr = rEntry.first;
+ pStrings[iTarget] = aStr;
+ iTarget++;
+ }
+ }
+ return aIDSeq;
+}
+
+Sequence< OUString > StringResourceImpl::getResourceIDsForLocale
+ ( const Locale& locale )
+{
+ std::unique_lock aGuard( m_aMutex );
+ LocaleItem* pLocaleItem = getItemForLocale( locale, false );
+ return implGetResourceIDs( pLocaleItem );
+}
+
+Sequence< OUString > StringResourceImpl::getResourceIDs( )
+{
+ std::unique_lock aGuard( m_aMutex );
+ return implGetResourceIDs( m_pCurrentLocaleItem );
+}
+
+Locale StringResourceImpl::getCurrentLocale()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ Locale aRetLocale;
+ if( m_pCurrentLocaleItem != nullptr )
+ aRetLocale = m_pCurrentLocaleItem->m_locale;
+ return aRetLocale;
+}
+
+Locale StringResourceImpl::getDefaultLocale( )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ Locale aRetLocale;
+ if( m_pDefaultLocaleItem != nullptr )
+ aRetLocale = m_pDefaultLocaleItem->m_locale;
+ return aRetLocale;
+}
+
+Sequence< Locale > StringResourceImpl::getLocales( )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ sal_Int32 nSize = m_aLocaleItemVector.size();
+ Sequence< Locale > aLocalSeq( nSize );
+ Locale* pLocales = aLocalSeq.getArray();
+ int iTarget = 0;
+ for( const auto& pLocaleItem : m_aLocaleItemVector )
+ {
+ pLocales[iTarget] = pLocaleItem->m_locale;
+ iTarget++;
+ }
+ return aLocalSeq;
+}
+
+
+// XStringResourceManager
+
+void StringResourceImpl::implCheckReadOnly( const char* pExceptionMsg )
+{
+ if( m_bReadOnly )
+ {
+ OUString errorMsg = OUString::createFromAscii( pExceptionMsg );
+ throw NoSupportException( errorMsg );
+ }
+}
+
+sal_Bool StringResourceImpl::isReadOnly()
+{
+ return m_bReadOnly;
+}
+
+void StringResourceImpl::implSetCurrentLocale( std::unique_lock<std::mutex>& rGuard, const Locale& locale,
+ bool FindClosestMatch, bool bUseDefaultIfNoMatch )
+{
+ LocaleItem* pLocaleItem = nullptr;
+ if( FindClosestMatch )
+ pLocaleItem = getClosestMatchItemForLocale( locale );
+ else
+ pLocaleItem = getItemForLocale( locale, true );
+
+ if( pLocaleItem == nullptr && bUseDefaultIfNoMatch )
+ pLocaleItem = m_pDefaultLocaleItem;
+
+ if( pLocaleItem != nullptr )
+ {
+ (void)loadLocale( pLocaleItem );
+ m_pCurrentLocaleItem = pLocaleItem;
+
+ // Only notify without modifying
+ implNotifyListeners(rGuard);
+ }
+}
+
+void StringResourceImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch )
+{
+ std::unique_lock aGuard( m_aMutex );
+ implSetCurrentLocale( aGuard, locale, FindClosestMatch, false/*bUseDefaultIfNoMatch*/ );
+}
+
+void StringResourceImpl::setDefaultLocale( const Locale& locale )
+{
+ std::unique_lock aGuard( m_aMutex );
+ implCheckReadOnly( "StringResourceImpl::setDefaultLocale(): Read only" );
+
+ LocaleItem* pLocaleItem = getItemForLocale( locale, true );
+ if( pLocaleItem && pLocaleItem != m_pDefaultLocaleItem )
+ {
+ if( m_pDefaultLocaleItem )
+ {
+ m_aChangedDefaultLocaleVector.push_back(
+ std::make_unique<LocaleItem>( m_pDefaultLocaleItem->m_locale ) );
+ }
+
+ m_pDefaultLocaleItem = pLocaleItem;
+ m_bDefaultModified = true;
+ implModified(aGuard);
+ }
+}
+
+void StringResourceImpl::implSetString( std::unique_lock<std::mutex>& rGuard, const OUString& ResourceID,
+ const OUString& Str, LocaleItem* pLocaleItem )
+{
+ if( !(pLocaleItem != nullptr && loadLocale( pLocaleItem )) )
+ return;
+
+ IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap;
+
+ IdToStringMap::iterator it = rHashMap.find( ResourceID );
+ bool bNew = ( it == rHashMap.end() );
+ if( bNew )
+ {
+ IdToIndexMap& rIndexMap = pLocaleItem->m_aIdToIndexMap;
+ rIndexMap[ ResourceID ] = pLocaleItem->m_nNextIndex++;
+ implScanIdForNumber( ResourceID );
+ }
+ rHashMap[ ResourceID ] = Str;
+ pLocaleItem->m_bModified = true;
+ implModified(rGuard);
+}
+
+void StringResourceImpl::setString( const OUString& ResourceID, const OUString& Str )
+{
+ std::unique_lock aGuard( m_aMutex );
+ implCheckReadOnly( "StringResourceImpl::setString(): Read only" );
+ implSetString( aGuard, ResourceID, Str, m_pCurrentLocaleItem );
+}
+
+void StringResourceImpl::setStringForLocale
+ ( const OUString& ResourceID, const OUString& Str, const Locale& locale )
+{
+ std::unique_lock aGuard( m_aMutex );
+ implCheckReadOnly( "StringResourceImpl::setStringForLocale(): Read only" );
+ LocaleItem* pLocaleItem = getItemForLocale( locale, false );
+ implSetString( aGuard, ResourceID, Str, pLocaleItem );
+}
+
+void StringResourceImpl::implRemoveId( std::unique_lock<std::mutex>& rGuard, const OUString& ResourceID, LocaleItem* pLocaleItem )
+{
+ if( pLocaleItem != nullptr && loadLocale( pLocaleItem ) )
+ {
+ IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap;
+ IdToStringMap::iterator it = rHashMap.find( ResourceID );
+ if( it == rHashMap.end() )
+ {
+ throw css::resource::MissingResourceException( "StringResourceImpl: No entries for ResourceID: " + ResourceID );
+ }
+ rHashMap.erase( it );
+ pLocaleItem->m_bModified = true;
+ implModified(rGuard);
+ }
+}
+
+void StringResourceImpl::removeId( const OUString& ResourceID )
+{
+ std::unique_lock aGuard( m_aMutex );
+ implCheckReadOnly( "StringResourceImpl::removeId(): Read only" );
+ implRemoveId( aGuard, ResourceID, m_pCurrentLocaleItem );
+}
+
+void StringResourceImpl::removeIdForLocale( const OUString& ResourceID, const Locale& locale )
+{
+ std::unique_lock aGuard( m_aMutex );
+ implCheckReadOnly( "StringResourceImpl::removeIdForLocale(): Read only" );
+ LocaleItem* pLocaleItem = getItemForLocale( locale, false );
+ implRemoveId( aGuard, ResourceID, pLocaleItem );
+}
+
+void StringResourceImpl::newLocale( const Locale& locale )
+{
+ std::unique_lock aGuard( m_aMutex );
+ implCheckReadOnly( "StringResourceImpl::newLocale(): Read only" );
+
+ if( getItemForLocale( locale, false ) != nullptr )
+ {
+ throw ElementExistException( "StringResourceImpl: locale already exists" );
+ }
+
+ // TODO?: Check if locale is valid? How?
+ //if (!bValid)
+ //{
+ // OUString errorMsg("StringResourceImpl: Invalid locale");
+ // throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
+ //}
+
+ LocaleItem* pLocaleItem = new LocaleItem( locale );
+ m_aLocaleItemVector.emplace_back( pLocaleItem );
+ pLocaleItem->m_bModified = true;
+
+ // Copy strings from default locale
+ LocaleItem* pCopyFromItem = m_pDefaultLocaleItem;
+ if( pCopyFromItem == nullptr )
+ pCopyFromItem = m_pCurrentLocaleItem;
+ if( pCopyFromItem != nullptr && loadLocale( pCopyFromItem ) )
+ {
+ const IdToStringMap& rSourceMap = pCopyFromItem->m_aIdToStringMap;
+ IdToStringMap& rTargetMap = pLocaleItem->m_aIdToStringMap;
+ for( const auto& rEntry : rSourceMap )
+ {
+ OUString aId = rEntry.first;
+ OUString aStr = rEntry.second;
+ rTargetMap[ aId ] = aStr;
+ }
+
+ const IdToIndexMap& rSourceIndexMap = pCopyFromItem->m_aIdToIndexMap;
+ IdToIndexMap& rTargetIndexMap = pLocaleItem->m_aIdToIndexMap;
+ for( const auto& rIndex : rSourceIndexMap )
+ {
+ OUString aId = rIndex.first;
+ sal_Int32 nIndex = rIndex.second;
+ rTargetIndexMap[ aId ] = nIndex;
+ }
+ pLocaleItem->m_nNextIndex = pCopyFromItem->m_nNextIndex;
+ }
+
+ if( m_pCurrentLocaleItem == nullptr )
+ m_pCurrentLocaleItem = pLocaleItem;
+
+ if( m_pDefaultLocaleItem == nullptr )
+ {
+ m_pDefaultLocaleItem = pLocaleItem;
+ m_bDefaultModified = true;
+ }
+
+ implModified(aGuard);
+}
+
+void StringResourceImpl::removeLocale( const Locale& locale )
+{
+ std::unique_lock aGuard( m_aMutex );
+ implCheckReadOnly( "StringResourceImpl::removeLocale(): Read only" );
+
+ LocaleItem* pRemoveItem = getItemForLocale( locale, true );
+ if( !pRemoveItem )
+ return;
+
+ // Last locale?
+ sal_Int32 nLocaleCount = m_aLocaleItemVector.size();
+ if( nLocaleCount > 1 )
+ {
+ if( m_pCurrentLocaleItem == pRemoveItem ||
+ m_pDefaultLocaleItem == pRemoveItem )
+ {
+ LocaleItem* pFallbackItem = nullptr;
+ for( const auto& pLocaleItem : m_aLocaleItemVector )
+ {
+ if( pLocaleItem.get() != pRemoveItem )
+ {
+ pFallbackItem = pLocaleItem.get();
+ break;
+ }
+ }
+ if( m_pCurrentLocaleItem == pRemoveItem )
+ {
+ setCurrentLocale( pFallbackItem->m_locale, false/*FindClosestMatch*/ );
+ }
+ if( m_pDefaultLocaleItem == pRemoveItem )
+ {
+ setDefaultLocale( pFallbackItem->m_locale );
+ }
+ }
+ }
+ auto it = std::find_if(m_aLocaleItemVector.begin(), m_aLocaleItemVector.end(),
+ [&pRemoveItem](const std::unique_ptr<LocaleItem>& rxItem) { return rxItem.get() == pRemoveItem; });
+ if (it == m_aLocaleItemVector.end())
+ return;
+
+ // Remember locale item to delete file while storing
+ m_aDeletedLocaleItemVector.push_back( std::move(*it) );
+
+ // Last locale?
+ if( nLocaleCount == 1 )
+ {
+ m_nNextUniqueNumericId = 0;
+ if( m_pDefaultLocaleItem )
+ {
+ m_aChangedDefaultLocaleVector.push_back(
+ std::make_unique<LocaleItem>( m_pDefaultLocaleItem->m_locale ) );
+ }
+ m_pCurrentLocaleItem = nullptr;
+ m_pDefaultLocaleItem = nullptr;
+ }
+
+ m_aLocaleItemVector.erase( it );
+
+ implModified(aGuard);
+}
+
+void StringResourceImpl::implScanIdForNumber( const OUString& ResourceID )
+{
+ const sal_Unicode* pSrc = ResourceID.getStr();
+ sal_Int32 nLen = ResourceID.getLength();
+
+ sal_Int32 nNumber = 0;
+ for( sal_Int32 i = 0 ; i < nLen ; i++ )
+ {
+ sal_Unicode c = pSrc[i];
+ if( c >= '0' && c <= '9' )
+ {
+ sal_uInt16 nDigitVal = c - '0';
+ nNumber = 10*nNumber + nDigitVal;
+ }
+ else
+ break;
+ }
+
+ if( m_nNextUniqueNumericId < nNumber + 1 )
+ m_nNextUniqueNumericId = nNumber + 1;
+}
+
+sal_Int32 StringResourceImpl::getUniqueNumericId( )
+{
+ if( m_nNextUniqueNumericId == UNIQUE_NUMBER_NEEDS_INITIALISATION )
+ {
+ implLoadAllLocales();
+ m_nNextUniqueNumericId = 0;
+ }
+
+ if( m_nNextUniqueNumericId < UNIQUE_NUMBER_NEEDS_INITIALISATION )
+ {
+ throw NoSupportException( "getUniqueNumericId: Extended sal_Int32 range" );
+ }
+ return m_nNextUniqueNumericId;
+}
+
+
+// Private helper methods
+
+LocaleItem* StringResourceImpl::getItemForLocale
+ ( const Locale& locale, bool bException )
+{
+ LocaleItem* pRetItem = nullptr;
+
+ // Search for locale
+ for( auto& pLocaleItem : m_aLocaleItemVector )
+ {
+ if( pLocaleItem )
+ {
+ Locale& cmp_locale = pLocaleItem->m_locale;
+ if( cmp_locale.Language == locale.Language &&
+ cmp_locale.Country == locale.Country &&
+ cmp_locale.Variant == locale.Variant )
+ {
+ pRetItem = pLocaleItem.get();
+ break;
+ }
+ }
+ }
+
+ if( pRetItem == nullptr && bException )
+ {
+ throw IllegalArgumentException( "StringResourceImpl: Invalid locale", Reference< XInterface >(), 0 );
+ }
+ return pRetItem;
+}
+
+// Returns the LocaleItem for a given locale, if it exists, otherwise NULL.
+// This method performs a closest match search, at least the language must match.
+LocaleItem* StringResourceImpl::getClosestMatchItemForLocale( const Locale& locale )
+{
+ LocaleItem* pRetItem = nullptr;
+
+ ::std::vector< Locale > aLocales( m_aLocaleItemVector.size());
+ size_t i = 0;
+ for( const auto& pLocaleItem : m_aLocaleItemVector )
+ {
+ aLocales[i] = (pLocaleItem ? pLocaleItem->m_locale : Locale());
+ ++i;
+ }
+ ::std::vector< Locale >::const_iterator iFound( LanguageTag::getMatchingFallback( aLocales, locale));
+ if (iFound != aLocales.end())
+ pRetItem = (m_aLocaleItemVector.begin() + (iFound - aLocales.begin()))->get();
+
+ return pRetItem;
+}
+
+void StringResourceImpl::implModified(std::unique_lock<std::mutex>& rGuard)
+{
+ m_bModified = true;
+ implNotifyListeners(rGuard);
+}
+
+void StringResourceImpl::implNotifyListeners(std::unique_lock<std::mutex>& rGuard)
+{
+ EventObject aEvent;
+ aEvent.Source = static_cast< XInterface* >( static_cast<OWeakObject*>(this) );
+ m_aListenerContainer.forEach(rGuard,
+ [&aEvent](const css::uno::Reference<XModifyListener>& xListener)
+ {
+ xListener->modified(aEvent);
+ }
+ );
+}
+
+
+// Loading
+
+bool StringResourceImpl::loadLocale( LocaleItem* )
+{
+ // Base implementation has nothing to load
+ return true;
+}
+
+void StringResourceImpl::implLoadAllLocales()
+{
+ // Base implementation has nothing to load
+}
+
+
+// StringResourcePersistenceImpl
+
+
+StringResourcePersistenceImpl::StringResourcePersistenceImpl( const Reference< XComponentContext >& rxContext )
+ : StringResourcePersistenceImpl_BASE( rxContext )
+{
+}
+
+
+StringResourcePersistenceImpl::~StringResourcePersistenceImpl()
+{
+}
+
+
+// XServiceInfo
+
+
+OUString StringResourcePersistenceImpl::getImplementationName( )
+{
+ return "com.sun.star.comp.scripting.StringResource";
+}
+
+
+sal_Bool StringResourcePersistenceImpl::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService( this, rServiceName );
+}
+
+
+Sequence< OUString > StringResourcePersistenceImpl::getSupportedServiceNames( )
+{
+ return StringResourceImpl::getSupportedServiceNames();
+}
+
+
+// XInitialization base functionality for derived classes
+
+
+constexpr OUStringLiteral aNameBaseDefaultStr = u"strings";
+
+void StringResourcePersistenceImpl::implInitializeCommonParameters
+ ( std::unique_lock<std::mutex>& rGuard, const Sequence< Any >& aArguments )
+{
+ bool bReadOnlyOk = (aArguments[1] >>= m_bReadOnly);
+ if( !bReadOnlyOk )
+ {
+ throw IllegalArgumentException( "XInitialization::initialize: Expected ReadOnly flag", Reference< XInterface >(), 1 );
+ }
+
+ css::lang::Locale aCurrentLocale;
+ bool bLocaleOk = (aArguments[2] >>= aCurrentLocale);
+ if( !bLocaleOk )
+ {
+ throw IllegalArgumentException( "XInitialization::initialize: Expected Locale", Reference< XInterface >(), 2 );
+ }
+
+ bool bNameBaseOk = (aArguments[3] >>= m_aNameBase);
+ if( !bNameBaseOk )
+ {
+ throw IllegalArgumentException( "XInitialization::initialize: Expected NameBase string", Reference< XInterface >(), 3 );
+ }
+ if( m_aNameBase.isEmpty() )
+ m_aNameBase = aNameBaseDefaultStr;
+
+ bool bCommentOk = (aArguments[4] >>= m_aComment);
+ if( !bCommentOk )
+ {
+ throw IllegalArgumentException( "XInitialization::initialize: Expected Comment string", Reference< XInterface >(), 4 );
+ }
+
+ implScanLocales();
+
+ implSetCurrentLocale( rGuard, aCurrentLocale, true/*FindClosestMatch*/, true/*bUseDefaultIfNoMatch*/ );
+}
+
+
+// Forwarding calls to base class
+
+// XModifyBroadcaster
+void StringResourcePersistenceImpl::addModifyListener( const Reference< XModifyListener >& aListener )
+{
+ StringResourceImpl::addModifyListener( aListener );
+}
+void StringResourcePersistenceImpl::removeModifyListener( const Reference< XModifyListener >& aListener )
+{
+ StringResourceImpl::removeModifyListener( aListener );
+}
+
+// XStringResourceResolver
+OUString StringResourcePersistenceImpl::resolveString( const OUString& ResourceID )
+{
+ return StringResourceImpl::resolveString( ResourceID ) ;
+}
+OUString StringResourcePersistenceImpl::resolveStringForLocale( const OUString& ResourceID, const Locale& locale )
+{
+ return StringResourceImpl::resolveStringForLocale( ResourceID, locale );
+}
+sal_Bool StringResourcePersistenceImpl::hasEntryForId( const OUString& ResourceID )
+{
+ return StringResourceImpl::hasEntryForId( ResourceID ) ;
+}
+sal_Bool StringResourcePersistenceImpl::hasEntryForIdAndLocale( const OUString& ResourceID,
+ const Locale& locale )
+{
+ return StringResourceImpl::hasEntryForIdAndLocale( ResourceID, locale );
+}
+Locale StringResourcePersistenceImpl::getCurrentLocale()
+{
+ return StringResourceImpl::getCurrentLocale();
+}
+Locale StringResourcePersistenceImpl::getDefaultLocale( )
+{
+ return StringResourceImpl::getDefaultLocale();
+}
+Sequence< Locale > StringResourcePersistenceImpl::getLocales( )
+{
+ return StringResourceImpl::getLocales();
+}
+
+// XStringResourceManager
+sal_Bool StringResourcePersistenceImpl::isReadOnly()
+{
+ return StringResourceImpl::isReadOnly();
+}
+void StringResourcePersistenceImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch )
+{
+ StringResourceImpl::setCurrentLocale( locale, FindClosestMatch );
+}
+void StringResourcePersistenceImpl::setDefaultLocale( const Locale& locale )
+{
+ StringResourceImpl::setDefaultLocale( locale );
+}
+Sequence< OUString > StringResourcePersistenceImpl::getResourceIDs( )
+{
+ return StringResourceImpl::getResourceIDs();
+}
+void StringResourcePersistenceImpl::setString( const OUString& ResourceID, const OUString& Str )
+{
+ StringResourceImpl::setString( ResourceID, Str );
+}
+void StringResourcePersistenceImpl::setStringForLocale
+ ( const OUString& ResourceID, const OUString& Str, const Locale& locale )
+{
+ StringResourceImpl::setStringForLocale( ResourceID, Str, locale );
+}
+Sequence< OUString > StringResourcePersistenceImpl::getResourceIDsForLocale
+ ( const Locale& locale )
+{
+ return StringResourceImpl::getResourceIDsForLocale( locale );
+}
+void StringResourcePersistenceImpl::removeId( const OUString& ResourceID )
+{
+ StringResourceImpl::removeId( ResourceID );
+}
+void StringResourcePersistenceImpl::removeIdForLocale( const OUString& ResourceID, const Locale& locale )
+{
+ StringResourceImpl::removeIdForLocale( ResourceID, locale );
+}
+void StringResourcePersistenceImpl::newLocale( const Locale& locale )
+{
+ StringResourceImpl::newLocale( locale );
+}
+void StringResourcePersistenceImpl::removeLocale( const Locale& locale )
+{
+ StringResourceImpl::removeLocale( locale );
+}
+sal_Int32 StringResourcePersistenceImpl::getUniqueNumericId( )
+{
+ return StringResourceImpl::getUniqueNumericId();
+}
+
+
+// XStringResourcePersistence
+
+void StringResourcePersistenceImpl::store()
+{
+}
+
+sal_Bool StringResourcePersistenceImpl::isModified( )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ return m_bModified;
+}
+
+void StringResourcePersistenceImpl::setComment( const OUString& Comment )
+{
+ m_aComment = Comment;
+}
+
+void StringResourcePersistenceImpl::storeToStorage( const Reference< XStorage >& Storage,
+ const OUString& NameBase, const OUString& Comment )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ implStoreAtStorage( NameBase, Comment, Storage, false/*bUsedForStore*/, true/*bStoreAll*/ );
+}
+
+void StringResourcePersistenceImpl::implStoreAtStorage
+(
+ const OUString& aNameBase,
+ const OUString& aComment,
+ const Reference< css::embed::XStorage >& Storage,
+ bool bUsedForStore,
+ bool bStoreAll
+)
+{
+ // Delete files for deleted locales
+ if( bUsedForStore )
+ {
+ for( auto& pLocaleItem : m_aDeletedLocaleItemVector )
+ {
+ if( pLocaleItem )
+ {
+ OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem.get(), m_aNameBase ) + ".properties";
+
+ try
+ {
+ Storage->removeElement( aStreamName );
+ }
+ catch( Exception& )
+ {}
+
+ pLocaleItem.reset();
+ }
+ }
+ m_aDeletedLocaleItemVector.clear();
+ }
+
+ for( auto& pLocaleItem : m_aLocaleItemVector )
+ {
+ if( pLocaleItem != nullptr && (bStoreAll || pLocaleItem->m_bModified) &&
+ loadLocale( pLocaleItem.get() ) )
+ {
+ OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem.get(), aNameBase ) + ".properties";
+
+ Reference< io::XStream > xElementStream =
+ Storage->openStreamElement( aStreamName, ElementModes::READWRITE );
+
+ uno::Reference< beans::XPropertySet > xProps( xElementStream, uno::UNO_QUERY );
+ OSL_ENSURE( xProps.is(), "The StorageStream must implement XPropertySet interface!" );
+ if ( xProps.is() )
+ {
+ OUString aPropName("MediaType");
+ xProps->setPropertyValue( aPropName, uno::Any( OUString("text/plain") ) );
+
+ aPropName = "UseCommonStoragePasswordEncryption";
+ xProps->setPropertyValue( aPropName, uno::Any( true ) );
+ }
+
+ Reference< io::XOutputStream > xOutputStream = xElementStream->getOutputStream();
+ if( xOutputStream.is() )
+ implWritePropertiesFile( pLocaleItem.get(), xOutputStream, aComment );
+ xOutputStream->closeOutput();
+
+ if( bUsedForStore )
+ pLocaleItem->m_bModified = false;
+ }
+ }
+
+ // Delete files for changed defaults
+ if( bUsedForStore )
+ {
+ for( auto& pLocaleItem : m_aChangedDefaultLocaleVector )
+ {
+ OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem.get(), m_aNameBase ) + ".default";
+
+ try
+ {
+ Storage->removeElement( aStreamName );
+ }
+ catch( Exception& )
+ {}
+
+ pLocaleItem.reset();
+ }
+ m_aChangedDefaultLocaleVector.clear();
+ }
+
+ // Default locale
+ if( !(m_pDefaultLocaleItem != nullptr && (bStoreAll || m_bDefaultModified)) )
+ return;
+
+ OUString aStreamName = implGetFileNameForLocaleItem( m_pDefaultLocaleItem, aNameBase ) + ".default";
+
+ Reference< io::XStream > xElementStream =
+ Storage->openStreamElement( aStreamName, ElementModes::READWRITE );
+
+ // Only create stream without content
+ Reference< io::XOutputStream > xOutputStream = xElementStream->getOutputStream();
+ xOutputStream->closeOutput();
+
+ if( bUsedForStore )
+ m_bDefaultModified = false;
+}
+
+void StringResourcePersistenceImpl::storeToURL( const OUString& URL,
+ const OUString& NameBase, const OUString& Comment,
+ const Reference< css::task::XInteractionHandler >& Handler )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ Reference< ucb::XSimpleFileAccess3 > xFileAccess = ucb::SimpleFileAccess::create(m_xContext);
+ if( xFileAccess.is() && Handler.is() )
+ xFileAccess->setInteractionHandler( Handler );
+
+ implStoreAtLocation( URL, NameBase, Comment, xFileAccess, false/*bUsedForStore*/, true/*bStoreAll*/ );
+}
+
+void StringResourcePersistenceImpl::implKillRemovedLocaleFiles
+(
+ std::u16string_view Location,
+ const OUString& aNameBase,
+ const css::uno::Reference< css::ucb::XSimpleFileAccess3 >& xFileAccess
+)
+{
+ // Delete files for deleted locales
+ for( auto& pLocaleItem : m_aDeletedLocaleItemVector )
+ {
+ if( pLocaleItem )
+ {
+ OUString aCompleteFileName =
+ implGetPathForLocaleItem( pLocaleItem.get(), aNameBase, Location );
+ if( xFileAccess->exists( aCompleteFileName ) )
+ xFileAccess->kill( aCompleteFileName );
+
+ pLocaleItem.reset();
+ }
+ }
+ m_aDeletedLocaleItemVector.clear();
+}
+
+void StringResourcePersistenceImpl::implKillChangedDefaultFiles
+(
+ std::u16string_view Location,
+ const OUString& aNameBase,
+ const css::uno::Reference< css::ucb::XSimpleFileAccess3 >& xFileAccess
+)
+{
+ // Delete files for changed defaults
+ for( auto& pLocaleItem : m_aChangedDefaultLocaleVector )
+ {
+ OUString aCompleteFileName =
+ implGetPathForLocaleItem( pLocaleItem.get(), aNameBase, Location, true );
+ if( xFileAccess->exists( aCompleteFileName ) )
+ xFileAccess->kill( aCompleteFileName );
+ pLocaleItem.reset();
+ }
+ m_aChangedDefaultLocaleVector.clear();
+}
+
+void StringResourcePersistenceImpl::implStoreAtLocation
+(
+ std::u16string_view Location,
+ const OUString& aNameBase,
+ const OUString& aComment,
+ const Reference< ucb::XSimpleFileAccess3 >& xFileAccess,
+ bool bUsedForStore,
+ bool bStoreAll,
+ bool bKillAll
+)
+{
+ // Delete files for deleted locales
+ if( bUsedForStore || bKillAll )
+ implKillRemovedLocaleFiles( Location, aNameBase, xFileAccess );
+
+ for( auto& pLocaleItem : m_aLocaleItemVector )
+ {
+ if( pLocaleItem != nullptr && (bStoreAll || bKillAll || pLocaleItem->m_bModified) &&
+ loadLocale( pLocaleItem.get() ) )
+ {
+ OUString aCompleteFileName =
+ implGetPathForLocaleItem( pLocaleItem.get(), aNameBase, Location );
+ if( xFileAccess->exists( aCompleteFileName ) )
+ xFileAccess->kill( aCompleteFileName );
+
+ if( !bKillAll )
+ {
+ // Create Output stream
+ Reference< io::XOutputStream > xOutputStream = xFileAccess->openFileWrite( aCompleteFileName );
+ if( xOutputStream.is() )
+ {
+ implWritePropertiesFile( pLocaleItem.get(), xOutputStream, aComment );
+ xOutputStream->closeOutput();
+ }
+ if( bUsedForStore )
+ pLocaleItem->m_bModified = false;
+ }
+ }
+ }
+
+ // Delete files for changed defaults
+ if( bUsedForStore || bKillAll )
+ implKillChangedDefaultFiles( Location, aNameBase, xFileAccess );
+
+ // Default locale
+ if( !(m_pDefaultLocaleItem != nullptr && (bStoreAll || bKillAll || m_bDefaultModified)) )
+ return;
+
+ OUString aCompleteFileName =
+ implGetPathForLocaleItem( m_pDefaultLocaleItem, aNameBase, Location, true );
+ if( xFileAccess->exists( aCompleteFileName ) )
+ xFileAccess->kill( aCompleteFileName );
+
+ if( !bKillAll )
+ {
+ // Create Output stream
+ Reference< io::XOutputStream > xOutputStream = xFileAccess->openFileWrite( aCompleteFileName );
+ if( xOutputStream.is() )
+ xOutputStream->closeOutput();
+
+ if( bUsedForStore )
+ m_bDefaultModified = false;
+ }
+}
+
+
+// BinaryOutput, helper class for exportBinary
+
+class BinaryOutput
+{
+ Reference< XComponentContext > m_xContext;
+ Reference< XInterface > m_xTempFile;
+ Reference< io::XOutputStream > m_xOutputStream;
+
+public:
+ explicit BinaryOutput( Reference< XComponentContext > const & xContext );
+
+ const Reference< io::XOutputStream >& getOutputStream() const
+ { return m_xOutputStream; }
+
+ Sequence< ::sal_Int8 > closeAndGetData();
+
+ // Template to be used with sal_Int16 and sal_Unicode
+ template< class T >
+ void write16BitInt( T n );
+ void writeInt16( sal_Int16 n )
+ { write16BitInt( n ); }
+ void writeUnicodeChar( sal_Unicode n )
+ { write16BitInt( n ); }
+ void writeInt32( sal_Int32 n );
+ void writeString( const OUString& aStr );
+};
+
+BinaryOutput::BinaryOutput( Reference< XComponentContext > const & xContext )
+ : m_xContext( xContext )
+{
+ m_xTempFile = io::TempFile::create( m_xContext );
+ m_xOutputStream.set( m_xTempFile, UNO_QUERY_THROW );
+}
+
+template< class T >
+void BinaryOutput::write16BitInt( T n )
+{
+ if( !m_xOutputStream.is() )
+ return;
+
+ Sequence< sal_Int8 > aSeq( 2 );
+ sal_Int8* p = aSeq.getArray();
+
+ sal_Int8 nLow = sal_Int8( n & 0xff );
+ sal_Int8 nHigh = sal_Int8( n >> 8 );
+
+ p[0] = nLow;
+ p[1] = nHigh;
+ m_xOutputStream->writeBytes( aSeq );
+}
+
+void BinaryOutput::writeInt32( sal_Int32 n )
+{
+ if( !m_xOutputStream.is() )
+ return;
+
+ Sequence< sal_Int8 > aSeq( 4 );
+ sal_Int8* p = aSeq.getArray();
+
+ for( sal_Int16 i = 0 ; i < 4 ; i++ )
+ {
+ p[i] = sal_Int8( n & 0xff );
+ n >>= 8;
+ }
+ m_xOutputStream->writeBytes( aSeq );
+}
+
+void BinaryOutput::writeString( const OUString& aStr )
+{
+ sal_Int32 nLen = aStr.getLength();
+ const sal_Unicode* pStr = aStr.getStr();
+
+ for( sal_Int32 i = 0 ; i < nLen ; i++ )
+ writeUnicodeChar( pStr[i] );
+
+ writeUnicodeChar( 0 );
+}
+
+Sequence< ::sal_Int8 > BinaryOutput::closeAndGetData()
+{
+ Sequence< ::sal_Int8 > aRetSeq;
+ if( !m_xOutputStream.is() )
+ return aRetSeq;
+
+ m_xOutputStream->closeOutput();
+
+ Reference< io::XSeekable> xSeekable( m_xTempFile, UNO_QUERY );
+ if( !xSeekable.is() )
+ return aRetSeq;
+
+ sal_Int32 nSize = static_cast<sal_Int32>(xSeekable->getPosition());
+
+ Reference< io::XInputStream> xInputStream( m_xTempFile, UNO_QUERY );
+ if( !xInputStream.is() )
+ return aRetSeq;
+
+ xSeekable->seek( 0 );
+ sal_Int32 nRead = xInputStream->readBytes( aRetSeq, nSize );
+ OSL_ENSURE( nRead == nSize, "BinaryOutput::closeAndGetData: nRead != nSize" );
+
+ return aRetSeq;
+}
+
+
+// Binary format:
+
+// Header
+// Byte Content
+// 0 + 1 sal_Int16: Version, currently 0, low byte first
+// 2 + 3 sal_Int16: Locale count = n, low byte first
+// 4 + 5 sal_Int16: Default Locale position in Locale list, == n if none
+// 6 - 7 sal_Int32: Start index locale block 0, lowest byte first
+// (n-1) * sal_Int32: Start index locale block 1 to n, lowest byte first
+// 6 + 4*n sal_Int32: "Start index" non existing locale block n+1,
+// marks the first invalid index, kind of EOF
+
+// Locale block
+// All strings are stored as 2-Byte-0 terminated sequence
+// of 16 bit Unicode characters, each with low byte first
+// Empty strings only contain the 2-Byte-0
+
+// Members of com.sun.star.lang.Locale
+// with l1 = Locale.Language.getLength()
+// with l2 = Locale.Country.getLength()
+// with l3 = Locale.Variant.getLength()
+// pos0 = 0 Locale.Language
+// pos1 = 2 * (l1 + 1) Locale.Country
+// pos2 = pos1 + 2 * (l2 + 1) Locale.Variant
+// pos3 = pos2 + 2 * (l3 + 1)
+// pos3 Properties file written by implWritePropertiesFile
+
+Sequence< sal_Int8 > StringResourcePersistenceImpl::exportBinary( )
+{
+ BinaryOutput aOut( m_xContext );
+
+ sal_Int32 nLocaleCount = m_aLocaleItemVector.size();
+ std::vector<Sequence< sal_Int8 >> aLocaleDataSeq(nLocaleCount);
+
+ sal_Int32 iLocale = 0;
+ sal_Int32 iDefault = 0;
+ for( auto& pLocaleItem : m_aLocaleItemVector )
+ {
+ if( pLocaleItem != nullptr && loadLocale( pLocaleItem.get() ) )
+ {
+ if( m_pDefaultLocaleItem == pLocaleItem.get() )
+ iDefault = iLocale;
+
+ BinaryOutput aLocaleOut( m_xContext );
+ implWriteLocaleBinary( pLocaleItem.get(), aLocaleOut );
+
+ aLocaleDataSeq[iLocale] = aLocaleOut.closeAndGetData();
+ }
+ ++iLocale;
+ }
+
+ // Write header
+ sal_Int16 nLocaleCount16 = static_cast<sal_Int16>(nLocaleCount);
+ sal_Int16 iDefault16 = static_cast<sal_Int16>(iDefault);
+ aOut.writeInt16( 0 ); // nVersion
+ aOut.writeInt16( nLocaleCount16 );
+ aOut.writeInt16( iDefault16 );
+
+ // Write data positions
+ sal_Int32 nDataPos = 6 + 4 * (nLocaleCount + 1);
+ for( iLocale = 0; iLocale < nLocaleCount; iLocale++ )
+ {
+ aOut.writeInt32( nDataPos );
+
+ Sequence< sal_Int8 >& rSeq = aLocaleDataSeq[iLocale];
+ sal_Int32 nSeqLen = rSeq.getLength();
+ nDataPos += nSeqLen;
+ }
+ // Write final position
+ aOut.writeInt32( nDataPos );
+
+ // Write data
+ Reference< io::XOutputStream > xOutputStream = aOut.getOutputStream();
+ if( xOutputStream.is() )
+ {
+ for( iLocale = 0; iLocale < nLocaleCount; iLocale++ )
+ {
+ Sequence< sal_Int8 >& rSeq = aLocaleDataSeq[iLocale];
+ xOutputStream->writeBytes( rSeq );
+ }
+ }
+
+ Sequence< sal_Int8 > aRetSeq = aOut.closeAndGetData();
+ return aRetSeq;
+}
+
+void StringResourcePersistenceImpl::implWriteLocaleBinary
+ ( LocaleItem* pLocaleItem, BinaryOutput& rOut )
+{
+ Reference< io::XOutputStream > xOutputStream = rOut.getOutputStream();
+ if( !xOutputStream.is() )
+ return;
+
+ Locale& rLocale = pLocaleItem->m_locale;
+ rOut.writeString( rLocale.Language );
+ rOut.writeString( rLocale.Country );
+ rOut.writeString( rLocale.Variant );
+ implWritePropertiesFile( pLocaleItem, xOutputStream, m_aComment );
+}
+
+
+// BinaryOutput, helper class for exportBinary
+
+namespace {
+
+class BinaryInput
+{
+ Sequence< sal_Int8 > m_aData;
+ Reference< XComponentContext > m_xContext;
+
+ const sal_Int8* m_pData;
+ sal_Int32 m_nCurPos;
+ sal_Int32 m_nSize;
+
+public:
+ BinaryInput( const Sequence< ::sal_Int8 >& aData, Reference< XComponentContext > const & xContext );
+
+ Reference< io::XInputStream > getInputStreamForSection( sal_Int32 nSize );
+
+ void seek( sal_Int32 nPos );
+ sal_Int32 getPosition() const
+ { return m_nCurPos; }
+
+ sal_Int16 readInt16();
+ sal_Int32 readInt32();
+ sal_Unicode readUnicodeChar();
+ OUString readString();
+};
+
+}
+
+BinaryInput::BinaryInput( const Sequence< ::sal_Int8 >& aData, Reference< XComponentContext > const & xContext )
+ : m_aData( aData )
+ , m_xContext( xContext )
+{
+ m_pData = m_aData.getConstArray();
+ m_nCurPos = 0;
+ m_nSize = m_aData.getLength();
+}
+
+Reference< io::XInputStream > BinaryInput::getInputStreamForSection( sal_Int32 nSize )
+{
+ Reference< io::XInputStream > xIn;
+ if( m_nCurPos + nSize <= m_nSize )
+ {
+ Reference< io::XOutputStream > xTempOut( io::TempFile::create(m_xContext), UNO_QUERY_THROW );
+ Sequence< sal_Int8 > aSection( m_pData + m_nCurPos, nSize );
+ xTempOut->writeBytes( aSection );
+
+ Reference< io::XSeekable> xSeekable( xTempOut, UNO_QUERY );
+ if( xSeekable.is() )
+ xSeekable->seek( 0 );
+
+ xIn.set( xTempOut, UNO_QUERY );
+ }
+ else
+ OSL_FAIL( "BinaryInput::getInputStreamForSection(): Read past end" );
+
+ return xIn;
+}
+
+void BinaryInput::seek( sal_Int32 nPos )
+{
+ if( nPos <= m_nSize )
+ m_nCurPos = nPos;
+ else
+ OSL_FAIL( "BinaryInput::seek(): Position past end" );
+}
+
+
+sal_Int16 BinaryInput::readInt16()
+{
+ sal_Int16 nRet = 0;
+ if( m_nCurPos + 2 <= m_nSize )
+ {
+ nRet = nRet + sal_Int16( sal_uInt8( m_pData[m_nCurPos++] ) );
+ nRet += 256 * sal_Int16( sal_uInt8( m_pData[m_nCurPos++] ) );
+ }
+ else
+ OSL_FAIL( "BinaryInput::readInt16(): Read past end" );
+
+ return nRet;
+}
+
+sal_Int32 BinaryInput::readInt32()
+{
+ sal_Int32 nRet = 0;
+ if( m_nCurPos + 4 <= m_nSize )
+ {
+ sal_Int32 nFactor = 1;
+ for( sal_Int16 i = 0; i < 4; i++ )
+ {
+ nRet += sal_uInt8( m_pData[m_nCurPos++] ) * nFactor;
+ nFactor *= 256;
+ }
+ }
+ else
+ OSL_FAIL( "BinaryInput::readInt32(): Read past end" );
+
+ return nRet;
+}
+
+sal_Unicode BinaryInput::readUnicodeChar()
+{
+ sal_uInt16 nRet = 0;
+ if( m_nCurPos + 2 <= m_nSize )
+ {
+ nRet = nRet + sal_uInt8( m_pData[m_nCurPos++] );
+ nRet += 256 * sal_uInt8( m_pData[m_nCurPos++] );
+ }
+ else
+ OSL_FAIL( "BinaryInput::readUnicodeChar(): Read past end" );
+
+ sal_Unicode cRet = nRet;
+ return cRet;
+}
+
+OUString BinaryInput::readString()
+{
+ OUStringBuffer aBuf;
+ sal_Unicode c;
+ do
+ {
+ c = readUnicodeChar();
+ if( c != 0 )
+ aBuf.append( c );
+ }
+ while( c != 0 );
+
+ OUString aRetStr = aBuf.makeStringAndClear();
+ return aRetStr;
+}
+
+void StringResourcePersistenceImpl::importBinary( const Sequence< ::sal_Int8 >& Data )
+{
+ // Init: Remove all locales
+ sal_Int32 nOldLocaleCount = 0;
+ do
+ {
+ Sequence< Locale > aLocaleSeq = getLocales();
+ nOldLocaleCount = aLocaleSeq.getLength();
+ if( nOldLocaleCount > 0 )
+ {
+ Locale aLocale = aLocaleSeq[0];
+ removeLocale( aLocale );
+ }
+ }
+ while( nOldLocaleCount > 0 );
+
+ // Import data
+ BinaryInput aIn( Data, m_xContext );
+
+ aIn.readInt16(); // version
+ sal_Int32 nLocaleCount = aIn.readInt16();
+ sal_Int32 iDefault = aIn.readInt16();
+
+ std::unique_ptr<sal_Int32[]> pPositions( new sal_Int32[nLocaleCount + 1] );
+ for( sal_Int32 i = 0; i < nLocaleCount + 1; i++ )
+ pPositions[i] = aIn.readInt32();
+
+ // Import locales
+ LocaleItem* pUseAsDefaultItem = nullptr;
+ for( sal_Int32 i = 0; i < nLocaleCount; i++ )
+ {
+ sal_Int32 nPos = pPositions[i];
+ aIn.seek( nPos );
+
+ Locale aLocale;
+ aLocale.Language = aIn.readString();
+ aLocale.Country = aIn.readString();
+ aLocale.Variant = aIn.readString();
+
+ sal_Int32 nAfterStringPos = aIn.getPosition();
+ sal_Int32 nSize = pPositions[i+1] - nAfterStringPos;
+ Reference< io::XInputStream > xInput = aIn.getInputStreamForSection( nSize );
+ if( xInput.is() )
+ {
+ LocaleItem* pLocaleItem = new LocaleItem( std::move(aLocale) );
+ if( iDefault == i )
+ pUseAsDefaultItem = pLocaleItem;
+ m_aLocaleItemVector.emplace_back( pLocaleItem );
+ implReadPropertiesFile( pLocaleItem, xInput );
+ }
+ }
+
+ if( pUseAsDefaultItem != nullptr )
+ setDefaultLocale( pUseAsDefaultItem->m_locale );
+}
+
+
+// Private helper methods
+
+static bool checkNamingSceme( const OUString& aName, const OUString& aNameBase,
+ Locale& aLocale )
+{
+ bool bSuccess = false;
+
+ sal_Int32 nNameLen = aName.getLength();
+ sal_Int32 nNameBaseLen = aNameBase.getLength();
+
+ // Name has to start with NameBase followed
+ // by a '_' and at least one more character
+ if( aName.startsWith( aNameBase ) && nNameBaseLen < nNameLen-1 &&
+ aName[nNameBaseLen] == '_' )
+ {
+ bSuccess = true;
+
+ /* FIXME-BCP47: this uses '_' underscore character as separator and
+ * also appends Variant, which can't be blindly changed as it would
+ * violate the naming scheme in use. */
+
+ sal_Int32 iStart = nNameBaseLen + 1;
+ sal_Int32 iNext_ = aName.indexOf( '_', iStart );
+ if( iNext_ != -1 && iNext_ < nNameLen-1 )
+ {
+ aLocale.Language = aName.copy( iStart, iNext_ - iStart );
+
+ iStart = iNext_ + 1;
+ iNext_ = aName.indexOf( '_', iStart );
+ if( iNext_ != -1 && iNext_ < nNameLen-1 )
+ {
+ aLocale.Country = aName.copy( iStart, iNext_ - iStart );
+ aLocale.Variant = aName.copy( iNext_ + 1 );
+ }
+ else
+ aLocale.Country = aName.copy( iStart );
+ }
+ else
+ aLocale.Language = aName.copy( iStart );
+ }
+ return bSuccess;
+}
+
+void StringResourcePersistenceImpl::implLoadAllLocales()
+{
+ for( auto& pLocaleItem : m_aLocaleItemVector )
+ if( pLocaleItem )
+ loadLocale( pLocaleItem.get() );
+}
+
+// Scan locale properties files helper
+void StringResourcePersistenceImpl::implScanLocaleNames( const Sequence< OUString >& aContentSeq )
+{
+ Locale aDefaultLocale;
+ bool bDefaultFound = false;
+
+ for( const OUString& aCompleteName : aContentSeq )
+ {
+ OUString aPureName;
+ OUString aExtension;
+ sal_Int32 iDot = aCompleteName.lastIndexOf( '.' );
+ sal_Int32 iSlash = aCompleteName.lastIndexOf( '/' );
+ if( iDot != -1 && iDot > iSlash)
+ {
+ sal_Int32 iCopyFrom = (iSlash != -1) ? iSlash + 1 : 0;
+ aPureName = aCompleteName.copy( iCopyFrom, iDot-iCopyFrom );
+ aExtension = aCompleteName.copy( iDot + 1 );
+ }
+
+ if ( aExtension == "properties" )
+ {
+ //OUString aName = aInetObj.getBase();
+ Locale aLocale;
+
+ if( checkNamingSceme( aPureName, m_aNameBase, aLocale ) )
+ {
+ LocaleItem* pLocaleItem = new LocaleItem( std::move(aLocale), false );
+ m_aLocaleItemVector.emplace_back( pLocaleItem );
+
+ if( m_pCurrentLocaleItem == nullptr )
+ m_pCurrentLocaleItem = pLocaleItem;
+
+ if( m_pDefaultLocaleItem == nullptr )
+ {
+ m_pDefaultLocaleItem = pLocaleItem;
+ m_bDefaultModified = true;
+ }
+ }
+ }
+ else if( !bDefaultFound && aExtension == "default" )
+ {
+ if( checkNamingSceme( aPureName, m_aNameBase, aDefaultLocale ) )
+ bDefaultFound = true;
+ }
+ }
+ if( bDefaultFound )
+ {
+ LocaleItem* pLocaleItem = getItemForLocale( aDefaultLocale, false );
+ if( pLocaleItem )
+ {
+ m_pDefaultLocaleItem = pLocaleItem;
+ m_bDefaultModified = false;
+ }
+ }
+}
+
+// Scan locale properties files
+void StringResourcePersistenceImpl::implScanLocales()
+{
+ // Dummy implementation, method not called for this
+ // base class, but pure virtual not possible-
+}
+
+bool StringResourcePersistenceImpl::loadLocale( LocaleItem* pLocaleItem )
+{
+ bool bSuccess = false;
+
+ OSL_ENSURE( pLocaleItem, "StringResourcePersistenceImpl::loadLocale(): pLocaleItem == NULL" );
+ if( pLocaleItem )
+ {
+ if( pLocaleItem->m_bLoaded )
+ {
+ bSuccess = true;
+ }
+ else
+ {
+ bSuccess = implLoadLocale( pLocaleItem );
+ pLocaleItem->m_bLoaded = true; // = bSuccess??? -> leads to more tries
+ }
+ }
+ return bSuccess;
+}
+
+bool StringResourcePersistenceImpl::implLoadLocale( LocaleItem* )
+{
+ // Dummy implementation, method not called for this
+ // base class, but pure virtual not possible-
+ return false;
+}
+
+static OUString implGetNameScemeForLocaleItem( const LocaleItem* pLocaleItem )
+{
+ /* FIXME-BCP47: this uses '_' underscore character as separator and
+ * also appends Variant, which can't be blindly changed as it would
+ * violate the naming scheme in use. */
+
+ static const char aUnder[] = "_";
+
+ OSL_ENSURE( pLocaleItem,
+ "StringResourcePersistenceImpl::implGetNameScemeForLocaleItem(): pLocaleItem == NULL" );
+ Locale aLocale = pLocaleItem->m_locale;
+
+ OUString aRetStr = aUnder + aLocale.Language;
+
+ OUString aCountry = aLocale.Country;
+ if( !aCountry.isEmpty() )
+ {
+ aRetStr += aUnder + aCountry;
+ }
+
+ OUString aVariant = aLocale.Variant;
+ if( !aVariant.isEmpty() )
+ {
+ aRetStr += aUnder + aVariant;
+ }
+ return aRetStr;
+}
+
+OUString StringResourcePersistenceImpl::implGetFileNameForLocaleItem
+ ( LocaleItem const * pLocaleItem, const OUString& aNameBase )
+{
+ OUString aFileName = aNameBase;
+ if( aFileName.isEmpty() )
+ aFileName = aNameBaseDefaultStr;
+
+ aFileName += implGetNameScemeForLocaleItem( pLocaleItem );
+ return aFileName;
+}
+
+OUString StringResourcePersistenceImpl::implGetPathForLocaleItem
+ ( LocaleItem const * pLocaleItem, const OUString& aNameBase,
+ std::u16string_view aLocation, bool bDefaultFile )
+{
+ OUString aFileName = implGetFileNameForLocaleItem( pLocaleItem, aNameBase );
+ INetURLObject aInetObj( aLocation );
+ aInetObj.insertName( aFileName, true, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+ if( bDefaultFile )
+ aInetObj.setExtension( u"default" );
+ else
+ aInetObj.setExtension( u"properties" );
+ OUString aCompleteFileName = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ return aCompleteFileName;
+}
+
+// White space according to Java property files specification in
+// http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html#load(java.io.InputStream)
+static bool isWhiteSpace( sal_Unicode c )
+{
+ bool bWhite = ( c == 0x0020 || // space
+ c == 0x0009 || // tab
+ c == 0x000a || // line feed, not always handled by TextInputStream
+ c == 0x000d || // carriage return, not always handled by TextInputStream
+ c == 0x000C ); // form feed
+ return bWhite;
+}
+
+static void skipWhites( const sal_Unicode* pBuf, sal_Int32 nLen, sal_Int32& ri )
+{
+ while( ri < nLen )
+ {
+ if( !isWhiteSpace( pBuf[ri] ) )
+ break;
+ ri++;
+ }
+}
+
+static bool isHexDigit( sal_Unicode c, sal_uInt16& nDigitVal )
+{
+ bool bRet = true;
+ if( c >= '0' && c <= '9' )
+ nDigitVal = c - '0';
+ else if( c >= 'a' && c <= 'f' )
+ nDigitVal = c - 'a' + 10;
+ else if( c >= 'A' && c <= 'F' )
+ nDigitVal = c - 'A' + 10;
+ else
+ bRet = false;
+ return bRet;
+}
+
+static sal_Unicode getEscapeChar( const sal_Unicode* pBuf, sal_Int32 nLen, sal_Int32& ri )
+{
+ sal_Int32 i = ri;
+
+ sal_Unicode cRet = 0;
+ sal_Unicode c = pBuf[i];
+ switch( c )
+ {
+ case 't':
+ cRet = 0x0009;
+ break;
+ case 'n':
+ cRet = 0x000a;
+ break;
+ case 'f':
+ cRet = 0x000c;
+ break;
+ case 'r':
+ cRet = 0x000d;
+ break;
+ case '\\':
+ cRet = '\\';
+ break;
+ case 'u':
+ {
+ // Skip multiple u
+ i++;
+ while( i < nLen && pBuf[i] == 'u' )
+ i++;
+
+ // Process hex digits
+ sal_Int32 nDigitCount = 0;
+ sal_uInt16 nDigitVal;
+ while( i < nLen && isHexDigit( pBuf[i], nDigitVal ) )
+ {
+ cRet = 16 * cRet + nDigitVal;
+
+ nDigitCount++;
+ if( nDigitCount == 4 )
+ {
+ // Write back position
+ ri = i;
+ break;
+ }
+ i++;
+ }
+ break;
+ }
+ default:
+ cRet = c;
+ }
+
+ return cRet;
+}
+
+static void CheckContinueInNextLine( const Reference< io::XTextInputStream2 >& xTextInputStream,
+ OUString& aLine, bool& bEscapePending, const sal_Unicode*& pBuf,
+ sal_Int32& nLen, sal_Int32& i )
+{
+ if( !(i == nLen && bEscapePending) )
+ return;
+
+ bEscapePending = false;
+
+ if( !xTextInputStream->isEOF() )
+ {
+ aLine = xTextInputStream->readLine();
+ nLen = aLine.getLength();
+ pBuf = aLine.getStr();
+ i = 0;
+
+ skipWhites( pBuf, nLen, i );
+ }
+}
+
+bool StringResourcePersistenceImpl::implReadPropertiesFile
+ ( LocaleItem* pLocaleItem, const Reference< io::XInputStream >& xInputStream )
+{
+ if( !xInputStream.is() || pLocaleItem == nullptr )
+ return false;
+
+ Reference< io::XTextInputStream2 > xTextInputStream = io::TextInputStream::create( m_xContext );
+
+ xTextInputStream->setInputStream( xInputStream );
+
+ OUString aEncodingStr = OUString::createFromAscii
+ ( rtl_getMimeCharsetFromTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) );
+ xTextInputStream->setEncoding( aEncodingStr );
+
+ OUString aLine;
+ while( !xTextInputStream->isEOF() )
+ {
+ aLine = xTextInputStream->readLine();
+
+ sal_Int32 nLen = aLine.getLength();
+ if( 0 == nLen )
+ continue;
+ const sal_Unicode* pBuf = aLine.getStr();
+ OUStringBuffer aBuf;
+ sal_Unicode c = 0;
+ sal_Int32 i = 0;
+
+ skipWhites( pBuf, nLen, i );
+ if( i == nLen )
+ continue; // line contains only white spaces
+
+ // Comment?
+ c = pBuf[i];
+ if( c == '#' || c == '!' )
+ continue;
+
+ // Scan key
+ OUString aResourceID;
+ bool bEscapePending = false;
+ bool bStrComplete = false;
+ while( i < nLen && !bStrComplete )
+ {
+ c = pBuf[i];
+ if( bEscapePending )
+ {
+ aBuf.append( getEscapeChar( pBuf, nLen, i ) );
+ bEscapePending = false;
+ }
+ else
+ {
+ if( c == '\\' )
+ {
+ bEscapePending = true;
+ }
+ else
+ {
+ if( c == ':' || c == '=' || isWhiteSpace( c ) )
+ bStrComplete = true;
+ else
+ aBuf.append( c );
+ }
+ }
+ i++;
+
+ CheckContinueInNextLine( xTextInputStream, aLine, bEscapePending, pBuf, nLen, i );
+ if( i == nLen )
+ bStrComplete = true;
+
+ if( bStrComplete )
+ aResourceID = aBuf.makeStringAndClear();
+ }
+
+ // Ignore lines with empty keys
+ if( aResourceID.isEmpty() )
+ continue;
+
+ // Scan value
+ skipWhites( pBuf, nLen, i );
+
+ OUString aValueStr;
+ bEscapePending = false;
+ bStrComplete = false;
+ while( i < nLen && !bStrComplete )
+ {
+ c = pBuf[i];
+ if( c == 0x000a || c == 0x000d ) // line feed/carriage return, not always handled by TextInputStream
+ {
+ i++;
+ }
+ else
+ {
+ if( bEscapePending )
+ {
+ aBuf.append( getEscapeChar( pBuf, nLen, i ) );
+ bEscapePending = false;
+ }
+ else if( c == '\\' )
+ bEscapePending = true;
+ else
+ aBuf.append( c );
+ i++;
+
+ CheckContinueInNextLine( xTextInputStream, aLine, bEscapePending, pBuf, nLen, i );
+ }
+ if( i == nLen )
+ bStrComplete = true;
+
+ if( bStrComplete )
+ aValueStr = aBuf.makeStringAndClear();
+ }
+
+ // Push into table
+ pLocaleItem->m_aIdToStringMap[ aResourceID ] = aValueStr;
+ implScanIdForNumber( aResourceID );
+ IdToIndexMap& rIndexMap = pLocaleItem->m_aIdToIndexMap;
+ rIndexMap[ aResourceID ] = pLocaleItem->m_nNextIndex++;
+ }
+
+ return true;
+}
+
+
+static sal_Unicode getHexCharForDigit( sal_uInt16 nDigitVal )
+{
+ sal_Unicode cRet = ( nDigitVal < 10 ) ? ('0' + nDigitVal) : ('a' + (nDigitVal-10));
+ return cRet;
+}
+
+static void implWriteCharToBuffer( OUStringBuffer& aBuf, sal_Unicode cu, bool bKey )
+{
+ if( cu == '\\' )
+ {
+ aBuf.append( '\\' );
+ aBuf.append( '\\' );
+ }
+ else if( cu == 0x000a )
+ {
+ aBuf.append( '\\' );
+ aBuf.append( 'n' );
+ }
+ else if( cu == 0x000d )
+ {
+ aBuf.append( '\\' );
+ aBuf.append( 'r' );
+ }
+ else if( bKey && cu == '=' )
+ {
+ aBuf.append( '\\' );
+ aBuf.append( '=' );
+ }
+ else if( bKey && cu == ':' )
+ {
+ aBuf.append( '\\' );
+ aBuf.append( ':' );
+ }
+ // ISO/IEC 8859-1 range according to:
+ // http://en.wikipedia.org/wiki/ISO/IEC_8859-1
+ else if( cu >= 0x20 && cu <= 0x7e )
+ //TODO: Check why (cu >= 0xa0 && cu <= 0xFF)
+ //is encoded in sample properties files
+ //else if( (cu >= 0x20 && cu <= 0x7e) ||
+ // (cu >= 0xa0 && cu <= 0xFF) )
+ {
+ aBuf.append( cu );
+ }
+ else
+ {
+ // Unicode encoding
+ aBuf.append( '\\' );
+ aBuf.append( 'u' );
+
+ sal_uInt16 nVal = cu;
+ for( sal_uInt16 i = 0 ; i < 4 ; i++ )
+ {
+ sal_uInt16 nDigit = nVal / 0x1000;
+ nVal -= nDigit * 0x1000;
+ nVal *= 0x10;
+ aBuf.append( getHexCharForDigit( nDigit ) );
+ }
+ }
+}
+
+static void implWriteStringWithEncoding( const OUString& aStr,
+ Reference< io::XTextOutputStream2 > const & xTextOutputStream, bool bKey )
+{
+ static const sal_Unicode cLineFeed = 0xa;
+
+ OUStringBuffer aBuf;
+ sal_Int32 nLen = aStr.getLength();
+ const sal_Unicode* pSrc = aStr.getStr();
+ for( sal_Int32 i = 0 ; i < nLen ; i++ )
+ {
+ sal_Unicode cu = pSrc[i];
+ implWriteCharToBuffer( aBuf, cu, bKey );
+ // TODO?: split long lines
+ }
+ if( !bKey )
+ aBuf.append( cLineFeed );
+
+ OUString aWriteStr = aBuf.makeStringAndClear();
+ xTextOutputStream->writeString( aWriteStr );
+}
+
+bool StringResourcePersistenceImpl::implWritePropertiesFile( LocaleItem const * pLocaleItem,
+ const Reference< io::XOutputStream >& xOutputStream, const OUString& aComment )
+{
+ if( !xOutputStream.is() || pLocaleItem == nullptr )
+ return false;
+
+ bool bSuccess = false;
+ Reference< io::XTextOutputStream2 > xTextOutputStream = io::TextOutputStream::create(m_xContext);
+
+ xTextOutputStream->setOutputStream( xOutputStream );
+
+ OUString aEncodingStr = OUString::createFromAscii
+ ( rtl_getMimeCharsetFromTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) );
+ xTextOutputStream->setEncoding( aEncodingStr );
+
+ xTextOutputStream->writeString( aComment );
+ xTextOutputStream->writeString( "\n" );
+
+ const IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap;
+ if( !rHashMap.empty() )
+ {
+ // Sort ids according to read order
+ const IdToIndexMap& rIndexMap = pLocaleItem->m_aIdToIndexMap;
+
+ // Find max/min index
+ auto itMinMax = std::minmax_element(rIndexMap.begin(), rIndexMap.end(),
+ [](const IdToIndexMap::value_type& a, const IdToIndexMap::value_type& b) { return a.second < b.second; });
+ sal_Int32 nMinIndex = itMinMax.first->second;
+ sal_Int32 nMaxIndex = itMinMax.second->second;
+ sal_Int32 nTabSize = nMaxIndex - nMinIndex + 1;
+
+ // Create sorted array of pointers to the id strings
+ std::unique_ptr<const OUString*[]> pIdPtrs( new const OUString*[nTabSize] );
+ for(sal_Int32 i = 0 ; i < nTabSize ; i++ )
+ pIdPtrs[i] = nullptr;
+ for( const auto& rIndex : rIndexMap )
+ {
+ sal_Int32 nIndex = rIndex.second;
+ pIdPtrs[nIndex - nMinIndex] = &(rIndex.first);
+ }
+
+ // Write lines in correct order
+ for(sal_Int32 i = 0 ; i < nTabSize ; i++ )
+ {
+ const OUString* pStr = pIdPtrs[i];
+ if( pStr != nullptr )
+ {
+ OUString aResourceID = *pStr;
+ IdToStringMap::const_iterator it = rHashMap.find( aResourceID );
+ if( it != rHashMap.end() )
+ {
+ implWriteStringWithEncoding( aResourceID, xTextOutputStream, true );
+ xTextOutputStream->writeString( "=" );
+ OUString aValStr = (*it).second;
+ implWriteStringWithEncoding( aValStr, xTextOutputStream, false );
+ }
+ }
+ }
+ }
+
+ bSuccess = true;
+
+ return bSuccess;
+}
+
+
+// StringResourceWithStorageImpl
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scripting_StringResourceWithStorageImpl_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new StringResourceWithStorageImpl(context));
+}
+
+
+StringResourceWithStorageImpl::StringResourceWithStorageImpl( const Reference< XComponentContext >& rxContext )
+ : StringResourceWithStorageImpl_BASE( rxContext )
+ , m_bStorageChanged( false )
+{
+}
+
+
+StringResourceWithStorageImpl::~StringResourceWithStorageImpl()
+{
+}
+
+
+// XServiceInfo
+
+
+OUString StringResourceWithStorageImpl::getImplementationName( )
+{
+ return "com.sun.star.comp.scripting.StringResourceWithStorage";
+}
+
+sal_Bool StringResourceWithStorageImpl::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence< OUString > StringResourceWithStorageImpl::getSupportedServiceNames( )
+{
+ return { "com.sun.star.resource.StringResourceWithStorage" };
+}
+
+
+// XInitialization
+
+
+void StringResourceWithStorageImpl::initialize( const Sequence< Any >& aArguments )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( aArguments.getLength() != 5 )
+ {
+ throw RuntimeException(
+ "StringResourceWithStorageImpl::initialize: invalid number of arguments!" );
+ }
+
+ bool bOk = (aArguments[0] >>= m_xStorage);
+ if( bOk && !m_xStorage.is() )
+ bOk = false;
+
+ if( !bOk )
+ {
+ throw IllegalArgumentException( "StringResourceWithStorageImpl::initialize: invalid storage", Reference< XInterface >(), 0 );
+ }
+
+ implInitializeCommonParameters( aGuard, aArguments );
+}
+
+
+// Forwarding calls to base class
+
+// XModifyBroadcaster
+void StringResourceWithStorageImpl::addModifyListener( const Reference< XModifyListener >& aListener )
+{
+ StringResourceImpl::addModifyListener( aListener );
+}
+void StringResourceWithStorageImpl::removeModifyListener( const Reference< XModifyListener >& aListener )
+{
+ StringResourceImpl::removeModifyListener( aListener );
+}
+
+// XStringResourceResolver
+OUString StringResourceWithStorageImpl::resolveString( const OUString& ResourceID )
+{
+ return StringResourceImpl::resolveString( ResourceID ) ;
+}
+OUString StringResourceWithStorageImpl::resolveStringForLocale( const OUString& ResourceID, const Locale& locale )
+{
+ return StringResourceImpl::resolveStringForLocale( ResourceID, locale );
+}
+sal_Bool StringResourceWithStorageImpl::hasEntryForId( const OUString& ResourceID )
+{
+ return StringResourceImpl::hasEntryForId( ResourceID ) ;
+}
+sal_Bool StringResourceWithStorageImpl::hasEntryForIdAndLocale( const OUString& ResourceID,
+ const Locale& locale )
+{
+ return StringResourceImpl::hasEntryForIdAndLocale( ResourceID, locale );
+}
+Sequence< OUString > StringResourceWithStorageImpl::getResourceIDs( )
+{
+ return StringResourceImpl::getResourceIDs();
+}
+Sequence< OUString > StringResourceWithStorageImpl::getResourceIDsForLocale
+ ( const Locale& locale )
+{
+ return StringResourceImpl::getResourceIDsForLocale( locale );
+}
+Locale StringResourceWithStorageImpl::getCurrentLocale()
+{
+ return StringResourceImpl::getCurrentLocale();
+}
+Locale StringResourceWithStorageImpl::getDefaultLocale( )
+{
+ return StringResourceImpl::getDefaultLocale();
+}
+Sequence< Locale > StringResourceWithStorageImpl::getLocales( )
+{
+ return StringResourceImpl::getLocales();
+}
+
+// XStringResourceManager
+sal_Bool StringResourceWithStorageImpl::isReadOnly()
+{
+ return StringResourceImpl::isReadOnly();
+}
+void StringResourceWithStorageImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch )
+{
+ StringResourceImpl::setCurrentLocale( locale, FindClosestMatch );
+}
+void StringResourceWithStorageImpl::setDefaultLocale( const Locale& locale )
+{
+ StringResourceImpl::setDefaultLocale( locale );
+}
+void StringResourceWithStorageImpl::setString( const OUString& ResourceID, const OUString& Str )
+{
+ StringResourceImpl::setString( ResourceID, Str );
+}
+void StringResourceWithStorageImpl::setStringForLocale
+ ( const OUString& ResourceID, const OUString& Str, const Locale& locale )
+{
+ StringResourceImpl::setStringForLocale( ResourceID, Str, locale );
+}
+void StringResourceWithStorageImpl::removeId( const OUString& ResourceID )
+{
+ StringResourceImpl::removeId( ResourceID );
+}
+void StringResourceWithStorageImpl::removeIdForLocale( const OUString& ResourceID, const Locale& locale )
+{
+ StringResourceImpl::removeIdForLocale( ResourceID, locale );
+}
+void StringResourceWithStorageImpl::newLocale( const Locale& locale )
+{
+ StringResourceImpl::newLocale( locale );
+}
+void StringResourceWithStorageImpl::removeLocale( const Locale& locale )
+{
+ StringResourceImpl::removeLocale( locale );
+}
+sal_Int32 StringResourceWithStorageImpl::getUniqueNumericId( )
+{
+ return StringResourceImpl::getUniqueNumericId();
+}
+
+// XStringResourcePersistence
+void StringResourceWithStorageImpl::store()
+{
+ std::unique_lock aGuard( m_aMutex );
+ implCheckReadOnly( "StringResourceWithStorageImpl::store(): Read only" );
+
+ bool bStoreAll = m_bStorageChanged;
+ m_bStorageChanged = false;
+ if( !m_bModified && !bStoreAll )
+ return;
+
+ implStoreAtStorage( m_aNameBase, m_aComment, m_xStorage, true/*bUsedForStore*/, bStoreAll );
+ m_bModified = false;
+}
+
+sal_Bool StringResourceWithStorageImpl::isModified( )
+{
+ return StringResourcePersistenceImpl::isModified();
+}
+void StringResourceWithStorageImpl::setComment( const OUString& Comment )
+{
+ StringResourcePersistenceImpl::setComment( Comment );
+}
+void StringResourceWithStorageImpl::storeToStorage( const Reference< XStorage >& Storage,
+ const OUString& NameBase, const OUString& Comment )
+{
+ StringResourcePersistenceImpl::storeToStorage( Storage, NameBase, Comment );
+}
+void StringResourceWithStorageImpl::storeToURL( const OUString& URL,
+ const OUString& NameBase, const OUString& Comment,
+ const Reference< css::task::XInteractionHandler >& Handler )
+{
+ StringResourcePersistenceImpl::storeToURL( URL, NameBase, Comment, Handler );
+}
+Sequence< ::sal_Int8 > StringResourceWithStorageImpl::exportBinary( )
+{
+ return StringResourcePersistenceImpl::exportBinary();
+}
+void StringResourceWithStorageImpl::importBinary( const Sequence< ::sal_Int8 >& Data )
+{
+ StringResourcePersistenceImpl::importBinary( Data );
+}
+
+
+// XStringResourceWithStorage
+
+void StringResourceWithStorageImpl::storeAsStorage( const Reference< XStorage >& Storage )
+{
+ setStorage( Storage );
+ store();
+}
+
+void StringResourceWithStorageImpl::setStorage( const Reference< XStorage >& Storage )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !Storage.is() )
+ {
+ throw IllegalArgumentException( "StringResourceWithStorageImpl::setStorage: invalid storage", Reference< XInterface >(), 0 );
+ }
+
+ implLoadAllLocales();
+
+ m_xStorage = Storage;
+ m_bStorageChanged = true;
+}
+
+
+// Private helper methods
+
+
+// Scan locale properties files
+void StringResourceWithStorageImpl::implScanLocales()
+{
+ if( m_xStorage.is() )
+ {
+ Sequence< OUString > aContentSeq = m_xStorage->getElementNames();
+ implScanLocaleNames( aContentSeq );
+ }
+
+ implLoadAllLocales();
+}
+
+// Loading
+bool StringResourceWithStorageImpl::implLoadLocale( LocaleItem* pLocaleItem )
+{
+ bool bSuccess = false;
+ try
+ {
+ OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem, m_aNameBase ) + ".properties";
+
+ Reference< io::XStream > xElementStream =
+ m_xStorage->openStreamElement( aStreamName, ElementModes::READ );
+
+ if( xElementStream.is() )
+ {
+ Reference< io::XInputStream > xInputStream = xElementStream->getInputStream();
+ if( xInputStream.is() )
+ {
+ bSuccess = StringResourcePersistenceImpl::implReadPropertiesFile( pLocaleItem, xInputStream );
+ xInputStream->closeInput();
+ }
+ }
+ }
+ catch( uno::Exception& )
+ {}
+
+ return bSuccess;
+}
+
+
+// StringResourceWithLocationImpl
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scripting_StringResourceWithLocationImpl_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new StringResourceWithLocationImpl(context));
+}
+
+
+
+StringResourceWithLocationImpl::StringResourceWithLocationImpl( const Reference< XComponentContext >& rxContext )
+ : StringResourceWithLocationImpl_BASE( rxContext )
+ , m_bLocationChanged( false )
+{
+}
+
+
+StringResourceWithLocationImpl::~StringResourceWithLocationImpl()
+{
+}
+
+
+// XServiceInfo
+
+
+OUString StringResourceWithLocationImpl::getImplementationName( )
+{
+ return "com.sun.star.comp.scripting.StringResourceWithLocation";
+}
+
+sal_Bool StringResourceWithLocationImpl::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence< OUString > StringResourceWithLocationImpl::getSupportedServiceNames( )
+{
+ return { "com.sun.star.resource.StringResourceWithLocation" };
+}
+
+
+// XInitialization
+
+
+void StringResourceWithLocationImpl::initialize( const Sequence< Any >& aArguments )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( aArguments.getLength() != 6 )
+ {
+ throw RuntimeException(
+ "XInitialization::initialize: invalid number of arguments!" );
+ }
+
+ bool bOk = (aArguments[0] >>= m_aLocation);
+ sal_Int32 nLen = m_aLocation.getLength();
+ if( bOk && nLen == 0 )
+ {
+ bOk = false;
+ }
+ else
+ {
+ if( m_aLocation[nLen - 1] != '/' )
+ m_aLocation += "/";
+ }
+
+ if( !bOk )
+ {
+ throw IllegalArgumentException( "XInitialization::initialize: invalid URL", Reference< XInterface >(), 0 );
+ }
+
+
+ bOk = (aArguments[5] >>= m_xInteractionHandler);
+ if( !bOk )
+ {
+ throw IllegalArgumentException( "StringResourceWithStorageImpl::initialize: invalid type", Reference< XInterface >(), 5 );
+ }
+
+ implInitializeCommonParameters( aGuard, aArguments );
+}
+
+
+// Forwarding calls to base class
+
+// XModifyBroadcaster
+void StringResourceWithLocationImpl::addModifyListener( const Reference< XModifyListener >& aListener )
+{
+ StringResourceImpl::addModifyListener( aListener );
+}
+void StringResourceWithLocationImpl::removeModifyListener( const Reference< XModifyListener >& aListener )
+{
+ StringResourceImpl::removeModifyListener( aListener );
+}
+
+// XStringResourceResolver
+OUString StringResourceWithLocationImpl::resolveString( const OUString& ResourceID )
+{
+ return StringResourceImpl::resolveString( ResourceID ) ;
+}
+OUString StringResourceWithLocationImpl::resolveStringForLocale( const OUString& ResourceID, const Locale& locale )
+{
+ return StringResourceImpl::resolveStringForLocale( ResourceID, locale );
+}
+sal_Bool StringResourceWithLocationImpl::hasEntryForId( const OUString& ResourceID )
+{
+ return StringResourceImpl::hasEntryForId( ResourceID ) ;
+}
+sal_Bool StringResourceWithLocationImpl::hasEntryForIdAndLocale( const OUString& ResourceID,
+ const Locale& locale )
+{
+ return StringResourceImpl::hasEntryForIdAndLocale( ResourceID, locale );
+}
+Sequence< OUString > StringResourceWithLocationImpl::getResourceIDs( )
+{
+ return StringResourceImpl::getResourceIDs();
+}
+Sequence< OUString > StringResourceWithLocationImpl::getResourceIDsForLocale
+ ( const Locale& locale )
+{
+ return StringResourceImpl::getResourceIDsForLocale( locale );
+}
+Locale StringResourceWithLocationImpl::getCurrentLocale()
+{
+ return StringResourceImpl::getCurrentLocale();
+}
+Locale StringResourceWithLocationImpl::getDefaultLocale( )
+{
+ return StringResourceImpl::getDefaultLocale();
+}
+Sequence< Locale > StringResourceWithLocationImpl::getLocales( )
+{
+ return StringResourceImpl::getLocales();
+}
+
+// XStringResourceManager
+sal_Bool StringResourceWithLocationImpl::isReadOnly()
+{
+ return StringResourceImpl::isReadOnly();
+}
+void StringResourceWithLocationImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch )
+{
+ StringResourceImpl::setCurrentLocale( locale, FindClosestMatch );
+}
+void StringResourceWithLocationImpl::setDefaultLocale( const Locale& locale )
+{
+ StringResourceImpl::setDefaultLocale( locale );
+}
+void StringResourceWithLocationImpl::setString( const OUString& ResourceID, const OUString& Str )
+{
+ StringResourceImpl::setString( ResourceID, Str );
+}
+void StringResourceWithLocationImpl::setStringForLocale
+ ( const OUString& ResourceID, const OUString& Str, const Locale& locale )
+{
+ StringResourceImpl::setStringForLocale( ResourceID, Str, locale );
+}
+void StringResourceWithLocationImpl::removeId( const OUString& ResourceID )
+{
+ StringResourceImpl::removeId( ResourceID );
+}
+void StringResourceWithLocationImpl::removeIdForLocale( const OUString& ResourceID, const Locale& locale )
+{
+ StringResourceImpl::removeIdForLocale( ResourceID, locale );
+}
+void StringResourceWithLocationImpl::newLocale( const Locale& locale )
+{
+ StringResourceImpl::newLocale( locale );
+}
+void StringResourceWithLocationImpl::removeLocale( const Locale& locale )
+{
+ StringResourceImpl::removeLocale( locale );
+}
+sal_Int32 StringResourceWithLocationImpl::getUniqueNumericId( )
+{
+ return StringResourceImpl::getUniqueNumericId();
+}
+
+// XStringResourcePersistence
+void StringResourceWithLocationImpl::store()
+{
+ std::unique_lock aGuard( m_aMutex );
+ implCheckReadOnly( "StringResourceWithLocationImpl::store(): Read only" );
+
+ bool bStoreAll = m_bLocationChanged;
+ m_bLocationChanged = false;
+ if( !m_bModified && !bStoreAll )
+ return;
+
+ Reference< ucb::XSimpleFileAccess3 > xFileAccess = getFileAccessImpl();
+ implStoreAtLocation( m_aLocation, m_aNameBase, m_aComment,
+ xFileAccess, true/*bUsedForStore*/, bStoreAll );
+ m_bModified = false;
+}
+
+sal_Bool StringResourceWithLocationImpl::isModified( )
+{
+ return StringResourcePersistenceImpl::isModified();
+}
+void StringResourceWithLocationImpl::setComment( const OUString& Comment )
+{
+ StringResourcePersistenceImpl::setComment( Comment );
+}
+void StringResourceWithLocationImpl::storeToStorage( const Reference< XStorage >& Storage,
+ const OUString& NameBase, const OUString& Comment )
+{
+ StringResourcePersistenceImpl::storeToStorage( Storage, NameBase, Comment );
+}
+void StringResourceWithLocationImpl::storeToURL( const OUString& URL,
+ const OUString& NameBase, const OUString& Comment,
+ const Reference< css::task::XInteractionHandler >& Handler )
+{
+ StringResourcePersistenceImpl::storeToURL( URL, NameBase, Comment, Handler );
+}
+Sequence< ::sal_Int8 > StringResourceWithLocationImpl::exportBinary( )
+{
+ return StringResourcePersistenceImpl::exportBinary();
+}
+void StringResourceWithLocationImpl::importBinary( const Sequence< ::sal_Int8 >& Data )
+{
+ StringResourcePersistenceImpl::importBinary( Data );
+}
+
+
+// XStringResourceWithLocation
+
+// XStringResourceWithLocation
+void StringResourceWithLocationImpl::storeAsURL( const OUString& URL )
+{
+ setURL( URL );
+ store();
+}
+
+void StringResourceWithLocationImpl::setURL( const OUString& URL )
+{
+ std::unique_lock aGuard( m_aMutex );
+ implCheckReadOnly( "StringResourceWithLocationImpl::setURL(): Read only" );
+
+ sal_Int32 nLen = URL.getLength();
+ if( nLen == 0 )
+ {
+ throw IllegalArgumentException( "StringResourceWithLocationImpl::setURL: invalid URL", Reference< XInterface >(), 0 );
+ }
+
+ implLoadAllLocales();
+
+ // Delete files at old location
+ implStoreAtLocation( m_aLocation, m_aNameBase, m_aComment,
+ getFileAccessImpl(), false/*bUsedForStore*/, false/*bStoreAll*/, true/*bKillAll*/ );
+
+ m_aLocation = URL;
+ m_bLocationChanged = true;
+}
+
+
+// Private helper methods
+
+
+// Scan locale properties files
+void StringResourceWithLocationImpl::implScanLocales()
+{
+ const Reference< ucb::XSimpleFileAccess3 > xFileAccess = getFileAccessImpl();
+ if( xFileAccess.is() && xFileAccess->isFolder( m_aLocation ) )
+ {
+ Sequence< OUString > aContentSeq = xFileAccess->getFolderContents( m_aLocation, false );
+ implScanLocaleNames( aContentSeq );
+ }
+}
+
+// Loading
+bool StringResourceWithLocationImpl::implLoadLocale( LocaleItem* pLocaleItem )
+{
+ bool bSuccess = false;
+
+ const Reference< ucb::XSimpleFileAccess3 > xFileAccess = getFileAccessImpl();
+ if( xFileAccess.is() )
+ {
+ OUString aCompleteFileName =
+ implGetPathForLocaleItem( pLocaleItem, m_aNameBase, m_aLocation );
+
+ Reference< io::XInputStream > xInputStream;
+ try
+ {
+ xInputStream = xFileAccess->openFileRead( aCompleteFileName );
+ }
+ catch( Exception& )
+ {}
+ if( xInputStream.is() )
+ {
+ bSuccess = StringResourcePersistenceImpl::implReadPropertiesFile( pLocaleItem, xInputStream );
+ xInputStream->closeInput();
+ }
+ }
+
+ return bSuccess;
+}
+
+const Reference< ucb::XSimpleFileAccess3 > & StringResourceWithLocationImpl::getFileAccessImpl()
+{
+ if( !m_xSFI.is() )
+ {
+ m_xSFI = ucb::SimpleFileAccess::create(m_xContext);
+
+ if( m_xSFI.is() && m_xInteractionHandler.is() )
+ m_xSFI->setInteractionHandler( m_xInteractionHandler );
+ }
+ return m_xSFI;
+}
+
+} // namespace stringresource
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/stringresource/stringresource.hxx b/scripting/source/stringresource/stringresource.hxx
new file mode 100644
index 000000000..7722da62f
--- /dev/null
+++ b/scripting/source/stringresource/stringresource.hxx
@@ -0,0 +1,485 @@
+/* -*- 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/resource/XStringResourceWithStorage.hpp>
+#include <com/sun/star/resource/XStringResourceWithLocation.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/interfacecontainer4.hxx>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+
+namespace stringresource
+{
+
+
+// class stringresourceImpl
+
+
+// Hashtable to map string ids to string
+typedef std::unordered_map
+<
+ OUString,
+ OUString
+>
+IdToStringMap;
+
+typedef std::unordered_map
+<
+ OUString,
+ sal_Int32
+>
+IdToIndexMap;
+
+
+struct LocaleItem
+{
+ css::lang::Locale m_locale;
+ IdToStringMap m_aIdToStringMap;
+ IdToIndexMap m_aIdToIndexMap;
+ sal_Int32 m_nNextIndex;
+ bool m_bLoaded;
+ bool m_bModified;
+
+ LocaleItem( css::lang::Locale locale, bool bLoaded=true )
+ : m_locale( locale )
+ , m_nNextIndex( 0 )
+ , m_bLoaded( bLoaded )
+ , m_bModified( false )
+ {}
+};
+
+typedef ::cppu::WeakImplHelper<
+ css::lang::XServiceInfo,
+ css::resource::XStringResourceManager > StringResourceImpl_BASE;
+
+class StringResourceImpl : public StringResourceImpl_BASE
+{
+protected:
+ std::mutex m_aMutex;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ LocaleItem* m_pCurrentLocaleItem;
+ LocaleItem* m_pDefaultLocaleItem;
+ bool m_bDefaultModified;
+
+ ::comphelper::OInterfaceContainerHelper4<css::util::XModifyListener> m_aListenerContainer;
+
+ std::vector< std::unique_ptr<LocaleItem> > m_aLocaleItemVector;
+ std::vector< std::unique_ptr<LocaleItem> > m_aDeletedLocaleItemVector;
+ std::vector< std::unique_ptr<LocaleItem> > m_aChangedDefaultLocaleVector;
+
+ bool m_bModified;
+ bool m_bReadOnly;
+
+ sal_Int32 m_nNextUniqueNumericId;
+
+ // Scans ResourceID to start with number and adapt m_nNextUniqueNumericId
+ void implScanIdForNumber( const OUString& ResourceID );
+ const static sal_Int32 UNIQUE_NUMBER_NEEDS_INITIALISATION = -1;
+
+ // Checks read only status and throws exception if it's true
+ /// @throws css::lang::NoSupportException
+ void implCheckReadOnly( const char* pExceptionMsg );
+
+ // Returns the LocalItem for a given locale, if it exists, otherwise NULL
+ // This method compares the locales exactly, no closest match search is performed
+ /// @throws css::lang::IllegalArgumentException
+ LocaleItem* getItemForLocale( const css::lang::Locale& locale, bool bException );
+
+ // Returns the LocalItem for a given locale, if it exists, otherwise NULL
+ // This method performs a closest match search, at least the language must match
+ LocaleItem* getClosestMatchItemForLocale( const css::lang::Locale& locale );
+ /// @throws css::lang::IllegalArgumentException
+ /// @throws css::uno::RuntimeException
+ void implSetCurrentLocale( std::unique_lock<std::mutex>& rGuard, const css::lang::Locale& locale,
+ bool FindClosestMatch, bool bUseDefaultIfNoMatch );
+
+ void implModified(std::unique_lock<std::mutex>&);
+ void implNotifyListeners(std::unique_lock<std::mutex>&);
+
+ //=== Impl methods for ...ForLocale methods ===
+ /// @throws css::resource::MissingResourceException
+ OUString implResolveString( const OUString& ResourceID, LocaleItem* pLocaleItem );
+ bool implHasEntryForId( const OUString& ResourceID, LocaleItem* pLocaleItem );
+ css::uno::Sequence< OUString > implGetResourceIDs( LocaleItem* pLocaleItem );
+ void implSetString( std::unique_lock<std::mutex>& rGuard, const OUString& ResourceID,
+ const OUString& Str, LocaleItem* pLocaleItem );
+ /// @throws css::resource::MissingResourceException
+ void implRemoveId( std::unique_lock<std::mutex>& rGuard, const OUString& ResourceID, LocaleItem* pLocaleItem );
+
+ // Method to load a locale if necessary, returns true if loading was
+ // successful. Default implementation in base class just returns true.
+ virtual bool loadLocale( LocaleItem* pLocaleItem );
+
+ virtual void implLoadAllLocales();
+
+public:
+ explicit StringResourceImpl(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+ virtual ~StringResourceImpl() 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;
+
+ // XModifyBroadcaster
+ virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+ virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+
+ // XStringResourceResolver
+ virtual OUString SAL_CALL resolveString( const OUString& ResourceID ) override;
+ virtual OUString SAL_CALL resolveStringForLocale( const OUString& ResourceID,
+ const css::lang::Locale& locale ) override;
+ virtual sal_Bool SAL_CALL hasEntryForId( const OUString& ResourceID ) override;
+ virtual sal_Bool SAL_CALL hasEntryForIdAndLocale( const OUString& ResourceID,
+ const css::lang::Locale& locale ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDs( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDsForLocale
+ ( const css::lang::Locale& locale ) override;
+ virtual css::lang::Locale SAL_CALL getCurrentLocale( ) override;
+ virtual css::lang::Locale SAL_CALL getDefaultLocale( ) override;
+ virtual css::uno::Sequence< css::lang::Locale > SAL_CALL getLocales( ) override;
+
+ // XStringResourceManager
+ virtual sal_Bool SAL_CALL isReadOnly() override;
+ virtual void SAL_CALL setCurrentLocale( const css::lang::Locale& locale, sal_Bool FindClosestMatch ) override;
+ virtual void SAL_CALL setDefaultLocale( const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL setString( const OUString& ResourceID, const OUString& Str ) override;
+ virtual void SAL_CALL setStringForLocale( const OUString& ResourceID, const OUString& Str,
+ const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL removeId( const OUString& ResourceID ) override;
+ virtual void SAL_CALL removeIdForLocale( const OUString& ResourceID,
+ const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL newLocale( const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL removeLocale( const css::lang::Locale& locale ) override;
+ virtual ::sal_Int32 SAL_CALL getUniqueNumericId( ) override;
+ };
+
+typedef ::cppu::ImplInheritanceHelper<
+ StringResourceImpl,
+ css::resource::XStringResourcePersistence > StringResourcePersistenceImpl_BASE;
+
+class BinaryOutput;
+
+class StringResourcePersistenceImpl : public StringResourcePersistenceImpl_BASE
+{
+protected:
+ OUString m_aNameBase;
+ OUString m_aComment;
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ void implInitializeCommonParameters( std::unique_lock<std::mutex>& rGuard, const css::uno::Sequence< css::uno::Any >& aArguments );
+
+ // Scan locale properties files
+ virtual void implScanLocales();
+
+ // Method to load a locale if necessary, returns true if loading was successful
+ virtual bool loadLocale( LocaleItem* pLocaleItem ) override;
+
+ // does the actual loading
+ virtual bool implLoadLocale( LocaleItem* pLocaleItem );
+
+ virtual void implLoadAllLocales() override;
+
+ void implScanLocaleNames( const css::uno::Sequence< OUString >& aContentSeq );
+ static OUString implGetFileNameForLocaleItem( LocaleItem const * pLocaleItem, const OUString& aNameBase );
+ static OUString implGetPathForLocaleItem( LocaleItem const * pLocaleItem, const OUString& aNameBase,
+ std::u16string_view aLocation, bool bDefaultFile=false );
+
+ bool implReadPropertiesFile( LocaleItem* pLocaleItem,
+ const css::uno::Reference< css::io::XInputStream >& xInput );
+
+ bool implWritePropertiesFile( LocaleItem const * pLocaleItem,
+ const css::uno::Reference< css::io::XOutputStream >& xOutputStream,
+ const OUString& aComment );
+
+ void implWriteLocaleBinary( LocaleItem* pLocaleItem, BinaryOutput& rOut );
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ void implStoreAtStorage
+ (
+ const OUString& aNameBase,
+ const OUString& aComment,
+ const css::uno::Reference< css::embed::XStorage >& Storage,
+ bool bUsedForStore,
+ bool bStoreAll
+ );
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ void implKillRemovedLocaleFiles
+ (
+ std::u16string_view Location,
+ const OUString& aNameBase,
+ const css::uno::Reference< css::ucb::XSimpleFileAccess3 >& xFileAccess
+ );
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ void implKillChangedDefaultFiles
+ (
+ std::u16string_view Location,
+ const OUString& aNameBase,
+ const css::uno::Reference< css::ucb::XSimpleFileAccess3 >& xFileAccess
+ );
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ void implStoreAtLocation
+ (
+ std::u16string_view Location,
+ const OUString& aNameBase,
+ const OUString& aComment,
+ const css::uno::Reference< css::ucb::XSimpleFileAccess3 >& xFileAccess,
+ bool bUsedForStore,
+ bool bStoreAll,
+ bool bKillAll = false
+ );
+
+public:
+ explicit StringResourcePersistenceImpl(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+ virtual ~StringResourcePersistenceImpl() 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;
+
+ // XModifyBroadcaster
+ virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+ virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+
+ // XStringResourceResolver
+ virtual OUString SAL_CALL resolveString( const OUString& ResourceID ) override;
+ virtual OUString SAL_CALL resolveStringForLocale( const OUString& ResourceID,
+ const css::lang::Locale& locale ) override;
+ virtual sal_Bool SAL_CALL hasEntryForId( const OUString& ResourceID ) override;
+ virtual sal_Bool SAL_CALL hasEntryForIdAndLocale( const OUString& ResourceID,
+ const css::lang::Locale& locale ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDs( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDsForLocale
+ ( const css::lang::Locale& locale ) override;
+ virtual css::lang::Locale SAL_CALL getCurrentLocale( ) override;
+ virtual css::lang::Locale SAL_CALL getDefaultLocale( ) override;
+ virtual css::uno::Sequence< css::lang::Locale > SAL_CALL getLocales( ) override;
+
+ // XStringResourceManager
+ virtual sal_Bool SAL_CALL isReadOnly() override;
+ virtual void SAL_CALL setCurrentLocale( const css::lang::Locale& locale, sal_Bool FindClosestMatch ) override;
+ virtual void SAL_CALL setDefaultLocale( const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL setString( const OUString& ResourceID, const OUString& Str ) override;
+ virtual void SAL_CALL setStringForLocale( const OUString& ResourceID, const OUString& Str,
+ const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL removeId( const OUString& ResourceID ) override;
+ virtual void SAL_CALL removeIdForLocale( const OUString& ResourceID,
+ const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL newLocale( const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL removeLocale( const css::lang::Locale& locale ) override;
+ virtual ::sal_Int32 SAL_CALL getUniqueNumericId( ) override;
+
+ // XStringResourcePersistence
+ virtual void SAL_CALL store( ) override;
+ virtual sal_Bool SAL_CALL isModified( ) override;
+ virtual void SAL_CALL setComment( const OUString& Comment ) override;
+ virtual void SAL_CALL storeToStorage
+ ( const css::uno::Reference< css::embed::XStorage >& Storage,
+ const OUString& NameBase, const OUString& Comment ) override;
+ virtual void SAL_CALL storeToURL( const OUString& URL, const OUString& NameBase,
+ const OUString& Comment, const css::uno::Reference
+ < css::task::XInteractionHandler >& Handler ) override;
+ virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL exportBinary( ) override;
+ virtual void SAL_CALL importBinary( const css::uno::Sequence< ::sal_Int8 >& Data ) override;
+};
+
+
+typedef ::cppu::ImplInheritanceHelper<
+ StringResourcePersistenceImpl,
+ css::lang::XInitialization,
+ css::resource::XStringResourceWithStorage > StringResourceWithStorageImpl_BASE;
+
+class StringResourceWithStorageImpl : public StringResourceWithStorageImpl_BASE
+{
+ css::uno::Reference< css::embed::XStorage > m_xStorage;
+ bool m_bStorageChanged;
+
+ virtual void implScanLocales() override;
+ virtual bool implLoadLocale( LocaleItem* pLocaleItem ) override;
+
+public:
+ explicit StringResourceWithStorageImpl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+ virtual ~StringResourceWithStorageImpl() 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;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XModifyBroadcaster
+ virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+ virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+
+ // XStringResourceResolver
+ virtual OUString SAL_CALL resolveString( const OUString& ResourceID ) override;
+ virtual OUString SAL_CALL resolveStringForLocale( const OUString& ResourceID,
+ const css::lang::Locale& locale ) override;
+ virtual sal_Bool SAL_CALL hasEntryForId( const OUString& ResourceID ) override;
+ virtual sal_Bool SAL_CALL hasEntryForIdAndLocale( const OUString& ResourceID,
+ const css::lang::Locale& locale ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDs( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDsForLocale
+ ( const css::lang::Locale& locale ) override;
+ virtual css::lang::Locale SAL_CALL getCurrentLocale( ) override;
+ virtual css::lang::Locale SAL_CALL getDefaultLocale( ) override;
+ virtual css::uno::Sequence< css::lang::Locale > SAL_CALL getLocales( ) override;
+
+ // XStringResourceManager
+ virtual sal_Bool SAL_CALL isReadOnly() override;
+ virtual void SAL_CALL setCurrentLocale( const css::lang::Locale& locale, sal_Bool FindClosestMatch ) override;
+ virtual void SAL_CALL setDefaultLocale( const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL setString( const OUString& ResourceID, const OUString& Str ) override;
+ virtual void SAL_CALL setStringForLocale( const OUString& ResourceID, const OUString& Str,
+ const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL removeId( const OUString& ResourceID ) override;
+ virtual void SAL_CALL removeIdForLocale( const OUString& ResourceID,
+ const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL newLocale( const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL removeLocale( const css::lang::Locale& locale ) override;
+ virtual ::sal_Int32 SAL_CALL getUniqueNumericId( ) override;
+
+ // XStringResourcePersistence
+ virtual void SAL_CALL store( ) override;
+ virtual sal_Bool SAL_CALL isModified( ) override;
+ virtual void SAL_CALL setComment( const OUString& Comment ) override;
+ virtual void SAL_CALL storeToStorage
+ ( const css::uno::Reference< css::embed::XStorage >& Storage,
+ const OUString& NameBase, const OUString& Comment ) override;
+ virtual void SAL_CALL storeToURL( const OUString& URL, const OUString& NameBase,
+ const OUString& Comment, const css::uno::Reference
+ < css::task::XInteractionHandler >& Handler ) override;
+ virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL exportBinary( ) override;
+ virtual void SAL_CALL importBinary( const css::uno::Sequence< ::sal_Int8 >& Data ) override;
+
+ // XStringResourceWithStorage
+ virtual void SAL_CALL storeAsStorage
+ ( const css::uno::Reference< css::embed::XStorage >& Storage ) override;
+ virtual void SAL_CALL setStorage
+ ( const css::uno::Reference< css::embed::XStorage >& Storage ) override;
+};
+
+
+typedef ::cppu::ImplInheritanceHelper<
+ StringResourcePersistenceImpl,
+ css::lang::XInitialization,
+ css::resource::XStringResourceWithLocation > StringResourceWithLocationImpl_BASE;
+
+class StringResourceWithLocationImpl : public StringResourceWithLocationImpl_BASE
+{
+ OUString m_aLocation;
+ bool m_bLocationChanged;
+ css::uno::Reference< css::ucb::XSimpleFileAccess3 > m_xSFI;
+ css::uno::Reference< css::task::XInteractionHandler > m_xInteractionHandler;
+
+ const css::uno::Reference< css::ucb::XSimpleFileAccess3 > & getFileAccessImpl();
+
+ virtual void implScanLocales() override;
+ virtual bool implLoadLocale( LocaleItem* pLocaleItem ) override;
+
+public:
+ explicit StringResourceWithLocationImpl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+ virtual ~StringResourceWithLocationImpl() 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;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XModifyBroadcaster
+ virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+ virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+
+ // XStringResourceResolver
+ virtual OUString SAL_CALL resolveString( const OUString& ResourceID ) override;
+ virtual OUString SAL_CALL resolveStringForLocale( const OUString& ResourceID,
+ const css::lang::Locale& locale ) override;
+ virtual sal_Bool SAL_CALL hasEntryForId( const OUString& ResourceID ) override;
+ virtual sal_Bool SAL_CALL hasEntryForIdAndLocale( const OUString& ResourceID,
+ const css::lang::Locale& locale ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDs( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDsForLocale
+ ( const css::lang::Locale& locale ) override;
+ virtual css::lang::Locale SAL_CALL getCurrentLocale( ) override;
+ virtual css::lang::Locale SAL_CALL getDefaultLocale( ) override;
+ virtual css::uno::Sequence< css::lang::Locale > SAL_CALL getLocales( ) override;
+
+ // XStringResourceManager
+ virtual sal_Bool SAL_CALL isReadOnly() override;
+ virtual void SAL_CALL setCurrentLocale( const css::lang::Locale& locale, sal_Bool FindClosestMatch ) override;
+ virtual void SAL_CALL setDefaultLocale( const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL setString( const OUString& ResourceID, const OUString& Str ) override;
+ virtual void SAL_CALL setStringForLocale( const OUString& ResourceID, const OUString& Str,
+ const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL removeId( const OUString& ResourceID ) override;
+ virtual void SAL_CALL removeIdForLocale( const OUString& ResourceID,
+ const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL newLocale( const css::lang::Locale& locale ) override;
+ virtual void SAL_CALL removeLocale( const css::lang::Locale& locale ) override;
+ virtual ::sal_Int32 SAL_CALL getUniqueNumericId( ) override;
+
+ // XStringResourcePersistence
+ virtual void SAL_CALL store( ) override;
+ virtual sal_Bool SAL_CALL isModified( ) override;
+ virtual void SAL_CALL setComment( const OUString& Comment ) override;
+ virtual void SAL_CALL storeToStorage
+ ( const css::uno::Reference< css::embed::XStorage >& Storage,
+ const OUString& NameBase, const OUString& Comment ) override;
+ virtual void SAL_CALL storeToURL( const OUString& URL, const OUString& NameBase,
+ const OUString& Comment, const css::uno::Reference
+ < css::task::XInteractionHandler >& Handler ) override;
+ virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL exportBinary( ) override;
+ virtual void SAL_CALL importBinary( const css::uno::Sequence< ::sal_Int8 >& Data ) override;
+
+ // XStringResourceWithLocation
+ virtual void SAL_CALL storeAsURL( const OUString& URL ) override;
+ virtual void SAL_CALL setURL( const OUString& URL ) override;
+};
+
+
+} // namespace stringtable
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/vbaevents/eventhelper.cxx b/scripting/source/vbaevents/eventhelper.cxx
new file mode 100644
index 000000000..9da09b734
--- /dev/null
+++ b/scripting/source/vbaevents/eventhelper.cxx
@@ -0,0 +1,982 @@
+/* -*- 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/macros.h>
+#include <sal/log.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/uno3.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <ooo/vba/XVBAToOOEventDescGen.hpp>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/theIntrospection.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+
+#include <com/sun/star/util/XCloseListener.hpp>
+#include <com/sun/star/util/XCloseBroadcaster.hpp>
+
+#include <com/sun/star/frame/XModel.hpp>
+
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+#include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
+
+#include <com/sun/star/container/XNamed.hpp>
+
+#include <com/sun/star/drawing/XControlShape.hpp>
+
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/awt/XDialog.hpp>
+#include <com/sun/star/awt/KeyEvent.hpp>
+#include <com/sun/star/awt/MouseEvent.hpp>
+#include <com/sun/star/awt/XFixedText.hpp>
+#include <com/sun/star/awt/XTextComponent.hpp>
+#include <com/sun/star/awt/XComboBox.hpp>
+#include <com/sun/star/awt/XRadioButton.hpp>
+#include <com/sun/star/awt/XListBox.hpp>
+
+#include <sfx2/objsh.hxx>
+#include <basic/basmgr.hxx>
+#include <filter/msfilter/msvbahelper.hxx>
+#include <vbahelper/vbareturntypes.hxx>
+
+#include <com/sun/star/script/XScriptListener.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/evtmethodhelper.hxx>
+
+#include <vector>
+#include <unordered_map>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::uno;
+using namespace ::ooo::vba;
+
+// Some constants
+constexpr std::u16string_view DELIM = u"::";
+constexpr sal_Int32 DELIMLEN = DELIM.size();
+
+static bool isKeyEventOk( awt::KeyEvent& evt, const Sequence< Any >& params )
+{
+ return params.hasElements() && ( params[ 0 ] >>= evt );
+}
+
+static bool isMouseEventOk( awt::MouseEvent& evt, const Sequence< Any >& params )
+{
+ return params.hasElements() && ( params[ 0 ] >>= evt );
+}
+
+static Sequence< Any > ooMouseEvtToVBADblClick( const Sequence< Any >& params )
+{
+ awt::MouseEvent evt;
+
+ if ( !( isMouseEventOk(evt, params)) ||
+ (evt.ClickCount != 2) )
+ return Sequence< Any >();
+ // give back orig params, this will signal that the event is good
+ return params;
+}
+
+static Sequence< Any > ooMouseEvtToVBAMouseEvt( const Sequence< Any >& params )
+{
+ awt::MouseEvent evt;
+
+ if ( !isMouseEventOk(evt, params) )
+ return Sequence< Any >();
+
+ Sequence< Any > translatedParams{ Any(evt.Buttons), // Buttons
+ Any(evt.Modifiers), // Shift
+ Any(evt.X), // X
+ Any(evt.Y) }; // Y
+ return translatedParams;
+}
+
+static Sequence< Any > ooKeyPressedToVBAKeyPressed( const Sequence< Any >& params )
+{
+ awt::KeyEvent evt;
+
+ if ( !isKeyEventOk( evt, params ) )
+ return Sequence< Any >();
+
+ Reference< msforms::XReturnInteger> xKeyCode = new ReturnInteger( sal_Int32( evt.KeyCode ) );
+ Sequence< Any > translatedParams{ Any(xKeyCode) };
+ return translatedParams;
+}
+
+static Sequence< Any > ooKeyPressedToVBAKeyUpDown( const Sequence< Any >& params )
+{
+ awt::KeyEvent evt;
+
+ if ( !isKeyEventOk( evt, params ) )
+ return Sequence< Any >();
+
+ Reference< msforms::XReturnInteger> xKeyCode = new ReturnInteger( evt.KeyCode );
+ sal_Int8 shift = sal::static_int_cast<sal_Int8>( evt.Modifiers );
+
+ // #TODO check whether values from OOO conform to values generated from vba
+ Sequence< Any > translatedParams{ Any(xKeyCode), Any(shift) };
+ return translatedParams;
+}
+
+typedef Sequence< Any > (*Translator)(const Sequence< Any >&);
+
+namespace {
+
+//expand the "TranslateInfo" struct to support more kinds of events
+struct TranslateInfo
+{
+ OUString sVBAName; //vba event name
+ Translator toVBA; //the method to convert OO event parameters to VBA event parameters
+ bool (*ApproveRule)(const ScriptEvent& evt, void const * pPara); //this method is used to determine which types of controls should execute the event
+ void const *pPara; //Parameters for the above approve method
+};
+
+}
+
+typedef std::unordered_map<
+ OUString,
+ std::vector< TranslateInfo > > EventInfoHash;
+
+namespace {
+
+struct TranslatePropMap
+{
+ OUString sEventInfo; //OO event name
+ TranslateInfo aTransInfo;
+};
+
+}
+
+static bool ApproveAll(const ScriptEvent& evt, void const * pPara); //allow all types of controls to execute the event
+static bool ApproveType(const ScriptEvent& evt, void const * pPara); //certain types of controls should execute the event, those types are given by pPara
+static bool DenyType(const ScriptEvent& evt, void const * pPara); //certain types of controls should not execute the event, those types are given by pPara
+static bool DenyMouseDrag(const ScriptEvent& evt, void const * pPara); //used for VBA MouseMove event when "Shift" key is pressed
+
+namespace {
+
+struct TypeList
+{
+ uno::Type const * pTypeList;
+ int nListLength;
+};
+
+}
+
+Type const typeXFixedText = cppu::UnoType<awt::XFixedText>::get();
+Type const typeXTextComponent = cppu::UnoType<awt::XTextComponent>::get();
+Type const typeXComboBox = cppu::UnoType<awt::XComboBox>::get();
+Type const typeXRadioButton = cppu::UnoType<awt::XRadioButton>::get();
+Type const typeXListBox = cppu::UnoType<awt::XListBox>::get();
+
+
+TypeList const fixedTextList = {&typeXFixedText, 1};
+TypeList const textCompList = {&typeXTextComponent, 1};
+TypeList const radioButtonList = {&typeXRadioButton, 1};
+TypeList const comboBoxList = {&typeXComboBox, 1};
+TypeList const listBoxList = {&typeXListBox, 1};
+
+//this array stores the OO event to VBA event translation info
+static TranslatePropMap aTranslatePropMap_Impl[] =
+{
+ { OUString("actionPerformed"), { OUString("_Change"), nullptr, DenyType, static_cast<void const *>(&radioButtonList) } },
+ // actionPerformed ooo event
+ { OUString("actionPerformed"), { OUString("_Click"), nullptr, ApproveAll, nullptr } },
+ { OUString("itemStateChanged"), { OUString("_Change"), nullptr, ApproveType, static_cast<void const *>(&radioButtonList) } },
+ // itemStateChanged ooo event
+ { OUString("itemStateChanged"), { OUString("_Click"), nullptr, ApproveType, static_cast<void const *>(&comboBoxList) } },
+
+ { OUString("itemStateChanged"), { OUString("_Click"), nullptr, ApproveType, static_cast<void const *>(&listBoxList) } },
+ // changed ooo event
+ { OUString("changed"), { OUString("_Change"), nullptr, ApproveAll, nullptr } },
+
+ // focusGained ooo event
+ { OUString("focusGained"), { OUString("_GotFocus"), nullptr, ApproveAll, nullptr } },
+
+ // focusLost ooo event
+ { OUString("focusLost"), { OUString("_LostFocus"), nullptr, ApproveAll, nullptr } },
+ { OUString("focusLost"), { OUString("_Exit"), nullptr, ApproveType, static_cast<void const *>(&textCompList) } }, // support VBA TextBox_Exit event
+
+ // adjustmentValueChanged ooo event
+ { OUString("adjustmentValueChanged"), { OUString("_Scroll"), nullptr, ApproveAll, nullptr } },
+ { OUString("adjustmentValueChanged"), { OUString("_Change"), nullptr, ApproveAll, nullptr } },
+
+ // textChanged ooo event
+ { OUString("textChanged"), { OUString("_Change"), nullptr, ApproveAll, nullptr } },
+
+ // keyReleased ooo event
+ { OUString("keyReleased"), { OUString("_KeyUp"), ooKeyPressedToVBAKeyUpDown, ApproveAll, nullptr } },
+
+ // mouseReleased ooo event
+ { OUString("mouseReleased"), { OUString("_Click"), ooMouseEvtToVBAMouseEvt, ApproveType, static_cast<void const *>(&fixedTextList) } },
+ { OUString("mouseReleased"), { OUString("_MouseUp"), ooMouseEvtToVBAMouseEvt, ApproveAll, nullptr } },
+
+ // mousePressed ooo event
+ { OUString("mousePressed"), { OUString("_MouseDown"), ooMouseEvtToVBAMouseEvt, ApproveAll, nullptr } },
+ { OUString("mousePressed"), { OUString("_DblClick"), ooMouseEvtToVBADblClick, ApproveAll, nullptr } },
+
+ // mouseMoved ooo event
+ { OUString("mouseMoved"), { OUString("_MouseMove"), ooMouseEvtToVBAMouseEvt, ApproveAll, nullptr } },
+ { OUString("mouseDragged"), { OUString("_MouseMove"), ooMouseEvtToVBAMouseEvt, DenyMouseDrag, nullptr } },
+
+ // keyPressed ooo event
+ { OUString("keyPressed"), { OUString("_KeyDown"), ooKeyPressedToVBAKeyUpDown, ApproveAll, nullptr } },
+ { OUString("keyPressed"), { OUString("_KeyPress"), ooKeyPressedToVBAKeyPressed, ApproveAll, nullptr } }
+};
+
+static EventInfoHash& getEventTransInfo()
+{
+ static EventInfoHash eventTransInfo = []()
+ {
+ EventInfoHash tmp;
+ OUString sEventInfo;
+ TranslatePropMap* pTransProp = aTranslatePropMap_Impl;
+ int nCount = SAL_N_ELEMENTS(aTranslatePropMap_Impl);
+
+ int i = 0;
+ while (i < nCount)
+ {
+ sEventInfo = pTransProp->sEventInfo;
+ std::vector< TranslateInfo > infoList;
+ do
+ {
+ infoList.push_back( pTransProp->aTransInfo );
+ pTransProp++;
+ i++;
+ }while(i < nCount && sEventInfo == pTransProp->sEventInfo);
+ tmp[sEventInfo] = std::move(infoList);
+ }
+ return tmp;
+ }();
+ return eventTransInfo;
+}
+
+
+// Helper class
+
+namespace {
+
+class ScriptEventHelper
+{
+public:
+ explicit ScriptEventHelper( const Reference< XInterface >& xControl );
+ explicit ScriptEventHelper( const OUString& sCntrlServiceName );
+ ~ScriptEventHelper();
+ Sequence< ScriptEventDescriptor > createEvents( const OUString& sCodeName );
+ Sequence< OUString > getEventListeners() const;
+private:
+ Reference< XComponentContext > m_xCtx;
+ Reference< XInterface > m_xControl;
+ bool m_bDispose;
+};
+
+}
+
+static bool
+eventMethodToDescriptor( std::u16string_view rEventMethod, ScriptEventDescriptor& evtDesc, const OUString& sCodeName )
+{
+ // format of ControlListener is TypeName::methodname e.g.
+ // "com.sun.star.awt.XActionListener::actionPerformed" or
+ // "XActionListener::actionPerformed
+
+ OUString sMethodName;
+ OUString sTypeName;
+ size_t nDelimPos = rEventMethod.find( DELIM );
+ if ( nDelimPos == std::u16string_view::npos )
+ {
+ return false;
+ }
+ sMethodName = rEventMethod.substr( nDelimPos + DELIMLEN );
+ sTypeName = rEventMethod.substr( 0, nDelimPos );
+
+ EventInfoHash& infos = getEventTransInfo();
+
+ // Only create an ScriptEventDescriptor for an event we can translate
+ // or emulate
+ if ( !sMethodName.isEmpty()
+ && !sTypeName.isEmpty()
+ && ( infos.find( sMethodName ) != infos.end() ) )
+ {
+ // just fill in CodeName, when the event fires the other
+ // info is gathered from the event source to determine what
+ // event handler we try to call
+ evtDesc.ScriptCode = sCodeName;
+ evtDesc.ListenerType = sTypeName;
+ evtDesc.EventMethod = sMethodName;
+
+ // set this it VBAInterop, ensures that it doesn't
+ // get persisted or shown in property editors
+ evtDesc.ScriptType = "VBAInterop";
+ return true;
+ }
+ return false;
+
+}
+
+ScriptEventHelper::ScriptEventHelper( const Reference< XInterface >& xControl ) :
+ m_xCtx( comphelper::getProcessComponentContext() ),
+ m_xControl( xControl ),
+ m_bDispose( false )
+{}
+
+ScriptEventHelper::ScriptEventHelper( const OUString& sCntrlServiceName ) :
+ m_xCtx( comphelper::getProcessComponentContext() ),
+ m_bDispose( true )
+{
+ m_xControl.set( m_xCtx->getServiceManager()->createInstanceWithContext( sCntrlServiceName, m_xCtx ), uno::UNO_QUERY );
+}
+
+ScriptEventHelper::~ScriptEventHelper()
+{
+ // dispose control ( and remove any associated event registrations )
+ if ( m_bDispose )
+ {
+ try
+ {
+ uno::Reference< lang::XComponent > xComp( m_xControl, uno::UNO_QUERY_THROW );
+ xComp->dispose();
+ }
+ // destructor can't throw
+ catch( uno::Exception& )
+ {
+ }
+ }
+}
+
+Sequence< OUString >
+ScriptEventHelper::getEventListeners() const
+{
+ std::vector< OUString > eventMethods;
+
+ Reference< beans::XIntrospection > xIntrospection = beans::theIntrospection::get( m_xCtx );
+
+ Reference< beans::XIntrospectionAccess > xIntrospectionAccess =
+ xIntrospection->inspect( Any( m_xControl ) );
+ const Sequence< Type > aControlListeners =
+ xIntrospectionAccess->getSupportedListeners();
+ for ( const Type& listType : aControlListeners )
+ {
+ OUString sFullTypeName = listType.getTypeName();
+ const Sequence< OUString > sMeths =
+ comphelper::getEventMethodsForType( listType );
+ std::transform(sMeths.begin(), sMeths.end(), std::back_inserter(eventMethods),
+ [&sFullTypeName](const OUString& rMeth) -> OUString { return sFullTypeName + DELIM + rMeth; });
+ }
+
+ return comphelper::containerToSequence(eventMethods);
+}
+
+Sequence< ScriptEventDescriptor >
+ScriptEventHelper::createEvents( const OUString& sCodeName )
+{
+ const Sequence< OUString > aControlListeners = getEventListeners();
+ sal_Int32 nLength = aControlListeners.getLength();
+
+ Sequence< ScriptEventDescriptor > aDest( nLength );
+ sal_Int32 nEvts = 0;
+ for ( OUString const & i : aControlListeners)
+ {
+ // from getListeners eventName is of form
+ // "com.sun.star.awt.XActionListener::actionPerformed"
+ // we need to strip "com.sun.star.awt." from that for form
+ // controls
+ ScriptEventDescriptor evtDesc;
+ if ( eventMethodToDescriptor( i, evtDesc, sCodeName ) )
+ {
+ sal_Int32 dIndex = nEvts;
+ ++nEvts;
+ if ( nEvts > aDest.getLength() )
+ aDest.realloc( nEvts );// should never happen
+ aDest.getArray()[ dIndex ] = evtDesc;
+ }
+ }
+ aDest.realloc( nEvts );
+
+ return aDest;
+}
+
+
+typedef ::cppu::WeakImplHelper< container::XNameContainer > NameContainer_BASE;
+
+namespace {
+
+class ReadOnlyEventsNameContainer : public NameContainer_BASE
+{
+public:
+ ReadOnlyEventsNameContainer( const Sequence< OUString >& eventMethods, const OUString& sCodeName );
+ // XNameContainer
+
+ virtual void SAL_CALL insertByName( const OUString&, const Any& ) override
+ {
+ throw RuntimeException("ReadOnly container" );
+
+ }
+ virtual void SAL_CALL removeByName( const OUString& ) override
+ {
+ throw RuntimeException("ReadOnly container" );
+ }
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString&, const Any& ) override
+ {
+ throw RuntimeException("ReadOnly container" );
+
+ }
+
+ // XNameAccess
+ virtual Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual Type SAL_CALL getElementType( ) override
+ { return cppu::UnoType<OUString>::get(); }
+ virtual sal_Bool SAL_CALL hasElements( ) override
+ { return !m_hEvents.empty(); }
+private:
+
+typedef std::unordered_map< OUString, Any > EventSupplierHash;
+
+ EventSupplierHash m_hEvents;
+};
+
+}
+
+ReadOnlyEventsNameContainer::ReadOnlyEventsNameContainer( const Sequence< OUString >& eventMethods, const OUString& sCodeName )
+{
+ for ( const OUString& rSrc : eventMethods )
+ {
+ Any aDesc;
+ ScriptEventDescriptor evtDesc;
+ if ( eventMethodToDescriptor( rSrc, evtDesc, sCodeName ) )
+ {
+ aDesc <<= evtDesc;
+ m_hEvents[ rSrc ] = aDesc;
+ }
+ }
+}
+
+Any SAL_CALL
+ReadOnlyEventsNameContainer::getByName( const OUString& aName ){
+ EventSupplierHash::const_iterator it = m_hEvents.find( aName );
+ if ( it == m_hEvents.end() )
+ throw container::NoSuchElementException();
+ return it->second;
+}
+
+Sequence< OUString > SAL_CALL
+ReadOnlyEventsNameContainer::getElementNames( )
+{
+ return comphelper::mapKeysToSequence(m_hEvents);
+}
+
+sal_Bool SAL_CALL
+ReadOnlyEventsNameContainer::hasByName( const OUString& aName )
+{
+ EventSupplierHash::const_iterator it = m_hEvents.find( aName );
+ if ( it == m_hEvents.end() )
+ return false;
+ return true;
+}
+
+namespace {
+
+class ReadOnlyEventsSupplier : public ::cppu::WeakImplHelper< XScriptEventsSupplier >
+{
+public:
+ ReadOnlyEventsSupplier( const Sequence< OUString >& eventMethods, const OUString& sCodeName )
+ { m_xNameContainer = new ReadOnlyEventsNameContainer( eventMethods, sCodeName ); }
+
+ // XScriptEventSupplier
+ virtual Reference< container::XNameContainer > SAL_CALL getEvents( ) override { return m_xNameContainer; }
+private:
+ Reference< container::XNameContainer > m_xNameContainer;
+};
+
+}
+
+typedef ::cppu::WeakImplHelper< XScriptListener, util::XCloseListener, lang::XInitialization, css::lang::XServiceInfo > EventListener_BASE;
+
+#define EVENTLSTNR_PROPERTY_ID_MODEL 1
+constexpr OUStringLiteral EVENTLSTNR_PROPERTY_MODEL = u"Model";
+
+namespace {
+
+class EventListener : public EventListener_BASE
+ ,public ::comphelper::OMutexAndBroadcastHelper
+ ,public ::comphelper::OPropertyContainer
+ ,public ::comphelper::OPropertyArrayUsageHelper< EventListener >
+{
+
+public:
+ EventListener();
+ // XEventListener
+ virtual void SAL_CALL disposing(const lang::EventObject& Source) override;
+ using cppu::OPropertySetHelper::disposing;
+
+ // XScriptListener
+ virtual void SAL_CALL firing(const ScriptEvent& evt) override;
+ virtual Any SAL_CALL approveFiring(const ScriptEvent& evt) override;
+ // XCloseListener
+ virtual void SAL_CALL queryClosing( const lang::EventObject& Source, sal_Bool GetsOwnership ) override;
+ virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
+ // XInterface
+ DECLARE_XINTERFACE()
+
+ // XTypeProvider
+ DECLARE_XTYPEPROVIDER()
+ virtual void SAL_CALL setFastPropertyValue( sal_Int32 nHandle, const css::uno::Any& rValue ) override
+ {
+ if ( nHandle == EVENTLSTNR_PROPERTY_ID_MODEL )
+ {
+ uno::Reference< frame::XModel > xModel( rValue, uno::UNO_QUERY );
+ if( xModel != m_xModel)
+ {
+ // Remove the listener from the old XCloseBroadcaster.
+ uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY );
+ if (xCloseBroadcaster.is())
+ {
+ xCloseBroadcaster->removeCloseListener( this );
+ }
+ // Add the listener into the new XCloseBroadcaster.
+ xCloseBroadcaster.set( xModel, uno::UNO_QUERY );
+ if (xCloseBroadcaster.is())
+ {
+ xCloseBroadcaster->addCloseListener( this );
+ }
+ }
+ }
+ OPropertyContainer::setFastPropertyValue( nHandle, rValue );
+ if ( nHandle == EVENTLSTNR_PROPERTY_ID_MODEL )
+ setShellFromModel();
+ }
+
+ OUString SAL_CALL getImplementationName() override
+ {
+ return "ooo.vba.EventListener";
+ }
+
+ sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
+ {
+ return { getImplementationName() };
+ }
+
+protected:
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper( ) override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+private:
+ void setShellFromModel();
+ /// @throws RuntimeException
+ void firing_Impl( const ScriptEvent& evt, Any *pSyncRet );
+
+ Reference< frame::XModel > m_xModel;
+ bool m_bDocClosed;
+ SfxObjectShell* mpShell;
+};
+
+}
+
+EventListener::EventListener() :
+OPropertyContainer(GetBroadcastHelper()), m_bDocClosed(false), mpShell( nullptr )
+{
+ registerProperty( EVENTLSTNR_PROPERTY_MODEL, EVENTLSTNR_PROPERTY_ID_MODEL,
+ beans::PropertyAttribute::TRANSIENT, &m_xModel, cppu::UnoType<decltype(m_xModel)>::get() );
+}
+
+void
+EventListener::setShellFromModel()
+{
+ // reset mpShell
+ mpShell = nullptr;
+ SfxObjectShell* pShell = SfxObjectShell::GetFirst();
+ while ( m_xModel.is() && pShell )
+ {
+ if ( pShell->GetModel() == m_xModel )
+ {
+ mpShell = pShell;
+ break;
+ }
+ pShell = SfxObjectShell::GetNext( *pShell );
+ }
+}
+
+//XEventListener
+void
+EventListener::disposing(const lang::EventObject&)
+{
+}
+
+//XScriptListener
+
+void SAL_CALL
+EventListener::firing(const ScriptEvent& evt)
+{
+ firing_Impl( evt, nullptr );
+}
+
+Any SAL_CALL
+EventListener::approveFiring(const ScriptEvent& evt)
+{
+ Any ret;
+ firing_Impl( evt, &ret );
+ return ret;
+}
+
+// XCloseListener
+void SAL_CALL
+EventListener::queryClosing( const lang::EventObject& /*Source*/, sal_Bool /*GetsOwnership*/ )
+{
+ //Nothing to do
+}
+
+void SAL_CALL
+EventListener::notifyClosing( const lang::EventObject& /*Source*/ )
+{
+ m_bDocClosed = true;
+ uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY );
+ if (xCloseBroadcaster.is())
+ {
+ xCloseBroadcaster->removeCloseListener( this );
+ }
+}
+
+// XInitialization
+void SAL_CALL
+EventListener::initialize( const Sequence< Any >& aArguments )
+{
+ if ( aArguments.getLength() == 1 )
+ aArguments[0] >>= m_xModel;
+ SAL_INFO(
+ "scripting",
+ "args " << aArguments.getLength() << " m_xModel " << m_xModel.is());
+}
+
+// XInterface
+
+IMPLEMENT_FORWARD_XINTERFACE2( EventListener, EventListener_BASE, OPropertyContainer )
+
+// XTypeProvider
+
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( EventListener, EventListener_BASE, OPropertyContainer )
+
+// OPropertySetHelper
+
+::cppu::IPropertyArrayHelper&
+EventListener::getInfoHelper( )
+{
+ return *getArrayHelper();
+}
+
+// OPropertyArrayUsageHelper
+
+::cppu::IPropertyArrayHelper*
+EventListener::createArrayHelper( ) const
+{
+ Sequence< beans::Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+}
+
+// XPropertySet
+Reference< beans::XPropertySetInfo >
+EventListener::getPropertySetInfo( )
+{
+ Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+
+//decide if the control should execute the event
+bool ApproveAll(SAL_UNUSED_PARAMETER const ScriptEvent&, SAL_UNUSED_PARAMETER void const * )
+{
+ return true;
+}
+
+//for the given control type in evt.Arguments[0], look for if it appears in the type list in pPara
+static bool FindControl(const ScriptEvent& evt, void const * pPara)
+{
+ lang::EventObject aEvent;
+ evt.Arguments[ 0 ] >>= aEvent;
+ uno::Reference< uno::XInterface > xInterface( aEvent.Source, uno::UNO_QUERY );
+
+ TypeList const * pTypeListInfo = static_cast<TypeList const *>(pPara);
+ Type const * pType = pTypeListInfo->pTypeList;
+ int nLen = pTypeListInfo->nListLength;
+
+ for (int i = 0; i < nLen; i++)
+ {
+ if ( xInterface->queryInterface( *pType ).hasValue() )
+ {
+ return true;
+ }
+ pType++;
+ }
+
+ return false;
+}
+
+//if the given control type in evt.Arguments[0] appears in the type list in pPara, then approve the execution
+bool ApproveType(const ScriptEvent& evt, void const * pPara)
+{
+ return FindControl(evt, pPara);
+}
+
+//if the given control type in evt.Arguments[0] appears in the type list in pPara, then deny the execution
+bool DenyType(const ScriptEvent& evt, void const * pPara)
+{
+ return !FindControl(evt, pPara);
+}
+
+//when mouse is moving, either the mouse button is pressed or some key is pressed can trigger the OO mouseDragged event,
+//the former should be denied, and the latter allowed, only by doing so can the VBA MouseMove event when the "Shift" key is
+//pressed can be correctly triggered
+bool DenyMouseDrag(const ScriptEvent& evt, SAL_UNUSED_PARAMETER void const * )
+{
+ awt::MouseEvent aEvent;
+ evt.Arguments[ 0 ] >>= aEvent;
+ return aEvent.Buttons == 0;
+}
+
+
+// EventListener
+
+void
+EventListener::firing_Impl(const ScriptEvent& evt, Any* pRet )
+{
+ // let default handlers deal with non vba stuff
+ if ( evt.ScriptType != "VBAInterop" )
+ return;
+ lang::EventObject aEvent;
+ evt.Arguments[ 0 ] >>= aEvent;
+ OUString sName = "UserForm";
+
+ uno::Reference< awt::XDialog > xDlg( aEvent.Source, uno::UNO_QUERY );
+ if ( !xDlg.is() )
+ {
+ // evt.Source is
+ // a) Dialog
+ // b) xShapeControl ( from api (sheet control) )
+ // c) eventmanager ( I guess )
+ // d) vba control ( from api also )
+ uno::Reference< drawing::XControlShape > xCntrlShape( evt.Source, uno::UNO_QUERY );
+ uno::Reference< awt::XControl > xControl( aEvent.Source, uno::UNO_QUERY );
+ if ( xCntrlShape.is() )
+ {
+ // for sheet controls ( that fire from the api ) we don't
+ // have the real control ( that's only available from the view )
+ // api code creates just a control instance that is transferred
+ // via aEvent.Arguments[ 0 ] that control though has no
+ // info like name etc.
+ uno::Reference< container::XNamed > xName( xCntrlShape->getControl(), uno::UNO_QUERY_THROW );
+ sName = xName->getName();
+ }
+ else
+ {
+ // Userform control ( fired from the api or from event manager )
+ uno::Reference< beans::XPropertySet > xProps;
+ xProps.set( xControl->getModel(), uno::UNO_QUERY_THROW );
+ xProps->getPropertyValue("Name") >>= sName;
+ }
+ }
+ //dumpEvent( evt );
+ EventInfoHash& infos = getEventTransInfo();
+ EventInfoHash::const_iterator eventInfo_it = infos.find( evt.MethodName );
+ EventInfoHash::const_iterator it_end = infos.end();
+ if ( eventInfo_it == it_end )
+ {
+ SAL_WARN("scripting", "Bogus event for " << evt.ScriptType );
+ return;
+ }
+
+ uno::Reference< script::provider::XScriptProviderSupplier > xSPS( m_xModel, uno::UNO_QUERY );
+ uno::Reference< script::provider::XScriptProvider > xScriptProvider;
+ if ( xSPS.is() )
+ {
+ xScriptProvider = xSPS->getScriptProvider();
+ }
+ if ( !(xScriptProvider.is() && mpShell) )
+ return;
+
+ BasicManager* pBasicManager = mpShell->GetBasicManager();
+ OUString sProject;
+ OUString sScriptCode( evt.ScriptCode );
+ // dialogs pass their own library, presence of Dot determines that
+ if ( sScriptCode.indexOf( '.' ) == -1 )
+ {
+ //'Project' is a better default but I want to force failures
+ //OUString sMacroLoc("Project");
+ sProject = "Standard";
+
+ if (!pBasicManager->GetName().isEmpty())
+ {
+ sProject = pBasicManager->GetName();
+ }
+ }
+ else
+ {
+ sal_Int32 nIndex = sScriptCode.indexOf( '.' );
+ sProject = sScriptCode.copy( 0, nIndex );
+ sScriptCode = sScriptCode.copy( nIndex + 1 );
+ }
+ OUString sMacroLoc = sProject + "." + sScriptCode + ".";
+
+ for (const auto& rTxInfo : eventInfo_it->second)
+ {
+ // If the document is closed, we should not execute macro.
+ if (m_bDocClosed)
+ {
+ break;
+ }
+
+ // see if we have a match for the handlerextension
+ // where ScriptCode is methodname_handlerextension
+ OUString sToResolve = sMacroLoc + sName + rTxInfo.sVBAName;
+
+ ooo::vba::MacroResolvedInfo aMacroResolvedInfo = ooo::vba::resolveVBAMacro( mpShell, sToResolve );
+ if ( aMacroResolvedInfo.mbFound )
+ {
+
+ if (! rTxInfo.ApproveRule(evt, rTxInfo.pPara) )
+ {
+ continue;
+ }
+
+ // !! translate arguments & emulate events where necessary
+ Sequence< Any > aArguments;
+ if ( rTxInfo.toVBA )
+ {
+ aArguments = rTxInfo.toVBA( evt.Arguments );
+ }
+ else
+ {
+ aArguments = evt.Arguments;
+ }
+ if ( aArguments.hasElements() )
+ {
+ // call basic event handlers for event
+
+ // create script url
+ OUString url = aMacroResolvedInfo.msResolvedMacro;
+ try
+ {
+ uno::Any aDummyCaller( OUString("Error") );
+ if ( pRet )
+ {
+ ooo::vba::executeMacro( mpShell, url, aArguments, *pRet, aDummyCaller );
+ }
+ else
+ {
+ uno::Any aRet;
+ ooo::vba::executeMacro( mpShell, url, aArguments, aRet, aDummyCaller );
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("scripting", "event script raised" );
+ }
+ }
+ }
+ }
+}
+
+namespace {
+
+class VBAToOOEventDescGen : public ::cppu::WeakImplHelper< XVBAToOOEventDescGen, css::lang::XServiceInfo >
+{
+public:
+ VBAToOOEventDescGen();
+
+ // XVBAToOOEventDescGen
+ virtual Sequence< ScriptEventDescriptor > SAL_CALL getEventDescriptions( const OUString& sCtrlServiceName, const OUString& sCodeName ) override;
+ virtual Reference< XScriptEventsSupplier > SAL_CALL getEventSupplier( const Reference< XInterface >& xControl, const OUString& sCodeName ) override;
+
+ OUString SAL_CALL getImplementationName() override
+ {
+ return "ooo.vba.VBAToOOEventDesc";
+ }
+
+ sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
+ {
+ return { getImplementationName() };
+ }
+
+};
+
+}
+
+VBAToOOEventDescGen::VBAToOOEventDescGen() {}
+
+Sequence< ScriptEventDescriptor > SAL_CALL
+VBAToOOEventDescGen::getEventDescriptions( const OUString& sCntrlServiceName, const OUString& sCodeName )
+{
+ ScriptEventHelper evntHelper( sCntrlServiceName );
+ return evntHelper.createEvents( sCodeName );
+}
+
+Reference< XScriptEventsSupplier > SAL_CALL
+VBAToOOEventDescGen::getEventSupplier( const Reference< XInterface >& xControl, const OUString& sCodeName )
+{
+ ScriptEventHelper evntHelper( xControl );
+ Reference< XScriptEventsSupplier > xSupplier =
+ new ReadOnlyEventsSupplier(
+ evntHelper.getEventListeners(), sCodeName ) ;
+ return xSupplier;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ooo_vba_EventListener_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new EventListener);
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ooo_vba_VBAToOOEventDesc_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new VBAToOOEventDescGen);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/vbaevents/vbaevents.component b/scripting/source/vbaevents/vbaevents.component
new file mode 100644
index 000000000..75fcf0230
--- /dev/null
+++ b/scripting/source/vbaevents/vbaevents.component
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="ooo.vba.EventListener"
+ constructor="ooo_vba_EventListener_get_implementation">
+ <service name="ooo.vba.EventListener"/>
+ </implementation>
+ <implementation name="ooo.vba.VBAToOOEventDesc"
+ constructor="ooo_vba_VBAToOOEventDesc_get_implementation">
+ <service name="ooo.vba.VBAToOOEventDesc"/>
+ </implementation>
+</component>
diff --git a/scripting/util/scriptframe.component b/scripting/util/scriptframe.component
new file mode 100644
index 000000000..fc2af2a6b
--- /dev/null
+++ b/scripting/util/scriptframe.component
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.script.browse.BrowseNodeFactory"
+ constructor="scripting_BrowseNodeFactoryImpl_get_implementation">
+ <service name="com.sun.star.script.browse.BrowseNodeFactory"/>
+ <singleton name="com.sun.star.script.browse.theBrowseNodeFactory"/>
+ </implementation>
+ <implementation name="com.sun.star.script.provider.MasterScriptProvider"
+ constructor="scripting_MasterScriptProvider_get_implementation">
+ <service name="com.sun.star.script.browse.BrowseNode"/>
+ <service name="com.sun.star.script.provider.MasterScriptProvider"/>
+ <service name="com.sun.star.script.provider.ScriptProvider"/>
+ </implementation>
+ <implementation name="com.sun.star.script.provider.MasterScriptProviderFactory"
+ constructor="scripting_MasterScriptProviderFactory_get_implementation">
+ <service name="com.sun.star.script.provider.MasterScriptProviderFactory"/>
+ <singleton name="com.sun.star.script.provider.theMasterScriptProviderFactory"/>
+ </implementation>
+ <implementation name="com.sun.star.script.provider.ScriptURIHelper"
+ constructor="scripting_ScriptingFrameworkURIHelper_get_implementation">
+ <service name="com.sun.star.script.provider.ScriptURIHelper"/>
+ </implementation>
+</component>
diff --git a/scripting/workben/bindings/Highlight.xdl b/scripting/workben/bindings/Highlight.xdl
new file mode 100644
index 000000000..d711d87b6
--- /dev/null
+++ b/scripting/workben/bindings/Highlight.xdl
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * 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 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="Highlight" dlg:left="68" dlg:top="23" dlg:width="135" dlg:height="48" dlg:closeable="true" dlg:moveable="true">
+ <dlg:bulletinboard>
+ <dlg:text dlg:id="Label1" dlg:tab-index="2" dlg:left="3" dlg:top="8" dlg:width="33" dlg:height="9" dlg:value="Find What:"/>
+ <dlg:textfield dlg:id="HighlightTextField" dlg:tab-index="3" dlg:left="39" dlg:top="6" dlg:width="93" dlg:height="12"/>
+ <dlg:button dlg:id="HighlightButton" dlg:tab-index="0" dlg:left="20" dlg:top="24" dlg:width="46" dlg:height="18" dlg:value="Highlight">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Highlight.ButtonPressHandler.bsh?language=BeanShell&amp;location=share" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="ExitButton" dlg:tab-index="1" dlg:left="72" dlg:top="24" dlg:width="46" dlg:height="18" dlg:value="Exit">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Highlight.ButtonPressHandler.bsh?language=BeanShell&amp;location=share" script:language="Script"/>
+ </dlg:button>
+ </dlg:bulletinboard>
+</dlg:window>
diff --git a/scripting/workben/bindings/dialog.xlb b/scripting/workben/bindings/dialog.xlb
new file mode 100644
index 000000000..1445c98b8
--- /dev/null
+++ b/scripting/workben/bindings/dialog.xlb
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd">
+<library:library xmlns:library="http://openoffice.org/2000/library" library:name="ScriptBindingLibrary" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="Highlight"/>
+ <library:element library:name="MacroEditor"/>
+</library:library>
diff --git a/scripting/workben/bindings/script.xlb b/scripting/workben/bindings/script.xlb
new file mode 100644
index 000000000..33eb114b5
--- /dev/null
+++ b/scripting/workben/bindings/script.xlb
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd">
+<library:library xmlns:library="http://openoffice.org/2000/library" library:name="ScriptBindingLibrary" library:readonly="false" library:passwordprotected="false">
+</library:library>