From: <kp...@us...> - 2007-12-12 19:41:19
|
Revision: 11402 http://jedit.svn.sourceforge.net/jedit/?rev=11402&view=rev Author: kpouer Date: 2007-12-12 11:41:18 -0800 (Wed, 12 Dec 2007) Log Message: ----------- big changes in InputHandling to allow the standalone TextArea to use beanshell actions. The most incompatibility that can happens is when calling jEdit.getActionSets() that was returning ActionSet[] and now returns JEditActionSet[] Modified Paths: -------------- jEdit/trunk/org/gjt/sp/jedit/ActionContext.java jEdit/trunk/org/gjt/sp/jedit/ActionListHandler.java jEdit/trunk/org/gjt/sp/jedit/ActionSet.java jEdit/trunk/org/gjt/sp/jedit/EditAction.java jEdit/trunk/org/gjt/sp/jedit/gui/DefaultInputHandler.java jEdit/trunk/org/gjt/sp/jedit/gui/InputHandler.java jEdit/trunk/org/gjt/sp/jedit/gui/ShortcutPrefixActiveEvent.java jEdit/trunk/org/gjt/sp/jedit/input/AbstractInputHandler.java jEdit/trunk/org/gjt/sp/jedit/input/TextAreaInputHandler.java jEdit/trunk/org/gjt/sp/jedit/jEdit.java jEdit/trunk/org/gjt/sp/jedit/options/ContextOptionPane.java jEdit/trunk/org/gjt/sp/jedit/options/ShortcutsOptionPane.java jEdit/trunk/org/gjt/sp/jedit/options/ToolBarOptionPane.java jEdit/trunk/org/gjt/sp/jedit/textarea/TextArea.java Added Paths: ----------- jEdit/trunk/org/gjt/sp/jedit/IPropertyManager.java jEdit/trunk/org/gjt/sp/jedit/JEditAbstractEditAction.java jEdit/trunk/org/gjt/sp/jedit/JEditActionContext.java jEdit/trunk/org/gjt/sp/jedit/JEditActionSet.java jEdit/trunk/org/gjt/sp/jedit/JEditBeanShell.java jEdit/trunk/org/gjt/sp/jedit/JEditBeanShellAction.java jEdit/trunk/org/gjt/sp/jedit/textarea/textarea.actions.xml Modified: jEdit/trunk/org/gjt/sp/jedit/ActionContext.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/ActionContext.java 2007-12-12 17:02:02 UTC (rev 11401) +++ jEdit/trunk/org/gjt/sp/jedit/ActionContext.java 2007-12-12 19:41:18 UTC (rev 11402) @@ -37,133 +37,6 @@ * @author Slava Pestov * @version $Id$ */ -public abstract class ActionContext +public abstract class ActionContext extends JEditActionContext<EditAction, ActionSet> { - //{{{ invokeAction() method - /** - * Invokes the given action in response to a user-generated event. - * @param evt The event - * @param action The action - * @since jEdit 4.2pre1 - */ - public abstract void invokeAction(EventObject evt, EditAction action); - //}}} - - //{{{ addActionSet() method - /** - * Adds a new action set to the context. - * @since jEdit 4.2pre1 - */ - public void addActionSet(ActionSet actionSet) - { - actionNames = null; - actionSets.addElement(actionSet); - actionSet.context = this; - String[] actions = actionSet.getActionNames(); - for(int i = 0; i < actions.length; i++) - { - /* Is it already there? */ - if (actionHash.containsKey(actions[i])) - { - /* Save it for plugin unloading time */ - ActionSet oldAction = actionHash.get(actions[i]); - overriddenActions.put(actions[i], oldAction); - } - actionHash.put(actions[i],actionSet); - } - } //}}} - - //{{{ removeActionSet() method - /** - * Removes an action set from the context. - * @since jEdit 4.2pre1 - */ - public void removeActionSet(ActionSet actionSet) - { - actionNames = null; - actionSets.removeElement(actionSet); - actionSet.context = null; - String[] actions = actionSet.getActionNames(); - for(int i = 0; i < actions.length; i++) - { - actionHash.remove(actions[i]); - if (overriddenActions.containsKey(actions[i])) - { - ActionSet oldAction = overriddenActions.remove(actions[i]); - actionHash.put(actions[i], oldAction); - } - } - } //}}} - - //{{{ getActionSets() method - /** - * Returns all registered action sets. - * @since jEdit 4.2pre1 - */ - public ActionSet[] getActionSets() - { - ActionSet[] retVal = new ActionSet[actionSets.size()]; - actionSets.copyInto(retVal); - return retVal; - } //}}} - - //{{{ getAction() method - /** - * Returns the specified action. - * @param name The action name - * @since jEdit 4.2pre1 - */ - public EditAction getAction(String name) - { - ActionSet set = (ActionSet)actionHash.get(name); - if(set == null) - return null; - else - return set.getAction(name); - } //}}} - - //{{{ getActionSetForAction() method - /** - * Returns the action set that contains the specified action. - * - * @param action The action - * @since jEdit 4.2pre1 - */ - public ActionSet getActionSetForAction(String action) - { - return (ActionSet)actionHash.get(action); - } //}}} - - //{{{ getActionNames() method - /** - * Returns all registered action names. - */ - public String[] getActionNames() - { - if(actionNames == null) - { - List vec = new LinkedList(); - for(int i = 0; i < actionSets.size(); i++) - (actionSets.elementAt(i)).getActionNames(vec); - - actionNames = (String[])vec.toArray( - new String[vec.size()]); - Arrays.sort(actionNames, - new MiscUtilities.StringICaseCompare()); - } - - return actionNames; - } //}}} - - //{{{ Package-private members - String[] actionNames; - Hashtable<String, ActionSet> actionHash = new Hashtable<String, ActionSet>(); - - /** A map of built-in actions that were overridden by plugins. */ - Hashtable<String, ActionSet> overriddenActions = new Hashtable<String, ActionSet>(); - //}}} - - //{{{ Private members - private Vector<ActionSet> actionSets = new Vector<ActionSet>(); - //}}} } Modified: jEdit/trunk/org/gjt/sp/jedit/ActionListHandler.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/ActionListHandler.java 2007-12-12 17:02:02 UTC (rev 11401) +++ jEdit/trunk/org/gjt/sp/jedit/ActionListHandler.java 2007-12-12 19:41:18 UTC (rev 11402) @@ -35,19 +35,24 @@ import org.gjt.sp.util.XMLUtilities; //}}} +/** + * This class loads the actions.xml files into a {@link JEditActionSet}. * @author Slava Pestov + * @author Mike Dillon + */ class ActionListHandler extends DefaultHandler { //{{{ ActionListHandler constructor - ActionListHandler(String path, ActionSet actionSet) + ActionListHandler(String path, JEditActionSet actionSet) { this.path = path; this.actionSet = actionSet; - stateStack = new Stack(); - code = new StringBuffer(); - isSelected = new StringBuffer(); + stateStack = new Stack<String>(); + code = new StringBuilder(); + isSelected = new StringBuilder(); } //}}} //{{{ resolveEntity() method + @Override public InputSource resolveEntity(String publicId, String systemId) { return XMLUtilities.findEntity(systemId, "actions.dtd", getClass()); @@ -70,6 +75,7 @@ } //}}} //{{{ characters() method + @Override public void characters(char[] c, int off, int len) { String tag = peekElement(); @@ -84,6 +90,7 @@ } //}}} //{{{ startElement() method + @Override public void startElement(String uri, String localName, String qName, Attributes attrs) { @@ -101,6 +108,7 @@ } //}}} //{{{ endElement() method + @Override public void endElement(String uri, String localName, String qName) { String tag = peekElement(); @@ -111,9 +119,14 @@ { String selected = (isSelected.length() > 0) ? isSelected.toString() : null; - actionSet.addAction(new BeanShellAction(actionName, - code.toString(),selected, - noRepeat,noRecord,noRememberLast)); + JEditAbstractEditAction action = + actionSet.createBeanShellAction(actionName, + code.toString(), + selected, + noRepeat, + noRecord, + noRememberLast); + actionSet.addAction(action); noRepeat = noRecord = noRememberLast = false; code.setLength(0); isSelected.setLength(0); @@ -129,6 +142,7 @@ } //}}} //{{{ startDocument() method + @Override public void startDocument() { try @@ -137,7 +151,7 @@ } catch (Exception e) { - e.printStackTrace(); + Log.log(Log.ERROR,this, e); } } //}}} @@ -145,17 +159,17 @@ //{{{ Instance variables private String path; - private ActionSet actionSet; + private JEditActionSet actionSet; private String actionName; - private StringBuffer code; - private StringBuffer isSelected; + private final StringBuilder code; + private final StringBuilder isSelected; private boolean noRepeat; private boolean noRecord; private boolean noRememberLast; - private Stack stateStack; + private final Stack<String> stateStack; //}}} //{{{ pushElement() method @@ -171,15 +185,14 @@ //{{{ peekElement() method private String peekElement() { - return (String) stateStack.peek(); + return stateStack.peek(); } //}}} //{{{ popElement() method private String popElement() { - return (String) stateStack.pop(); + return stateStack.pop(); } //}}} //}}} - } Modified: jEdit/trunk/org/gjt/sp/jedit/ActionSet.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/ActionSet.java 2007-12-12 17:02:02 UTC (rev 11401) +++ jEdit/trunk/org/gjt/sp/jedit/ActionSet.java 2007-12-12 19:41:18 UTC (rev 11402) @@ -22,13 +22,14 @@ package org.gjt.sp.jedit; +//{{{ imports import java.io.*; import java.net.URL; import java.util.*; -import org.gjt.sp.jedit.gui.InputHandler; +import org.gjt.sp.jedit.input.AbstractInputHandler; import org.gjt.sp.util.Log; -import org.gjt.sp.util.XMLUtilities; +//}}} /** * A set of actions, either loaded from an XML file, or constructed at runtime @@ -141,7 +142,7 @@ * @version $Id$ * @since jEdit 4.0pre1 */ -public class ActionSet +public class ActionSet extends JEditActionSet<EditAction> { //{{{ ActionSet constructor /** @@ -150,11 +151,9 @@ */ public ActionSet() { - actions = new Hashtable(); - loaded = true; label = "<no label set; plugin bug>"; } //}}} - + //{{{ ActionSet constructor /** * Creates a new action set. @@ -182,6 +181,39 @@ } loaded = false; } //}}} + + //{{{ addAction() method + /** + * Adds an action to the action set. + * It exists for binary compatibility issues + * @param action The action + * @since jEdit 4.0pre1 + */ + @Override + public void addAction(EditAction action) + { + super.addAction(action); + } //}}} + + //{{{ getArray() method + protected EditAction[] getArray(int size) + { + return new EditAction[size]; + } //}}} + + //{{{ getActions() method + /** + * Returns an array of all actions in this action set.<p> + * + * <b>Deferred loading:</b> this will load the action set if necessary. + * + * @since jEdit 4.0pre1 + */ + @Override + public EditAction[] getActions() + { + return super.getActions(); + } //}}} //{{{ ActionSet constructor /** @@ -228,119 +260,16 @@ return plugin; } //}}} - //{{{ addAction() method - /** - * Adds an action to the action set. - * @param action The action - * @since jEdit 4.0pre1 - */ - public void addAction(EditAction action) - { - actions.put(action.getName(),action); - if(context != null) - { - context.actionNames = null; - context.actionHash.put(action.getName(),this); - } - } //}}} - - //{{{ removeAction() method - /** - * Removes an action from the action set. - * @param name The action name - * @since jEdit 4.0pre1 - */ - public void removeAction(String name) - { - actions.remove(name); - if(context != null) - { - context.actionNames = null; - context.actionHash.remove(name); - } - } //}}} - - //{{{ removeAllActions() method - /** - * Removes all actions from the action set. - * @since jEdit 4.0pre1 - */ - public void removeAllActions() - { - if(context != null) - { - context.actionNames = null; - String[] actions = getActionNames(); - for(int i = 0; i < actions.length; i++) - { - context.actionHash.remove(actions[i]); - } - } - this.actions.clear(); - } //}}} - - //{{{ getAction() method - /** - * Returns an action with the specified name.<p> - * - * <b>Deferred loading:</b> this will load the action set if necessary. - * - * @param name The action name - * @since jEdit 4.0pre1 - */ - public EditAction getAction(String name) - { - Object obj = actions.get(name); - if(obj == placeholder) - { - load(); - obj = actions.get(name); - if(obj == placeholder) - { - Log.log(Log.WARNING,this,"Outdated cache"); - obj = null; - } - } - - return (EditAction)obj; - } //}}} - - //{{{ getActionCount() method - /** - * Returns the number of actions in the set. - * @since jEdit 4.0pre1 - */ - public int getActionCount() - { - return actions.size(); - } //}}} - - //{{{ getActionNames() method - /** - * Returns an array of all action names in this action set. - * @since jEdit 4.2pre1 - */ - public String[] getActionNames() - { - String[] retVal = new String[actions.size()]; - Enumeration e = actions.keys(); - int i = 0; - while(e.hasMoreElements()) - { - retVal[i++] = (String)e.nextElement(); - } - return retVal; - } //}}} - //{{{ getCacheableActionNames() method /** * Returns an array of all action names in this action set that should * be cached; namely, <code>BeanShellAction</code>s. * @since jEdit 4.2pre1 */ + @Override public String[] getCacheableActionNames() { - LinkedList retVal = new LinkedList(); + LinkedList<String> retVal = new LinkedList<String>(); Enumeration e = actions.elements(); while(e.hasMoreElements()) { @@ -355,142 +284,46 @@ else if(obj instanceof BeanShellAction) retVal.add(((BeanShellAction)obj).getName()); } - return (String[])retVal.toArray(new String[retVal.size()]); + return retVal.toArray(new String[retVal.size()]); } //}}} - - //{{{ getActions() method - /** - * Returns an array of all actions in this action set.<p> - * - * <b>Deferred loading:</b> this will load the action set if necessary. - * - * @since jEdit 4.0pre1 - */ - public EditAction[] getActions() + + //{{{ getProperty() method + protected String getProperty(String name) { - load(); - - EditAction[] retVal = new EditAction[actions.size()]; - Enumeration e = actions.elements(); - int i = 0; - while(e.hasMoreElements()) - { - retVal[i++] = (EditAction)e.nextElement(); - } - return retVal; + return jEdit.getProperty(name); } //}}} - - //{{{ contains() method - /** - * Returns if this action set contains the specified action. - * @param action The action - * @since jEdit 4.2pre1 - */ - public boolean contains(String action) + + //{{{ getInputHandler() method + public AbstractInputHandler getInputHandler() { - boolean retval = actions.containsKey(action); - return retval; -// return actions.containsKey(action); + return jEdit.getInputHandler(); } //}}} - //{{{ size() method - /** - * Returns the number of actions in this action set. - * @since jEdit 4.2pre2 - */ - public int size() - { - return actions.size(); - } //}}} - //{{{ toString() method + @Override public String toString() { return label; } //}}} - - //{{{ initKeyBindings() method + + //{{{ createBeanShellAction() method /** - * Initializes the action set's key bindings. - * jEdit calls this method for all registered action sets when the - * user changes key bindings in the <b>Global Options</b> dialog box.<p> - * - * Note if your plugin adds a custom action set to jEdit's collection, - * it must also call this method on the action set after adding it. - * - * @since jEdit 4.2pre1 + * Creates a BeanShellAction. + * @since 4.3pre13 */ - public void initKeyBindings() + protected EditAction createBeanShellAction(String actionName, + String code, + String selected, + boolean noRepeat, + boolean noRecord, + boolean noRememberLast) { - InputHandler inputHandler = jEdit.getInputHandler(); - - Iterator iter = actions.entrySet().iterator(); - while(iter.hasNext()) - { - Map.Entry entry = (Map.Entry)iter.next(); - String name = (String)entry.getKey(); - - String shortcut1 = jEdit.getProperty(name + ".shortcut"); - if(shortcut1 != null) - inputHandler.addKeyBinding(shortcut1,name); - - String shortcut2 = jEdit.getProperty(name + ".shortcut2"); - if(shortcut2 != null) - inputHandler.addKeyBinding(shortcut2,name); - } - } //}}} - - //{{{ load() method - /** - * Forces the action set to be loaded. Plugins and macros should not - * call this method. - * @since jEdit 4.2pre1 - */ - public void load() - { - if(loaded) - return; - - loaded = true; - //actions.clear(); - - Reader stream = null; - - try - { - Log.log(Log.DEBUG,this,"Loading actions from " + uri); - ActionListHandler ah = new ActionListHandler(uri.toString(),this); - if ( XMLUtilities.parseXML(uri.openStream(), ah)) { - Log.log(Log.ERROR, this, "Unable to parse: " + uri); - } - } - catch(IOException e) - { - Log.log(Log.ERROR,this,uri,e); - } - } //}}} - - //{{{ Package-private members - ActionContext context; - - //{{{ getActionNames() method - void getActionNames(List vec) - { - Enumeration e = actions.keys(); - while(e.hasMoreElements()) - vec.add(e.nextElement()); - } //}}} - + return new BeanShellAction(actionName,code,selected,noRepeat,noRecord,noRememberLast); + } //}}} //{{{ Private members private String label; - private Hashtable actions; private PluginJAR plugin; - private URL uri; - private boolean loaded; - - private static final Object placeholder = new Object(); - //}}} } Modified: jEdit/trunk/org/gjt/sp/jedit/EditAction.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/EditAction.java 2007-12-12 17:02:02 UTC (rev 11401) +++ jEdit/trunk/org/gjt/sp/jedit/EditAction.java 2007-12-12 19:41:18 UTC (rev 11402) @@ -23,11 +23,10 @@ package org.gjt.sp.jedit; //{{{ Imports +import org.gjt.sp.util.Log; +import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.Component; - -import org.gjt.sp.util.Log; //}}} /** @@ -40,15 +39,8 @@ * @author Slava Pestov * @version $Id$ */ -public abstract class EditAction +public abstract class EditAction extends JEditAbstractEditAction<View> { - //{{{ Private members - private String name; - - protected Object[] args; - - //}}} - //{{{ EditAction constructors /** * Creates a new edit action with the specified name. @@ -56,33 +48,14 @@ */ public EditAction(String name) { - this.name = name; + super(name); } - public EditAction(String name, Object[] newArgs) { - this.name = name; - this.args = newArgs; - } //}}} - - //{{{ getName() method - /** - * Returns the internal name of this action. - */ - public String getName() + public EditAction(String name, Object[] newArgs) { - return name; + super(name, newArgs); } //}}} - - // {{{ setName() method - /** - * Changes the name of an action - * @param newName - * @since jEdit 4.3pre4 - */ - public void setName(String newName) { - name = newName; - }// }}} - + //{{{ getLabel() method /** * Returns the action's label. This returns the @@ -119,17 +92,6 @@ * abstract since jEdit 4.3pre7 */ abstract public void invoke(View view); - - /** - * - * @param view - * @param newArgs new argument list - * @since jEdit 4.3pre7 - */ - final public void invoke(View view, Object[] newArgs) { - args = newArgs; - invoke(view); - } //}}} //{{{ getView() method /** @@ -216,13 +178,7 @@ return "jEdit.getAction(" + name + ").invoke(view); "; } //}}} - - //{{{ toString() method - public String toString() - { - return name; - } //}}} - + //{{{ Wrapper class /** * 'Wrap' EditActions in this class to turn them into AWT @@ -231,8 +187,8 @@ public static class Wrapper implements ActionListener { - private ActionContext context; - private String actionName; + private final ActionContext context; + private final String actionName; /** * Creates a new action listener wrapper. @@ -263,7 +219,5 @@ else context.invokeAction(evt,action); } - - } //}}} } Added: jEdit/trunk/org/gjt/sp/jedit/IPropertyManager.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/IPropertyManager.java (rev 0) +++ jEdit/trunk/org/gjt/sp/jedit/IPropertyManager.java 2007-12-12 19:41:18 UTC (rev 11402) @@ -0,0 +1,41 @@ +/* + * IPropertyManager.java - An interface for class that returns properties + * :tabSize=8:indentSize=8:noTabs=false: + * :folding=explicit:collapseFolds=1: + * + * Copyright (C) 2007 Matthieu Casanova + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package org.gjt.sp.jedit; + +import java.io.*; +import java.util.*; + +/** + * Manage properties. + * @author Matthieu Casanova + * @since 4.3pre13 + */ +public interface IPropertyManager +{ + /** + * Returns a String property + * @param name the name of the property + * @return the string property or null if it doesn't exists + */ + String getProperty(String name); +} Added: jEdit/trunk/org/gjt/sp/jedit/JEditAbstractEditAction.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/JEditAbstractEditAction.java (rev 0) +++ jEdit/trunk/org/gjt/sp/jedit/JEditAbstractEditAction.java 2007-12-12 19:41:18 UTC (rev 11402) @@ -0,0 +1,107 @@ +/* + * EditAction.java - jEdit action listener + * :tabSize=8:indentSize=8:noTabs=false: + * :folding=explicit:collapseFolds=1: + * + * Copyright (C) 1998, 2003 Slava Pestov + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package org.gjt.sp.jedit; + +/** + * An action that can be bound to a menu item, tool bar button or keystroke. + * + * @see jEdit#getAction(String) + * @see jEdit#getActionNames() + * @see ActionSet + * + * @author Slava Pestov + * @version $Id: EditAction.java 11177 2007-12-01 09:50:50Z k_satoda $ + * @since 4.3pre13 + */ +public abstract class JEditAbstractEditAction<E> +{ + //{{{ Private members + protected String name; + + protected Object[] args; + + //}}} + + //{{{ EditAction constructors + /** + * Creates a new edit action with the specified name. + * @param name The action name + */ + public JEditAbstractEditAction(String name) + { + this.name = name; + } + + public JEditAbstractEditAction(String name, Object[] newArgs) + { + this.name = name; + this.args = newArgs; + } //}}} + + //{{{ getName() method + /** + * Returns the internal name of this action. + */ + public String getName() + { + return name; + } //}}} + + // {{{ setName() method + /** + * Changes the name of an action + * @param newName + * @since jEdit 4.3pre4 + */ + public void setName(String newName) + { + name = newName; + }// }}} + + //{{{ invoke() method + /** + * Invokes the action. This is an implementation of the Command pattern, + * and concrete actions should override this. + * + * @param arg the argument + */ + abstract public void invoke(E arg); + + /** + * + * @param arg + * @param newArgs new argument list + */ + public final void invoke(E arg, Object[] newArgs) + { + args = newArgs; + invoke(arg); + } //}}} + + //{{{ toString() method + @Override + public String toString() + { + return name; + } //}}} +} Added: jEdit/trunk/org/gjt/sp/jedit/JEditActionContext.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/JEditActionContext.java (rev 0) +++ jEdit/trunk/org/gjt/sp/jedit/JEditActionContext.java 2007-12-12 19:41:18 UTC (rev 11402) @@ -0,0 +1,170 @@ +/* + * JEditActionContext.java - For code sharing between jEdit and VFSBrowser + * :tabSize=8:indentSize=8:noTabs=false: + * :folding=explicit:collapseFolds=1: + * + * Copyright (C) 1998, 2003 Slava Pestov + * Portions copyright (C) 2007 Matthieu Casanova + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package org.gjt.sp.jedit; + +import java.util.*; + +/** + * Manages a collection of action sets. There are two instances of this class + * in jEdit: + * <ul> + * <li>{@link org.gjt.sp.jedit.jEdit#getActionContext()} - editor actions + * <li>{@link org.gjt.sp.jedit.browser.VFSBrowser#getActionContext()} - browser + * actions + * </ul> + * + * @since jEdit 4.3pre13 + * @author Slava Pestov + * @version $Id: ActionContext.java 6884 2006-09-06 02:38:55Z ezust $ + */ +public abstract class JEditActionContext<F extends JEditAbstractEditAction, E extends JEditActionSet<F>> +{ + //{{{ invokeAction() method + /** + * Invokes the given action in response to a user-generated event. + * @param evt The event + * @param action The action + * @since jEdit 4.3pre13 + */ + public abstract void invokeAction(EventObject evt, F action); + //}}} + + //{{{ addActionSet() method + /** + * Adds a new action set to the context. + * @since jEdit 4.3pre13 + */ + public void addActionSet(E actionSet) + { + actionNames = null; + actionSets.addElement(actionSet); + actionSet.context = this; + String[] actions = actionSet.getActionNames(); + for(int i = 0; i < actions.length; i++) + { + /* Is it already there? */ + if (actionHash.containsKey(actions[i])) + { + /* Save it for plugin unloading time */ + E oldAction = actionHash.get(actions[i]); + overriddenActions.put(actions[i], oldAction); + } + actionHash.put(actions[i],actionSet); + } + } //}}} + + //{{{ removeActionSet() method + /** + * Removes an action set from the context. + * @since jEdit 4.23pre13 + */ + public void removeActionSet(E actionSet) + { + actionNames = null; + actionSets.removeElement(actionSet); + actionSet.context = null; + String[] actions = actionSet.getActionNames(); + for(int i = 0; i < actions.length; i++) + { + actionHash.remove(actions[i]); + if (overriddenActions.containsKey(actions[i])) + { + E oldAction = overriddenActions.remove(actions[i]); + actionHash.put(actions[i], oldAction); + } + } + } //}}} + + //{{{ getActionSets() method + /** + * Returns all registered action sets. + * @since jEdit 4.23pre13 + */ + public JEditActionSet[] getActionSets() + { + // todo : test this method + JEditActionSet[] retVal = new JEditActionSet[actionSets.size()]; + actionSets.copyInto(retVal); + return retVal; + } //}}} + + //{{{ getAction() method + /** + * Returns the specified action. + * @param name The action name + * @since jEdit 4.2pre1 + */ + public F getAction(String name) + { + E set = actionHash.get(name); + if(set == null) + return null; + else + return set.getAction(name); + } //}}} + + //{{{ getActionSetForAction() method + /** + * Returns the action set that contains the specified action. + * + * @param action The action + * @since jEdit 4.2pre1 + */ + public E getActionSetForAction(String action) + { + return actionHash.get(action); + } //}}} + + //{{{ getActionNames() method + /** + * Returns all registered action names. + */ + public String[] getActionNames() + { + if(actionNames == null) + { + List<String> vec = new LinkedList<String>(); + for(int i = 0; i < actionSets.size(); i++) + (actionSets.elementAt(i)).getActionNames(vec); + + actionNames = vec.toArray(new String[vec.size()]); + Arrays.sort(actionNames, + new MiscUtilities.StringICaseCompare()); + } + + return actionNames; + } //}}} + + //{{{ Package-private members + String[] actionNames; + Hashtable<String, E> actionHash = new Hashtable<String, E>(); + + /** A map of built-in actions that were overridden by plugins. */ + Hashtable<String, E> overriddenActions = new Hashtable<String, E>(); + //}}} + + //{{{ Private members + private final Vector<E> actionSets = new Vector<E>(); + //}}} +} Added: jEdit/trunk/org/gjt/sp/jedit/JEditActionSet.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/JEditActionSet.java (rev 0) +++ jEdit/trunk/org/gjt/sp/jedit/JEditActionSet.java 2007-12-12 19:41:18 UTC (rev 11402) @@ -0,0 +1,473 @@ +/* + * JEditActionSet.java - A set of actions + * :tabSize=8:indentSize=8:noTabs=false: + * :folding=explicit:collapseFolds=1: + * + * Copyright (C) 2001, 2003 Slava Pestov + * Portions copyright (C) 2007 Matthieu Casanova + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package org.gjt.sp.jedit; + +import java.io.*; +import java.net.URL; +import java.util.*; + +import org.gjt.sp.jedit.input.AbstractInputHandler; +import org.gjt.sp.jedit.input.InputHandlerProvider; +import org.gjt.sp.util.Log; +import org.gjt.sp.util.XMLUtilities; + +/** + * A set of actions, either loaded from an XML file, or constructed at runtime + * by a plugin. <p> + * + * <h3>Action sets loaded from XML files</h3> + * + * Action sets are read from these files inside the plugin JAR: + * <ul> + * <li><code>actions.xml</code> - actions made available for use in jEdit views, + * including the view's <b>Plugins</b> menu, the tool bar, etc.</li> + * <li><code>browser.actions.xml</code> - actions for the file system browser's + * <b>Plugins</b> menu.</li> + * </ul> + * + * An action definition file has the following form: + * + * <pre><?xml version="1.0"?> + *<!DOCTYPE ACTIONS SYSTEM "actions.dtd"> + *<ACTIONS> + * <ACTION NAME="some-action"> + * <CODE> + * // BeanShell code evaluated when the action is invoked + * </CODE> + * </ACTION> + * <ACTION NAME="some-toggle-action"> + * <CODE> + * // BeanShell code evaluated when the action is invoked + * </CODE> + * <IS_SELECTED> + * // BeanShell code that should evaluate to true or false + * </IS_SELECTED> + * </ACTION> + *</ACTIONS></pre> + * + * The following elements are valid: + * + * <ul> + * <li> + * <code>ACTIONS</code> is the top-level element and refers + * to the set of actions used by the plugin. + * </li> + * <li> + * An <code>ACTION</code> contains the data for a particular action. + * It has three attributes: a required <code>NAME</code>; + * an optional <code>NO_REPEAT</code>, which is a flag + * indicating whether the action should not be repeated with the + * <b>C+ENTER</b> command; and an optional + * <code>NO_RECORD</code> which is a a flag indicating whether the + * action should be recorded if it is invoked while the user is recording a + * macro. The two flag attributes + * can have two possible values, "TRUE" or + * "FALSE". In both cases, "FALSE" is the + * default if the attribute is not specified. + * </li> + * <li> + * An <code>ACTION</code> can have two child elements + * within it: a required <code>CODE</code> element which + * specifies the + * BeanShell code that will be executed when the action is invoked, + * and an optional <code>IS_SELECTED</code> element, used for + * checkbox + * menu items. The <code>IS_SELECTED</code> element contains + * BeanShell code that returns a boolean flag that will + * determine the state of the checkbox. + * </li> + * </ul> + * + * Each action must have a property <code><i>name</i>.label</code> containing + * the action's menu item label. + * + * <h3>View actions</h3> + * + * Actions defined in <code>actions.xml</code> can be added to the view's + * <b>Plugins</b> menu; see {@link EditPlugin}. + * The action code may use any standard predefined + * BeanShell variable; see {@link BeanShell}. + * + * <h3>File system browser actions</h3> + * + * Actions defined in <code>actions.xml</code> can be added to the file + * system browser's <b>Plugins</b> menu; see {@link EditPlugin}. + * The action code may use any standard predefined + * BeanShell variable, in addition to a variable <code>browser</code> which + * contains a reference to the current + * {@link org.gjt.sp.jedit.browser.VFSBrowser} instance.<p> + * + * File system browser actions should not define + * <code><IS_SELECTED></code> blocks. + * + * <h3>Custom action sets</h3> + * + * Call {@link jEdit#addActionSet(ActionSet)} to add a custom action set to + * jEdit's action context. You must also call {@link #initKeyBindings()} for new + * action sets. Don't forget to call {@link jEdit#removeActionSet(ActionSet)} + * before your plugin is unloaded, too. + * + * @see jEdit#getActionContext() + * @see org.gjt.sp.jedit.browser.VFSBrowser#getActionContext() + * @see ActionContext#getActionNames() + * @see ActionContext#getAction(String) + * @see jEdit#addActionSet(ActionSet) + * @see jEdit#removeActionSet(ActionSet) + * @see PluginJAR#getActionSet() + * @see BeanShell + * @see View + * + * @author Slava Pestov + * @author John Gellene (API documentation) + * @version $Id: ActionSet.java 9529 2007-05-12 15:06:52Z ezust $ + * @since jEdit 4.3pre13 + */ +public abstract class JEditActionSet<E extends JEditAbstractEditAction> implements InputHandlerProvider +{ + //{{{ JEditActionSet constructor + /** + * Creates a new action set. + * @since jEdit 4.3pre13 + */ + public JEditActionSet() + { + actions = new Hashtable<String, Object>(); + loaded = true; + } //}}} + + //{{{ JEditActionSet constructor + /** + * Creates a new action set. + * @param cachedActionNames The list of cached action names + * @param uri The actions.xml URI + * @since jEdit 4.3pre13 + */ + public JEditActionSet(String[] cachedActionNames, URL uri) + { + this(); + this.uri = uri; + if(cachedActionNames != null) + { + for(int i = 0; i < cachedActionNames.length; i++) + { + actions.put(cachedActionNames[i],placeholder); + } + } + loaded = false; + } //}}} + + //{{{ addAction() method + /** + * Adds an action to the action set. + * @param action The action + * @since jEdit 4.0pre1 + */ + public void addAction(E action) + { + actions.put(action.getName(),action); + if(context != null) + { + context.actionNames = null; + context.actionHash.put(action.getName(),this); + } + } //}}} + + //{{{ removeAction() method + /** + * Removes an action from the action set. + * @param name The action name + * @since jEdit 4.0pre1 + */ + public void removeAction(String name) + { + actions.remove(name); + if(context != null) + { + context.actionNames = null; + context.actionHash.remove(name); + } + } //}}} + + //{{{ removeAllActions() method + /** + * Removes all actions from the action set. + * @since jEdit 4.0pre1 + */ + public void removeAllActions() + { + if(context != null) + { + context.actionNames = null; + String[] actions = getActionNames(); + for(int i = 0; i < actions.length; i++) + { + context.actionHash.remove(actions[i]); + } + } + this.actions.clear(); + } //}}} + + //{{{ getAction() method + /** + * Returns an action with the specified name.<p> + * + * <b>Deferred loading:</b> this will load the action set if necessary. + * + * @param name The action name + * @since jEdit 4.0pre1 + */ + public E getAction(String name) + { + Object obj = actions.get(name); + if(obj == placeholder) + { + load(); + obj = actions.get(name); + if(obj == placeholder) + { + Log.log(Log.WARNING,this,"Outdated cache"); + obj = null; + } + } + + return (E) obj; + } //}}} + + //{{{ getActionCount() method + /** + * Returns the number of actions in the set. + * @since jEdit 4.0pre1 + */ + public int getActionCount() + { + return actions.size(); + } //}}} + + //{{{ getActionNames() method + /** + * Returns an array of all action names in this action set. + * @since jEdit 4.2pre1 + */ + public String[] getActionNames() + { + String[] retVal = new String[actions.size()]; + Enumeration e = actions.keys(); + int i = 0; + while(e.hasMoreElements()) + { + retVal[i++] = (String)e.nextElement(); + } + return retVal; + } //}}} + + //{{{ getCacheableActionNames() method + /** + * Returns an array of all action names in this action set that should + * be cached; namely, <code>BeanShellAction</code>s. + * @since jEdit 4.2pre1 + */ + public String[] getCacheableActionNames() + { + LinkedList<String> retVal = new LinkedList<String>(); + Enumeration e = actions.elements(); + while(e.hasMoreElements()) + { + Object obj = e.nextElement(); + if(obj == placeholder) + { + // ??? this should only be called with + // fully loaded action set + Log.log(Log.WARNING,this,"Action set not up " + + "to date"); + } + else if(obj instanceof JEditBeanShellAction) + retVal.add(((JEditBeanShellAction)obj).getName()); + } + return retVal.toArray(new String[retVal.size()]); + } //}}} + + //{{{ getArray() method + /** + * Returns an empty array E[]. + * I know it is bad, if you find a method to instantiate a generic Array, + * tell me + * @param size the size of the array + * @return the empty array + */ + protected abstract E[] getArray(int size); + //}}} + + //{{{ getActions() method + /** + * Returns an array of all actions in this action set.<p> + * + * <b>Deferred loading:</b> this will load the action set if necessary. + * + * @since jEdit 4.0pre1 + */ + public E[] getActions() + { + load(); + E[] retVal = getArray(actions.size()); + Enumeration e = actions.elements(); + int i = 0; + while(e.hasMoreElements()) + { + retVal[i++] = (E) e.nextElement(); + } + return (E[]) retVal; + } //}}} + + //{{{ contains() method + /** + * Returns if this action set contains the specified action. + * @param action The action + * @since jEdit 4.2pre1 + */ + public boolean contains(String action) + { + boolean retval = actions.containsKey(action); + return retval; +// return actions.containsKey(action); + } //}}} + + //{{{ size() method + /** + * Returns the number of actions in this action set. + * @since jEdit 4.2pre2 + */ + public int size() + { + return actions.size(); + } //}}} + + //{{{ load() method + /** + * Forces the action set to be loaded. Plugins and macros should not + * call this method. + * @since jEdit 4.2pre1 + */ + public void load() + { + if(loaded) + return; + + loaded = true; + //actions.clear(); + + if (uri == null) + return; + try + { + Log.log(Log.DEBUG,this,"Loading actions from " + uri); + ActionListHandler ah = new ActionListHandler(uri.toString(),this); + if ( XMLUtilities.parseXML(uri.openStream(), ah)) { + Log.log(Log.ERROR, this, "Unable to parse: " + uri); + } + } + catch(IOException e) + { + Log.log(Log.ERROR,this,uri,e); + } + } //}}} + + //{{{ createBeanShellAction() method + /** + * This method should be implemented to return an action that will execute + * the given code + * @since 4.3pre13 + */ + protected abstract JEditAbstractEditAction createBeanShellAction(String actionName, + String code, + String selected, + boolean noRepeat, + boolean noRecord, + boolean noRememberLast); + //}}} + + //{{{ initKeyBindings() method + /** + * Initializes the action set's key bindings. + * jEdit calls this method for all registered action sets when the + * user changes key bindings in the <b>Global Options</b> dialog box.<p> + * + * Note if your plugin adds a custom action set to jEdit's collection, + * it must also call this method on the action set after adding it. + * + * @since jEdit 4.2pre1 + */ + public void initKeyBindings() + { + AbstractInputHandler inputHandler = getInputHandler(); + + Iterator<Map.Entry<String,Object>> iter = actions.entrySet().iterator(); + while(iter.hasNext()) + { + Map.Entry<String,Object> entry = iter.next(); + String name = entry.getKey(); + + String shortcut1 = getProperty(name + ".shortcut"); + if(shortcut1 != null) + inputHandler.addKeyBinding(shortcut1,name); + + String shortcut2 = getProperty(name + ".shortcut2"); + if(shortcut2 != null) + inputHandler.addKeyBinding(shortcut2,name); + } + } //}}} + + //{{{ getProperty() method + /** + * Returns a property for the given name. + * In jEdit it will returns a jEdit.getProperty(name), but it can + * return something else for a standalone textarea. + * @param name the property name + * @return the property value + * @since 4.3pre13 + */ + protected abstract String getProperty(String name); + //}}} + + //{{{ Package-private members + JEditActionContext context; + + //{{{ getActionNames() method + void getActionNames(List<String> vec) + { + Enumeration<String> e = actions.keys(); + while(e.hasMoreElements()) + vec.add(e.nextElement()); + } //}}} + + //}}} + + //{{{ Private members + protected Hashtable<String,Object> actions; + protected URL uri; + protected boolean loaded; + + protected static final Object placeholder = new Object(); + + //}}} +} Added: jEdit/trunk/org/gjt/sp/jedit/JEditBeanShell.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/JEditBeanShell.java (rev 0) +++ jEdit/trunk/org/gjt/sp/jedit/JEditBeanShell.java 2007-12-12 19:41:18 UTC (rev 11402) @@ -0,0 +1,428 @@ +/* + * BeanShell.java - BeanShell scripting support + * :tabSize=8:indentSize=8:noTabs=false: + * :folding=explicit:collapseFolds=1: + * + * Copyright (C) 2000, 2004 Slava Pestov + * Portions Copyright (C) 2007 Matthieu Casanova + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package org.gjt.sp.jedit; + +//{{{ Imports +import org.gjt.sp.jedit.bsh.*; +import org.gjt.sp.jedit.bsh.classpath.ClassManagerImpl; + +import java.io.*; +import java.lang.ref.*; +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import org.gjt.sp.jedit.io.*; +import org.gjt.sp.jedit.gui.BeanShellErrorDialog; +import org.gjt.sp.jedit.textarea.*; +import org.gjt.sp.util.Log; +//}}} + +/** + * BeanShell is jEdit's extension language.<p> + * + * When run from jEdit, BeanShell code has access to the following predefined + * variables: + * + * <ul> + * <li><code>view</code> - the currently active {@link View}.</li> + * <li><code>editPane</code> - the currently active {@link EditPane}.</li> + * <li><code>textArea</code> - the edit pane's {@link JEditTextArea}.</li> + * <li><code>buffer</code> - the edit pane's {@link Buffer}.</li> + * <li><code>wm</code> - the view's {@link + * org.gjt.sp.jedit.gui.DockableWindowManager}.</li> + * <li><code>scriptPath</code> - the path name of the currently executing + * BeanShell script.</li> + * </ul> + * + * @author Slava Pestov + * @version $Id: BeanShell.java 10803 2007-10-04 20:45:31Z kpouer $ + */ +public class JEditBeanShell +{ + //{{{ static initializer + static + { + // Initialize JEditBeanShell only if needed + // It is used mostly for the standalone textarea + init(); + } //}}} + + + //{{{ evalSelection() method + /** + * Evaluates the text selected in the specified text area. + * @since jEdit 2.7pre2 + */ + public static void evalSelection(TextArea textArea) + { + String command = textArea.getSelectedText(); + if(command == null) + { + textArea.getToolkit().beep(); + return; + } + Object returnValue = eval(textArea,global,command); + if(returnValue != null) + textArea.setSelectedText(returnValue.toString()); + } //}}} + + //{{{ eval() method + /** + * Evaluates the specified BeanShell expression. Errors are reported in + * a dialog box. + * @param view The view. Within the script, references to + * <code>buffer</code>, <code>textArea</code> and <code>editPane</code> + * are determined with reference to this parameter. + * @param namespace The namespace + * @param command The expression + * @since jEdit 4.0pre8 + */ + public static Object eval(TextArea textArea, NameSpace namespace, String command) + { + try + { + return _eval(textArea,namespace,command); + } + catch(Throwable e) + { + Log.log(Log.ERROR,JEditBeanShell.class,e); + + handleException(textArea,null,e); + } + + return null; + } //}}} + + //{{{ _eval() method + /** + * Evaluates the specified BeanShell expression. Unlike + * <code>eval()</code>, this method passes any exceptions to the caller. + * + * @param view The view. Within the script, references to + * <code>buffer</code>, <code>textArea</code> and <code>editPane</code> + * are determined with reference to this parameter. + * @param namespace The namespace + * @param command The expression + * @exception Exception instances are thrown when various BeanShell + * errors occur + * @since jEdit 3.2pre7 + */ + public static Object _eval(TextArea textArea, NameSpace namespace, String command) + throws Exception + { + Interpreter interp = createInterpreter(namespace); + + try + { + setupDefaultVariables(namespace,textArea); + if(Debug.BEANSHELL_DEBUG) + Log.log(Log.DEBUG,JEditBeanShell.class,command); + return interp.eval(command); + } + catch(Exception e) + { + unwrapException(e); + // never called + return null; + } + finally + { + try + { + resetDefaultVariables(namespace); + } + catch(UtilEvalError e) + { + // do nothing + } + } + } //}}} + + //{{{ cacheBlock() method + /** + * Caches a block of code, returning a handle that can be passed to + * runCachedBlock(). + * @param id An identifier. If null, a unique identifier is generated + * @param code The code + * @param namespace If true, the namespace will be set + * @exception Exception instances are thrown when various BeanShell errors + * occur + * @since jEdit 4.1pre1 + */ + public static BshMethod cacheBlock(String id, String code, boolean namespace) + throws Exception + { + String name = "__internal_" + id; + + // evaluate a method declaration + if(namespace) + { + _eval(null,global,name + "(ns) {\nthis.callstack.set(0,ns);\n" + code + "\n}"); + return global.getMethod(name,new Class[] { NameSpace.class }); + } + else + { + _eval(null,global,name + "() {\n" + code + "\n}"); + return global.getMethod(name,new Class[0]); + } + } //}}} + + //{{{ runCachedBlock() method + /** + * Runs a cached block of code in the specified namespace. Faster than + * evaluating the block each time. + * @param method The method instance returned by cacheBlock() + * @param view The view + * @param namespace The namespace to run the code in + * @exception Exception instances are thrown when various BeanShell + * errors occur + * @since jEdit 4.1pre1 + */ + public static Object runCachedBlock(BshMethod method, TextArea textArea, + NameSpace namespace) throws Exception + { + boolean useNamespace; + if(namespace == null) + { + useNamespace = false; + namespace = global; + } + else + useNamespace = true; + + try + { + setupDefaultVariables(namespace,textArea); + + Object retVal = method.invoke(useNamespace + ? new Object[] { namespace } + : NO_ARGS, + interpForMethods,new CallStack(), null); + if(retVal instanceof Primitive) + { + if(retVal == Primitive.VOID) + return null; + else + return ((Primitive)retVal).getValue(); + } + else + return retVal; + } + catch(Exception e) + { + unwrapException(e); + // never called + return null; + } + finally + { + resetDefaultVariables(namespace); + } + } //}}} + + //{{{ isScriptRunning() method + /** + * Returns if a BeanShell script or macro is currently running. + * @since jEdit 2.7pre2 + */ + public static boolean isScriptRunning() + { + return running; + } //}}} + + //{{{ getNameSpace() method + /** + * Returns the global namespace. + * @since jEdit 3.2pre5 + */ + public static NameSpace getNameSpace() + { + return global; + } //}}} + + //{{{ Package-private members + + //{{{ init() method + static void init() + { + classManager = new ClassManagerImpl(); + classManager.setClassLoader(new JARClassLoader()); + + global = new NameSpace(classManager, + "jEdit embedded BeanShell interpreter"); + global.importPackage("org.gjt.sp.jedit"); + global.importPackage("org.gjt.sp.jedit.buffer"); + global.importPackage("org.gjt.sp.jedit.syntax"); + global.importPackage("org.gjt.sp.jedit.textarea"); + global.importPackage("org.gjt.sp.util"); + + interpForMethods = createInterpreter(global); + } //}}} + + //{{{ resetClassManager() method + /** + * Causes BeanShell internal structures to drop references to cached + * Class instances. + */ + static void resetClassManager() + { + classManager.reset(); + } //}}} + + //}}} + + //{{{ Private members + + //{{{ Static variables + private static final Object[] NO_ARGS = new Object[0]; + private static BshClassManager classManager; + private static Interpreter interpForMethods; + private static NameSpace global; + private static boolean running; + //}}} + + //{{{ setupDefaultVariables() method + private static void setupDefaultVariables(NameSpace namespace, TextArea textArea) + throws UtilEvalError + { + if(textArea != null) + { + namespace.setVariable("buffer",textArea.getBuffer(), false); + namespace.setVariable("textArea",textArea, false); + } + } //}}} + + //{{{ resetDefaultVariables() method + private static void resetDefaultVariables(NameSpace namespace) + throws UtilEvalError + { + namespace.setVariable("buffer",null, false); + namespace.setVariable("textArea",null, false); + } //}}} + + //{{{ unwrapException() method + /** + * This extracts an exception from a 'wrapping' exception, as BeanShell + * sometimes throws. This gives the user a more accurate error traceback + */ + private static void unwrapException(Exception e) throws Exception + { + if(e instanceof TargetError) + { + Throwable t = ((TargetError)e).getTarget(); + if(t instanceof Exception) + throw (Exception)t; + else if(t instanceof Error) + throw (Error)t; + } + + if(e instanceof InvocationTargetException) + { + Throwable t = ((InvocationTargetException)e).getTargetException(); + if(t instanceof Exception) + throw (Exception)t; + else if(t instanceof Error) + throw (Error)t; + } + + throw e; + } //}}} + + //{{{ handleException() method + private static void handleException(TextArea textArea, String path, Throwable t) + { + new BeanShellErrorDialog(null,t); + } //}}} + + //{{{ createInterpreter() method + private static Interpreter createInterpreter(NameSpace nameSpace) + { + return new Interpreter(null,System.out,System.err,false,nameSpace); + } //}}} + + //}}} + + //{{{ CustomClassManager class + static class CustomClassManager extends ClassManagerImpl + { + private LinkedList listeners = new LinkedList(); + private ReferenceQueue refQueue = new ReferenceQueue(); + + // copy and paste from bsh/classpath/ClassManagerImpl.java... + @Override + public synchronized void addListener(Listener l) + { + listeners.add( new WeakReference( l, refQueue) ); + + // clean up old listeners + Reference deadref; + while ( (deadref = refQueue.poll()) != null ) + { + boolean ok = listeners.remove( deadref ); + if ( ok ) + { + //System.err.println("cleaned up weak ref: "+deadref); + } + else + { + if ( Interpreter.DEBUG ) Interpreter.debug( + "tried to remove non-existent weak ref: "+deadref); + } + } + } + + @Override + public void removeListener( Listener l ) + { + throw new Error("unimplemented"); + } + + @Override + public void reset() + { + classLoaderChanged(); + } + + @Override + protected synchronized void classLoaderChanged() + { + // clear the static caches in BshClassManager + clearCaches(); + if (listeners != null) + { + + for (Iterator iter = listeners.iterator(); + iter.hasNext(); ) + { + WeakReference wr = (WeakReference) + iter.next(); + Listener l = (Listener)wr.get(); + if ( l == null ) // garbage collected + iter.remove(); + else + l.classLoaderChanged(); + } + } + } + } //}}} +} Added: jEdit/trunk/org/gjt/sp/jedit/JEditBeanShellAction.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/JEditBeanShellAction.java (rev 0) +++ jEdit/trunk/org/gjt/sp/jedit/JEditBeanShellAction.java 2007-12-12 19:41:18 UTC (rev 11402) @@ -0,0 +1,174 @@ +/* + * BeanShellAction.java - BeanShell action + * :tabSize=8:indentSize=8:noTabs=false: + * :folding=explicit:collapseFolds=1: + * + * Copyright (C) 2000, 2003 Slava Pestov + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package org.gjt.sp.jedit; + +import org.gjt.sp.jedit.bsh.*; +import java.awt.Component; +import org.gjt.sp.jedit.textarea.TextArea; +import org.gjt.sp.util.Log; + +/** + * An action that evaluates BeanShell code when invoked. BeanShell actions are + * usually loaded from <code>actions.xml</code> and + * <code>browser.actions.xml</code> files; see {@link ActionSet} for syntax + * information. + * + * @see jEdit#getAction(String) + * @see jEdit#getActionNames() + * @see ActionSet + * + * @author Slava Pestov + * @version $Id: BeanShellAction.java 10803 2007-10-04 20:45:31Z kpouer $ + */ +public class JEditBeanShellAction extends JEditAbstractEditAction<TextArea> +{ + //{{{ BeanShellAction constructor + public JEditBeanShellAction(String name, String code, String isSelected, + boolean noRepeat, boolean noRecord, boolean noRememberLast) + { + super(name); + + this.code = code; + this.isSelected = isSelected; + this.noRepeat = noRepeat; + this.noRecord = noRecord; + this.noRememberLast = noRememberLast; + + /* Some characters that we like to use in action names + * ('.', '-') are not allowed in BeanShell identifiers. */ + sanitizedName = name.replace('.','_').replace('-','_'); + } //}}} + + //{{{ invoke() method + public void invoke(TextArea textArea) + { + try + { + if(cachedCode == null) + { + String cachedCodeName = "action_" + sanitizedName; + cachedCode = JEditBeanShell.cacheBlock(cachedCodeName,code,true); + } + + JEditBeanShell.runCachedBlock(cachedCode,textArea, + new NameSpace(JEditBeanShell.getNameSpace(), + "BeanShellAction.invoke()")); + } + catch(Throwable e) + { + Log.log(Log.ERROR,this,e); + } + } //}}} + + //{{{ isSelected() method + public boolean isSelected(Component comp) + { + if(isSelected == null) + return false; + + NameSpace global = JEditBeanShell.getNameSpace(); + + try + { + if(cachedIsSelected == null) + { + String cachedIsSelectedName = "selected_" + sanitizedName; + cachedIsSelected = JEditBeanShell.cacheBlock(cachedIsSelectedName, + isSelected,true); + } + + // undocumented hack to allow browser actions to work. + // XXX - clean up in 4.3 + global.setVariable("_comp",comp); + + return Boolean.TRUE.equals(JEditBeanShell.runCachedBlock( + cachedIsSelected,null, + new NameSpace(JEditBeanShell.getNameSpace(), + "BeanShellAction.isSelected()"))); + } + catch(Throwable e) + { + Log.log(Log.ERROR,this,e); + + // dialogs fuck things up if a menu is visible, etc! + //new BeanShellErrorDialog(view,e); + + // so that in the future we don't see streams of + // exceptions + isSelected = null; + + return false; + } + finally + { + try + { + global.setVariable("_comp",null); + } + catch(UtilEvalError err) + { + Log.log(Log.ERROR,this,err); + } + } + } //}}} + + //{{{ noRepeat() method + public boolean noRepeat() + { + return noRepeat; + } //}}} + + //{{{ noRecord() method + public boolean noRecord() + { + return noRecord; + } //}}} + + //{{{ noRememberLast() method + /** + * Returns if this edit action should not be remembered as the most + * recently invoked action. + * @since jEdit 4.2pre1 + */ + public boolean noRememberLast() + { + return noRememberLast; + } //}}} + + //{{{ getCode() method + public String getCode() + { + return code.trim(); + } //}}} + + //{{{ Private members + private boolean noRepeat; + private boolean noRecord; + private boolean noRememberLast; + private String code; + private String isSelected; + private BshMethod cachedCode; + private BshMethod cachedIsSelected; + private String sanitizedName; + //}}} +} Modified: jEdit/trunk/org/gjt/sp/jedit/gui/DefaultInputHandler.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/gui/DefaultInputHandler.java 2007-12-12 17:02:02 UTC (rev 11401) +++ jEdit/trunk/org/gjt/sp/jedit/gui/DefaultInputHandler.java 2007-12-12 19:41:18 UTC (rev 11402) @@ -26,7 +26,6 @@ import java.awt.event.InputEvent; import java.awt.Toolkit; import java.util.Hashtable; -import java.util.StringTokenizer; import org.gjt.sp.jedit.*; //}}} @@ -79,198 +78,19 @@ this(view,copy.bindings); } //}}} - //{{{ addKeyBinding() method - /** - * Adds a key binding to this input handler. The key binding is - * a list of white space separated key strokes of the form - * <i>[modifiers+]key</i> where modifier is C for Control, A for Alt, - * or S for Shift, and key is either a character (a-z) or a field - * name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE) - * @param keyBinding Th... [truncated message content] |