summaryrefslogtreecommitdiffstats
path: root/scripting/java/com/sun/star/script/framework/provider
diff options
context:
space:
mode:
Diffstat (limited to 'scripting/java/com/sun/star/script/framework/provider')
-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
26 files changed, 3968 insertions, 0 deletions
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)" );