From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- .../framework/provider/ClassLoaderFactory.java | 55 ++ .../framework/provider/EditorScriptContext.java | 79 +++ .../star/script/framework/provider/PathUtils.java | 83 +++ .../script/framework/provider/ScriptContext.java | 143 +++++ .../script/framework/provider/ScriptEditor.java | 30 + .../framework/provider/ScriptEditorBase.java | 73 +++ .../script/framework/provider/ScriptProvider.java | 673 +++++++++++++++++++++ .../script/framework/provider/SwingInvocation.java | 39 ++ .../framework/provider/beanshell/MANIFEST.MF | 2 + .../provider/beanshell/PlainSourceView.java | 395 ++++++++++++ .../beanshell/ScriptEditorForBeanShell.java | 400 ++++++++++++ .../beanshell/ScriptProviderForBeanShell.java | 367 +++++++++++ .../provider/beanshell/ScriptSourceModel.java | 125 ++++ .../provider/beanshell/ScriptSourceView.java | 29 + .../provider/beanshell/UnsavedChangesListener.java | 13 + .../framework/provider/beanshell/template.bsh | 65 ++ .../script/framework/provider/java/MANIFEST.MF | 2 + .../script/framework/provider/java/Resolver.java | 36 ++ .../framework/provider/java/ScriptDescriptor.java | 165 +++++ .../provider/java/ScriptProviderForJava.java | 307 ++++++++++ .../framework/provider/java/ScriptProxy.java | 69 +++ .../framework/provider/java/StrictResolver.java | 113 ++++ .../framework/provider/javascript/MANIFEST.MF | 2 + .../javascript/ScriptEditorForJavaScript.java | 319 ++++++++++ .../javascript/ScriptProviderForJavaScript.java | 330 ++++++++++ .../framework/provider/javascript/template.js | 54 ++ 26 files changed, 3968 insertions(+) create mode 100644 scripting/java/com/sun/star/script/framework/provider/ClassLoaderFactory.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/EditorScriptContext.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/PathUtils.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/ScriptContext.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/ScriptEditor.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/ScriptEditorBase.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/ScriptProvider.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/SwingInvocation.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/beanshell/MANIFEST.MF create mode 100644 scripting/java/com/sun/star/script/framework/provider/beanshell/PlainSourceView.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptEditorForBeanShell.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptProviderForBeanShell.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptSourceModel.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptSourceView.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/beanshell/UnsavedChangesListener.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/beanshell/template.bsh create mode 100644 scripting/java/com/sun/star/script/framework/provider/java/MANIFEST.MF create mode 100644 scripting/java/com/sun/star/script/framework/provider/java/Resolver.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/java/ScriptDescriptor.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/java/ScriptProviderForJava.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/java/ScriptProxy.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/java/StrictResolver.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/javascript/MANIFEST.MF create mode 100644 scripting/java/com/sun/star/script/framework/provider/javascript/ScriptEditorForJavaScript.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/javascript/ScriptProviderForJavaScript.java create mode 100644 scripting/java/com/sun/star/script/framework/provider/javascript/template.js (limited to 'scripting/java/com/sun/star/script/framework/provider') 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() { + 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 unsavedListener = new ArrayList(); + + 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 BEING_EDITED = + new HashMap(); + + // 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 JavaLoader + *

+ * + * @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 XSingleServiceFactory 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 ScriptDescriptor 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 m_classpath; + private final ArrayList> m_argumentTypes = new ArrayList>(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 ScriptDescriptor + * + * @return The Script Name value + */ + public String getName() { + return m_name; + } + + /** + * Gets the fully qualified name of this ScriptDescriptor + * + * @return The Script Name value + */ + public String getClassName() { + return m_className; + } + + /** + * Gets the method name of this ScriptDescriptor + * + * @return The methodName value + */ + public String getMethodName() { + return m_methodName; + } + + /** + * Sets the classpath value stored by this ScriptDescriptor + * + * @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 ScriptDescriptor + * + * @param classpath The new classpath value + */ + public void setClasspath(List classpath) { + this.m_classpath = classpath; + } + + /** + * Gets the classpath value stored by this ScriptDescriptor + * + * @return The classpath value + */ + public List getClasspath() { + return m_classpath; + } + + /** + * Adds the given Class 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 + * ScriptDescriptor + * + * 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 String representation of this + * ScriptDescriptor + * + * @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 JavaLoader + *

+ * + * @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 XSingleServiceFactory 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 invocationArgList = new ArrayList(); + 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 Method + * + * @see java.lang.reflect.Method + */ +public class ScriptProxy { + + private Object m_targetObject; + private final Method m_method; + + /** + * Constructs a ScriptProxy object for the given + * Method + * + * @param method Description of the Parameter + */ + public ScriptProxy(Method method) { + this.m_method = method; + } + + /** + * Sets the Object 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 ScriptProxy, + * 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 BEING_EDITED = new + HashMap(); + + 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 iter = BEING_EDITED.keySet().iterator(); + java.util.ArrayList keysToRemove = new java.util.ArrayList(); + + 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 JavaLoader + *

+ * + * @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 XSingleServiceFactory 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, "", 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)" ); -- cgit v1.2.3