blob: 8db8fc792bd484f05689e99143f4dded29b2d487 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
package com.sun.star.script.framework.provider.beanshell;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Map;
import java.util.HashMap;
import com.sun.star.script.provider.XScriptContext;
import com.sun.star.script.framework.provider.ScriptEditor;
import com.sun.star.script.framework.provider.SwingInvocation;
import com.sun.star.script.framework.container.ScriptMetaData;
import com.sun.star.script.framework.provider.ClassLoaderFactory;
public class ScriptEditorForBeanShell
implements ScriptEditor, ActionListener
{
private JFrame frame;
private String filename;
private ScriptSourceModel model;
private ScriptSourceView view;
private XScriptContext context;
private URL scriptURL = null;
private ClassLoader cl = null;
// global ScriptEditorForBeanShell returned for getEditor() calls
private static ScriptEditorForBeanShell theScriptEditorForBeanShell;
// global list of ScriptEditors, key is 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 {
try {
URL url =
ScriptEditorForBeanShell.class.getResource("template.bsh");
InputStream in = url.openStream();
StringBuffer buf = new StringBuffer();
byte[] b = new byte[1024];
int len = 0;
while ((len = in.read(b)) != -1) {
buf.append(new String(b, 0, len));
}
in.close();
BSHTEMPLATE = buf.toString();
}
catch (IOException ioe) {
BSHTEMPLATE = "// BeanShell script";
}
catch (Exception e) {
BSHTEMPLATE = "// BeanShell script";
}
}
/**
* Returns the global ScriptEditorForBeanShell instance.
*/
public static ScriptEditorForBeanShell getEditor()
{
if (theScriptEditorForBeanShell == null)
{
synchronized(ScriptEditorForBeanShell.class)
{
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 (ScriptEditorForBeanShell)BEING_EDITED.get(url);
}
}
/**
* 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 occured
*
*/
public void indicateErrorLine( int lineNum )
{
model.indicateErrorLine( lineNum );
}
/**
* Executes the script edited by the editor
*
*/
public Object execute() throws Exception {
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;
String sUrl = entry.getParcelLocation();
if ( !sUrl.endsWith( "/" ) )
{
sUrl += "/";
}
sUrl += entry.getLanguageName();
final URL url = entry.getSourceURL();
SwingInvocation.invoke(
new Runnable() {
public void run() {
ScriptEditorForBeanShell editor;
synchronized (BEING_EDITED) {
editor = (ScriptEditorForBeanShell)
BEING_EDITED.get(url);
if (editor == null) {
editor = new ScriptEditorForBeanShell(
context, theCl, url);
BEING_EDITED.put(url, editor);
}
}
editor.frame.toFront();
}
});
}
catch (IOException ioe) {
showErrorMessage( "Error loading file: " + ioe.getMessage() );
}
}
}
private ScriptEditorForBeanShell() {
}
private ScriptEditorForBeanShell(XScriptContext context, ClassLoader cl,
URL url)
{
this.context = context;
this.scriptURL = url;
this.model = new ScriptSourceModel(url);
this.filename = url.getFile();
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();
frame.show();
}
private void showErrorMessage(String message) {
JOptionPane.showMessageDialog(frame, message,
"Error", JOptionPane.ERROR_MESSAGE);
}
private void initUI() {
frame = new JFrame("BeanShell Debug Window: " + filename);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(
new WindowAdapter()
{
public void windowClosing(WindowEvent e) {
doClose();
}
}
);
String[] labels = {"Run", "Clear", "Save", "Close"};
JPanel p = new JPanel();
p.setLayout(new FlowLayout());
for (int i = 0; i < labels.length; i++) {
JButton b = new JButton(labels[i]);
b.addActionListener(this);
p.add(b);
if (labels[i].equals("Save") && filename == null) {
b.setEnabled(false);
}
}
frame.getContentPane().add((JComponent)view, "Center");
frame.getContentPane().add(p, "South");
frame.pack();
frame.setSize(590, 480);
frame.setLocation(300, 200);
}
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 == false)
{
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();
if ( fos != null )
{
fos.close();
}
}
catch (IOException ignore) {
}
}
}
return result;
}
private void shutdown()
{
synchronized (BEING_EDITED) {
BEING_EDITED.remove(scriptURL);
}
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Run")) {
try
{
execute();
}
catch (Exception invokeException ) {
showErrorMessage(invokeException.getMessage());
}
}
else if (e.getActionCommand().equals("Close")) {
doClose();
}
else if (e.getActionCommand().equals("Save")) {
saveTextArea();
}
else if (e.getActionCommand().equals("Clear")) {
view.clear();
}
}
}