trunk contents moved to root

This commit is contained in:
Jindra Petřík
2014-05-10 20:50:57 +02:00
parent 1b851e66a8
commit 199a4d0c2b
2296 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
Version 0.9.5 - Java Reflection Completions additions
* Configuration class overhaul. Each kit now has its own COnfiguration file
which merges the superclass(es) Configurations.
* Usable Reflect Completions Dialog (Java with F1 or Menu)
* Java ENTER key responds properly to multi line comments
* Font can be changed for each Kit
* Kits for XHTML and Xpath added. XHTML has a simple Preview Action.
* Added Execute Script to JacaScript (can also be used for Groovy if Groovy
Scripting support is installed properly).
* Hotkeys for actions are displayed in Popup Menus
* Word Completion action can also do CamelCase matches
* Smart Home Action (and Smart Home Extend Selection)
* Enhanced JavaScript support. Issue 115
* Better Undo grouping
* Replace DIalog ENhancement. Only for updatedable editors and added single replace.
* Added append method to SyntaxDocument
* Fixed Issue 130 - Compound Undo on multiple lines.
Version 0.9.4 - IntelliSense additions
* Adding IntelliSense to Java with simple List of selectable keywords
* Added Toggle Comment Actions using Control SLASH
* Fixed Issue 47.
* Added Clojure, Scala, DOS Batch and 'nix bash support
* Added Configurable Popup menus with default Tango Desktop icons
* Added configurable format for the CaretMonitor class
* Toggle Comments Action selects the lines affected after being performed
* Added multi-line support in ActionUtils.insertMagicSTring method.
* GotoLine dialog responds to ESC key
Version 0.9.3 - Start of scripts for the document:
* Added new methods getLine() to SyntaxDocument
* SyntaxDocument getIndexOf methods deprecated, use getMatchers instead
* Added Line Numbering to Java
* Added CaretMonitor Class
* Merged Find And Replace dialogs into one.
* Created SyntaxComponent interface and have all UI components implement
that interface. DefaultSyntaxKit will use config.properties class to
dynamically install these components.
* Added Right Margin option and Single Color Selection Options
* Added Python, C and C++ Support
* Added Ruby Syntax Support
* Fixed Issue 37 (NPE for LineNumbersRuler)
* Fixed Issue 39 (Highlighting Tokens overrides selection highlights)
* Fixed some JavaDoc comments.
* Fixed Line Numbers being displayed for the height of the editor and now
just for the actual available lines.
* Fixed Margin typo in all project. Issue 43
* Changing Actions to be more configurable:
* SyntaxActions renamed to ActionUtils
* Removed all inner classes from SyntaxActions
* Will create new SyntaxAction interface that will allow dynamic addition
actions (in the addKeyActions of DefaultSyntaxKit
* Added Text AA property to SyntaxView
Version 0.9.2:
* Fixing Java Indentation and Un-Indentattion Actions
* Added and used (in the Tester) clearUndoes on the SyntaxDocument
* Added Basic JFlex Syntax
* Added getContentTypes to DefaultSyntaxKit to get all registered
ContentTypes. This is now also used in the SyntaxTester instead of
hardcoding the types.
* Cleanup and optimization of Lexers by removing duplicate Java Code
(replaced with Regex OR)
* Removed calls to deprecated calls in SyntaxView
* Modified the SyntaxDOcument to override the fireXXX methods and parse
the document at that time instead of overriding the inserUpdate method.
This fixes issue 24.
* Added Groovy GString expression highlights
* Removed getLanguages method from Lexer interface and implementations.
* Added WARNING and ERROR TokenTypes and added their default styles.
* Moved Keymaps and install methods to SyntaxKits instead of the Lexers
* Removed deprecated methods from SyntaxActions class
* Split SyntaxActions into new package and moved inner classes to the new
package
* Added Token HighLighter to Java
* Added Pairs Highlighter to Java
* Token class made immutable (all final fields)
* Added Find and Replace Dialogs and Action to Java (mapped to C-F and
C-H )
* Added pair matching to XML tags
* Added CDATA matching and pair highlights for XML
* Added Comment Pair Highlighting in XML
* Fixed highlighting with selections so the selection always appears
* Merged Find and Replace Dialogs into one
* Fixed issue 33 (undable to add new line after final closing brace for
Java)
* Added Groovy Multi-Line strings and fixed Comments as Regex issue.
* Fixes to empty find text field causing NPE
Version 0.9.1
* Fixed empty strings in XML syntax Issue 29
* Fixed TAL lexer using incorrect package name
Version 0.9.0
* Initial version after major overhaul

View File

@@ -0,0 +1,11 @@
# Java Regex Lexer:
COMMENT=/\\*(?:.|[\\n\\r])*?\\*/|//.*
STRING=\"((?:\\\")|.*)?\"
IDENTIFIER=[a-z][a-zA-Z0-9_]*
TYPE=[A-Z_]\\w*
KEYWORD=abstract|boolean|break|byte|case|catch|char|class|const|continue|\
do|double|enum|else|extends|final|finally|float|for|default|implements|import|\
instanceof|int|interface|long|native|new|goto|if|public|short|super|switch|\
synchronized|package|private|protected|transient|return|void|static|while|this|\
throw|throws|try|volatile|strictfp|true|false|null
TYPE3=@\\w+

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/target/generated-sources/annotations" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/target/generated-sources/jflex" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target/classes" />
<excludeFolder url="file://$MODULE_DIR$/target/maven-archiver" />
<excludeFolder url="file://$MODULE_DIR$/target/test-classes" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<actions>
<action>
<actionName>run</actionName>
<goals>
<goal>process-classes</goal>
<goal>org.codehaus.mojo:exec-maven-plugin:1.1:exec</goal>
</goals>
<properties>
<exec.args>-classpath %classpath jsyntaxpane.SyntaxTester</exec.args>
<exec.executable>java</exec.executable>
</properties>
</action>
<action>
<actionName>debug</actionName>
<goals>
<goal>process-classes</goal>
<goal>org.codehaus.mojo:exec-maven-plugin:1.1:exec</goal>
</goals>
<properties>
<exec.args>-Xdebug -Djava.compiler=none -Xnoagent -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath jsyntaxpane.SyntaxTester</exec.args>
<jpda.listen>true</jpda.listen>
<exec.executable>java</exec.executable>
</properties>
</action>
<action>
<actionName>profile</actionName>
<packagings>
<packaging>jar</packaging>
</packagings>
<goals>
<goal>process-classes</goal>
<goal>org.codehaus.mojo:exec-maven-plugin:1.1:exec</goal>
</goals>
<properties>
<exec.args>${profiler.args} -classpath %classpath jsyntaxpane.SyntaxTester</exec.args>
<profiler.action>profile</profiler.action>
<exec.executable>${profiler.java}</exec.executable>
</properties>
</action>
</actions>

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>jsyntaxpane</groupId>
<artifactId>jsyntaxpane</artifactId>
<packaging>jar</packaging>
<version>0.9.5</version>
<name>jsyntaxpane</name>
<description>A very simple to use and extend JEditorKit that supports few languages. The main goal is to make it easy to have nice looking Java Swing Editors with support for Syntax Highlighting.</description>
<url>http://jsyntaxpane.googlecode.com/</url>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<url>http://jsyntaxpane.googlecode.com/svn/</url>
</scm>
<pluginRepositories>
<pluginRepository>
<id>jflex</id>
<name>JFlex repository</name>
<url>http://jflex.sourceforge.net/repo/</url>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3</version>
<configuration>
<!--<compilerArgument>-encoding utf8</compilerArgument>-->
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<outputDirectory>../../../lib</outputDirectory>
<excludes>
<exclude>**/Thumbs.db</exclude>
</excludes>
<archive>
<manifest>
<mainClass>jsyntaxpane.SyntaxTester</mainClass>
<packageName>jsyntaxpane</packageName>
<addClasspath>true</addClasspath>
<classpathPrefix />
</manifest>
<manifestEntries>
<mode>development</mode>
<url>${pom.url}</url>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>de.jflex</groupId>
<artifactId>maven-jflex-plugin</artifactId>
<!--version>0.2</version-->
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/java" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,140 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane;
import javax.swing.event.UndoableEditEvent;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AbstractDocument.DefaultDocumentEvent;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.CompoundEdit;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEdit;
/**
* A revised UndoManager that groups undos based on positions. If the change is relatively next to the
* previous change, like when continuous typing, then the undoes are grouped together.
*
* This is cutomized from the
*
* http://www.camick.com/java/source/CompoundUndoMan.java
*
* from the blog:
*
* http://tips4java.wordpress.com/2008/10/27/compound-undo-manager/
*
* @author Ayman Al-Sairafi
*/
public class CompoundUndoMan extends UndoManager {
private CompoundEdit compoundEdit;
// This allows us to start combining operations.
// it will be reset after the first change.
private boolean startCombine = false;
// This holds the start of the last line edited, if edits are on multiple
// lines, then they will not be combined.
private int lastLine = -1;
public CompoundUndoMan(SyntaxDocument doc) {
doc.addUndoableEditListener(this);
lastLine = doc.getStartPosition().getOffset();
}
/**
* Whenever an UndoableEdit happens the edit will either be absorbed
* by the current compound edit or a new compound edit will be started
*/
@Override
public void undoableEditHappened(UndoableEditEvent e) {
// Start a new compound edit
AbstractDocument.DefaultDocumentEvent docEvt = (DefaultDocumentEvent) e.getEdit();
if (compoundEdit == null) {
compoundEdit = startCompoundEdit(e.getEdit());
startCombine = false;
return;
}
int editLine = ((SyntaxDocument)docEvt.getDocument()).getLineNumberAt(docEvt.getOffset());
// Check for an incremental edit or backspace.
// The Change in Caret position and Document length should both be
// either 1 or -1.
if ((startCombine || Math.abs(docEvt.getLength()) == 1) && editLine == lastLine) {
compoundEdit.addEdit(e.getEdit());
startCombine = false;
return;
}
// Not incremental edit, end previous edit and start a new one
lastLine = editLine;
compoundEdit.end();
compoundEdit = startCompoundEdit(e.getEdit());
}
/*
** Each CompoundEdit will store a group of related incremental edits
** (ie. each character typed or backspaced is an incremental edit)
*/
private CompoundEdit startCompoundEdit(UndoableEdit anEdit) {
// Track Caret and Document information of this compound edit
AbstractDocument.DefaultDocumentEvent docEvt = (DefaultDocumentEvent) anEdit;
// The compound edit is used to store incremental edits
compoundEdit = new MyCompoundEdit();
compoundEdit.addEdit(anEdit);
// The compound edit is added to the UndoManager. All incremental
// edits stored in the compound edit will be undone/redone at once
addEdit(compoundEdit);
return compoundEdit;
}
class MyCompoundEdit extends CompoundEdit {
@Override
public boolean isInProgress() {
// in order for the canUndo() and canRedo() methods to work
// assume that the compound edit is never in progress
return false;
}
@Override
public void undo() throws CannotUndoException {
// End the edit so future edits don't get absorbed by this edit
if (compoundEdit != null) {
compoundEdit.end();
}
super.undo();
// Always start a new compound edit after an undo
compoundEdit = null;
}
}
/**
* Start to combine the next operations together. Only the next operation is combined.
* The flag is then automatically reset.
*/
public void startCombine() {
startCombine = true;
}
}

View File

@@ -0,0 +1,679 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane;
import java.awt.Color;
import java.awt.Container;
import java.util.logging.Level;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JEditorPane;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Document;
import javax.swing.text.EditorKit;
import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import jsyntaxpane.actions.DefaultSyntaxAction;
import jsyntaxpane.actions.SyntaxAction;
import jsyntaxpane.components.SyntaxComponent;
import jsyntaxpane.util.Configuration;
import jsyntaxpane.util.JarServiceProvider;
/**
* The DefaultSyntaxKit is the main entry to SyntaxPane. To use the package, just
* set the EditorKit of the EditorPane to a new instance of this class.
*
* You need to pass a proper lexer to the class.
*
* @author ayman
*/
public class DefaultSyntaxKit extends DefaultEditorKit implements ViewFactory {
public static final String CONFIG_CARETCOLOR = "CaretColor";
public static final String CONFIG_SELECTION = "SelectionColor";
public static final String CONFIG_COMPONENTS = "Components";
public static final String CONFIG_MENU = "PopupMenu";
public static final String CONFIG_TOOLBAR = "Toolbar";
public static final String CONFIG_TOOLBAR_ROLLOVER = "Toolbar.Buttons.Rollover";
public static final String CONFIG_TOOLBAR_BORDER = "Toolbar.Buttons.BorderPainted";
public static final String CONFIG_TOOLBAR_OPAQUE = "Toolbar.Buttons.Opaque";
public static final String CONFIG_TOOLBAR_BORDER_SIZE = "Toolbar.Buttons.BorderSize";
private static final Pattern ACTION_KEY_PATTERN = Pattern.compile("Action\\.((\\w|-)+)");
private static final Pattern DEFAULT_ACTION_PATTERN = Pattern.compile("(DefaultAction.((\\w|-)+)).*");
private static Font DEFAULT_FONT;
private static Set<String> CONTENT_TYPES = new HashSet<String>();
private static Boolean initialized = false;
private static Map<String, String> abbrvs;
private static String MENU_MASK_STRING = "control ";
private Lexer lexer;
private static final Logger LOG = Logger.getLogger(DefaultSyntaxKit.class.getName());
private Map<JEditorPane, List<SyntaxComponent>> editorComponents =
new WeakHashMap<JEditorPane, List<SyntaxComponent>>();
private Map<JEditorPane, JPopupMenu> popupMenu =
new WeakHashMap<JEditorPane, JPopupMenu>();
/**
* Main Configuration of JSyntaxPane EditorKits
*/
private static Map<Class<? extends DefaultSyntaxKit>, Configuration> CONFIGS;
static {
// we only need to initialize once.
if (!initialized) {
initKit();
}
int menuMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
if(menuMask == KeyEvent.ALT_DOWN_MASK) {
MENU_MASK_STRING = "alt ";
}
}
private static final String ACTION_MENU_TEXT = "MenuText";
/**
* Create a new Kit for the given language
* @param lexer
*/
public DefaultSyntaxKit(Lexer lexer) {
super();
this.lexer = lexer;
}
/**
* Adds UI components to the pane
* @param editorPane
*/
public void addComponents(JEditorPane editorPane) {
// install the components to the editor:
String[] components = getConfig().getPropertyList(CONFIG_COMPONENTS);
for (String c : components) {
installComponent(editorPane, c);
}
}
/**
* Creates a SyntaxComponent of the the given classname and installs
* it on the pane
* @param pane
* @param classname
*/
public void installComponent(JEditorPane pane, String classname) {
try {
@SuppressWarnings(value = "unchecked")
Class compClass = Class.forName(classname);
SyntaxComponent comp = (SyntaxComponent) compClass.newInstance();
comp.config(getConfig());
comp.install(pane);
if (editorComponents.get(pane) == null) {
editorComponents.put(pane, new ArrayList<SyntaxComponent>());
}
editorComponents.get(pane).add(comp);
} catch (InstantiationException ex) {
LOG.log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
LOG.log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
/**
* Find the SyntaxCOmponent with given classname that is installed
* on the given pane, then deinstalls and removes it fom the
* editorComponents list
* @param pane
* @param classname
*/
public void deinstallComponent(JEditorPane pane, String classname) {
for (SyntaxComponent c : editorComponents.get(pane)) {
if (c.getClass().getName().equals(classname)) {
c.deinstall(pane);
editorComponents.get(pane).remove(c);
break;
}
}
}
/**
* Checks if the component with given classname is installed on the
* pane.
* @param pane
* @param classname
* @return true if component is installed, false otherwise
*/
public boolean isComponentInstalled(JEditorPane pane, String classname) {
for (SyntaxComponent c : editorComponents.get(pane)) {
if (c.getClass().getName().equals(classname)) {
return true;
}
}
return false;
}
/**
* Toggles the component with given classname. If component is found
* and installed, then it is deinstalled. Otherwise a new one is
* installed
* @param pane
* @param classname
* @return true if component was installed, false if it was removed
*/
public boolean toggleComponent(JEditorPane pane, String classname) {
for (SyntaxComponent c : editorComponents.get(pane)) {
if (c.getClass().getName().equals(classname)) {
c.deinstall(pane);
editorComponents.get(pane).remove(c);
return false;
}
}
installComponent(pane, classname);
return true;
}
/**
* Adds a popup menu to the editorPane if needed.
*
* @param editorPane
*/
public void addPopupMenu(JEditorPane editorPane) {
String[] menuItems = getConfig().getPropertyList(CONFIG_MENU);
if (menuItems == null || menuItems.length == 0) {
return;
}
popupMenu.put(editorPane, new JPopupMenu());
JMenu stack = null;
for (String menuString : menuItems) {
// create the Popup menu
if (menuString.equals("-")) {
popupMenu.get(editorPane).addSeparator();
} else if (menuString.startsWith(">")) {
JMenu sub = new JMenu(menuString.substring(1));
popupMenu.get(editorPane).add(sub);
stack = sub;
} else if (menuString.startsWith("<")) {
Container parent = stack.getParent();
if (parent instanceof JMenu) {
JMenu jMenu = (JMenu) parent;
stack = jMenu;
} else {
stack = null;
}
} else {
Action action = editorPane.getActionMap().get(menuString);
if (action != null) {
JMenuItem menuItem;
if (action.getValue(Action.SELECTED_KEY) != null) {
menuItem = new JCheckBoxMenuItem(action);
} else {
menuItem = new JMenuItem(action);
}
// Use our own property if it was set for the menu text
if (action.getValue(ACTION_MENU_TEXT) != null) {
menuItem.setText((String) action.getValue(ACTION_MENU_TEXT));
}
if (stack == null) {
popupMenu.get(editorPane).add(menuItem);
} else {
stack.add(menuItem);
}
}
}
}
editorPane.setComponentPopupMenu(popupMenu.get(editorPane));
}
/**
* Add all pop-up menu items to a Toolbar. <b>You need to call the validate method
* on the toolbar after this is done to layout the buttons.</b>
* Only Actions which have a SMALL_ICON property will be added to the toolbar
* There are three Configuration Keys that affect the appearance of the added buttons:
* CONFIG_TOOLBAR_ROLLOVER, CONFIG_TOOLBAR_BORDER, CONFIG_TOOLBAR_OPAQUE
*
* @param editorPane
* @param toolbar
*/
public void addToolBarActions(JEditorPane editorPane, JToolBar toolbar) {
String[] toolBarItems = getConfig().getPropertyList(CONFIG_TOOLBAR);
if (toolBarItems == null || toolBarItems.length == 0) {
toolBarItems = getConfig().getPropertyList(CONFIG_MENU);
if (toolBarItems == null || toolBarItems.length == 0) {
return;
}
}
boolean btnRolloverEnabled = getConfig().getBoolean(CONFIG_TOOLBAR_ROLLOVER, true);
boolean btnBorderPainted = getConfig().getBoolean(CONFIG_TOOLBAR_BORDER, false);
boolean btnOpaque = getConfig().getBoolean(CONFIG_TOOLBAR_OPAQUE, false);
int btnBorderSize = getConfig().getInteger(CONFIG_TOOLBAR_BORDER_SIZE, 2);
for (String menuString : toolBarItems) {
if (menuString.equals("-") ||
menuString.startsWith("<") ||
menuString.startsWith(">")) {
toolbar.addSeparator();
} else {
Action action = editorPane.getActionMap().get(menuString);
if (action != null && action.getValue(Action.SMALL_ICON) != null) {
JButton b = toolbar.add(action);
b.setRolloverEnabled(btnRolloverEnabled);
b.setBorderPainted(btnBorderPainted);
b.setOpaque(btnOpaque);
b.setFocusable(false);
b.setBorder(BorderFactory.createEmptyBorder(btnBorderSize,
btnBorderSize, btnBorderSize, btnBorderSize));
}
}
}
}
@Override
public ViewFactory getViewFactory() {
return this;
}
@Override
public View create(Element element) {
return new SyntaxView(element, getConfig());
}
/**
* Install the View on the given EditorPane. This is called by Swing and
* can be used to do anything you need on the JEditorPane control. Here
* I set some default Actions.
*
* @param editorPane
*/
@Override
public void install(JEditorPane editorPane) {
super.install(editorPane);
// get our font
String fontName = getProperty("DefaultFont");
Font font = DEFAULT_FONT;
if (fontName != null) {
font = Font.decode(fontName);
}
editorPane.setFont(font);
Configuration conf = getConfig();
Color caretColor = conf.getColor(CONFIG_CARETCOLOR, Color.BLACK);
editorPane.setCaretColor(caretColor);
Color selectionColor = getConfig().getColor(CONFIG_SELECTION, new Color(0x99ccff));
editorPane.setSelectionColor(selectionColor);
addActions(editorPane);
addComponents(editorPane);
addPopupMenu(editorPane);
}
@Override
public void deinstall(JEditorPane editorPane) {
for (SyntaxComponent c : editorComponents.remove(editorPane)) {
c.deinstall(editorPane);
}
editorPane.getInputMap().clear();
editorPane.getActionMap().clear();
}
/**
* Add keyboard actions to this control using the Configuration we have
* This is revised to properly use InputMap and ActionMap of the component
* instead of using the KeyMaps directly.
* @param editorPane
*/
public void addActions(JEditorPane editorPane) {
InputMap imap = new InputMap();
imap.setParent(editorPane.getInputMap());
ActionMap amap = new ActionMap();
amap.setParent(editorPane.getActionMap());
for (Configuration.StringKeyMatcher m : getConfig().getKeys(ACTION_KEY_PATTERN)) {
String[] values = Configuration.COMMA_SEPARATOR.split(
m.value);
String actionClass = values[0];
String actionName = m.group1;
SyntaxAction action = createAction(actionClass);
// The configuration keys will need to be prefixed by Action
// to make it more readable in the Configuration files.
action.config(getConfig(), DefaultSyntaxAction.ACTION_PREFIX + actionName);
// Add the action to the component also
amap.put(actionName, action);
// Now bind all the keys to the Action we have using the InputMap
for (int i = 1; i < values.length; i++) {
String keyStrokeString = values[i].replace("menu ", MENU_MASK_STRING);
KeyStroke ks = KeyStroke.getKeyStroke(keyStrokeString);
// we may have more than onr value ( for key action ), but we will use the
// last one in the single value here. This will display the key in the
// popup menus. Pretty neat.
if (ks == null) {
throw new IllegalArgumentException("Invalid KeyStroke: " +
keyStrokeString);
}
action.putValue(Action.ACCELERATOR_KEY, ks);
imap.put(ks, actionName);
}
}
// Now configure the Default actions for better display in the popup menu
for (Configuration.StringKeyMatcher m : getConfig().getKeys(DEFAULT_ACTION_PATTERN)) {
String name = m.matcher.group(2);
Action action = editorPane.getActionMap().get(name);
if (action != null) {
configActionProperties(action, name, m.group1);
}
// The below commented block does find the keys for the default Actions
// using InputMap, however there are multiple bound keys for the
// default actions that displaying them in the menu will probably not
// be the most obvious binding
/*
for (KeyStroke key : imap.allKeys()) {
Object o = imap.get(key);
if(name.equals(o)) {
action.putValue(Action.ACCELERATOR_KEY, key);
break;
}
}
*/
}
editorPane.setActionMap(amap);
editorPane.setInputMap(JTextComponent.WHEN_FOCUSED, imap);
}
private void configActionProperties(Action action, String actionName, String configKey) {
// if we have an icon, then load it:
String iconLoc = getConfig().getString(configKey + ".SmallIcon", actionName + ".png");
URL loc = this.getClass().getResource(DefaultSyntaxAction.SMALL_ICONS_LOC_PREFIX + iconLoc);
if (loc != null) {
ImageIcon i = new ImageIcon(loc);
action.putValue(Action.SMALL_ICON, i);
}
// Set the menu text. Use the Action.NAME property, unless it is
// already set.
// The NAME would be set for default actions, and we should not change those names.
// so we will put another property and use it for the menu text
String name = getProperty(configKey + ".MenuText");
if (action.getValue(Action.NAME) == null) {
action.putValue(Action.NAME, name);
} else {
action.putValue(ACTION_MENU_TEXT, name);
}
// Set the menu tooltips
String shortDesc = getProperty(configKey + ".ToolTip");
if (shortDesc != null) {
action.putValue(Action.SHORT_DESCRIPTION, shortDesc);
} else {
action.putValue(Action.SHORT_DESCRIPTION, name);
}
}
private SyntaxAction createAction(String actionClassName) {
SyntaxAction action = null;
try {
Class clazz = Class.forName(actionClassName);
action = (SyntaxAction) clazz.newInstance();
} catch (InstantiationException ex) {
throw new IllegalArgumentException("Cannot create action class: " +
actionClassName + ". Ensure it has default constructor.", ex);
} catch (IllegalAccessException ex) {
throw new IllegalArgumentException("Cannot create action class: " +
actionClassName, ex);
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException("Cannot create action class: " +
actionClassName, ex);
} catch (ClassCastException ex) {
throw new IllegalArgumentException("Cannot create action class: " +
actionClassName, ex);
}
return action;
}
/**
* This is called by Swing to create a Document for the JEditorPane document
* This may be called before you actually get a reference to the control.
* We use it here to create a proper lexer and pass it to the
* SyntaxDcument we return.
* @return
*/
@Override
public Document createDefaultDocument() {
return new SyntaxDocument(lexer);
}
/**
* This is called to initialize the list of <code>Lexer</code>s we have.
* You can call this at initialization, or it will be called when needed.
* The method will also add the appropriate EditorKit classes to the
* corresponding ContentType of the JEditorPane. After this is called,
* you can simply call the editor.setCOntentType("text/java") on the
* control and you will be done.
*/
public synchronized static void initKit() {
// attempt to find a suitable default font
String defaultFont = getConfig(DefaultSyntaxKit.class).getString("DefaultFont");
if (defaultFont != null) {
DEFAULT_FONT = Font.decode(defaultFont);
} else {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
String[] fonts = ge.getAvailableFontFamilyNames();
Arrays.sort(fonts);
if (Arrays.binarySearch(fonts, "Courier New") >= 0) {
DEFAULT_FONT = new Font("Courier New", Font.PLAIN, 12);
} else if (Arrays.binarySearch(fonts, "Courier") >= 0) {
DEFAULT_FONT = new Font("Courier", Font.PLAIN, 12);
} else if (Arrays.binarySearch(fonts, "Monospaced") >= 0) {
DEFAULT_FONT = new Font("Monospaced", Font.PLAIN, 13);
}
}
// read the Default Kits and their associated types
Properties kitsForTypes = JarServiceProvider.readProperties("jsyntaxpane/kitsfortypes");
for (Map.Entry e : kitsForTypes.entrySet()) {
String type = e.getKey().toString();
String classname = e.getValue().toString();
registerContentType(type, classname);
}
initialized = true;
}
/**
* Register the given content type to use the given class name as its kit
* When this is called, an entry is added into the private HashMap of the
* registered editors kits. This is needed so that the SyntaxPane library
* has it's own registration of all the EditorKits
* @param type
* @param classname
*/
public static void registerContentType(String type, String classname) {
try {
// ensure the class is available and that it does supply a no args
// constructor. This saves debugging later if the classname is incorrect
// or does not behave correctly:
Class c = Class.forName(classname);
// attempt to create the class, if we cannot with an empty argument
// then the class is invalid
Object kit = c.newInstance();
if (!(kit instanceof EditorKit)) {
throw new IllegalArgumentException("Cannot register class: " + classname +
". It does not extend EditorKit");
}
JEditorPane.registerEditorKitForContentType(type, classname);
CONTENT_TYPES.add(type);
} catch (InstantiationException ex) {
throw new IllegalArgumentException("Cannot register class: " + classname +
". Ensure it has Default Constructor.", ex);
} catch (IllegalAccessException ex) {
throw new IllegalArgumentException("Cannot register class: " + classname, ex);
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException("Cannot register class: " + classname, ex);
} catch (RuntimeException ex) {
throw new IllegalArgumentException("Cannot register class: " + classname, ex);
}
}
/**
* Return all the content types supported by this library. This will be the
* content types in the file WEB-INF/services/resources/jsyntaxpane/kitsfortypes
* @return sorted array of all registered content types
*/
public static String[] getContentTypes() {
String[] types = CONTENT_TYPES.toArray(new String[0]);
Arrays.sort(types);
return types;
}
/**
* Merges the given properties with the configurations for this Object
*
* @param config
*/
public void setConfig(Properties config) {
getConfig().putAll(config);
}
/**
* Sets the given property to the given value. If the kit is not
* initialized, then calls initKit
* @param key
* @param value
*/
public void setProperty(String key, String value) {
getConfig().put(key, value);
}
/**
* Return the property with the given key. If the kit is not
* initialized, then calls initKit
* Be careful when changing property as the default property may be used
* @param key
* @return value for given key
*/
public String getProperty(String key) {
return getConfig().getString(key);
}
/**
* Get the configuration for this Object
* @return
*/
public Configuration getConfig() {
return getConfig(this.getClass());
}
/**
* JPEXS: Reload configs - for language change
*/
public static void reloadConfigs(){
if (CONFIGS != null) {
CONFIGS.clear();
CONFIGS = null;
}
}
/**
* Return the Configurations object for a Kit. Perfrom lazy creation of a
* Configuration object if nothing is created.
*
* @param kit
* @return
*/
public static synchronized Configuration getConfig(Class<? extends DefaultSyntaxKit> kit) {
if (CONFIGS == null) {
CONFIGS = new WeakHashMap<Class<? extends DefaultSyntaxKit>, Configuration>();
Configuration defaultConfig = new Configuration(DefaultSyntaxKit.class);
loadConfig(defaultConfig, DefaultSyntaxKit.class);
CONFIGS.put(DefaultSyntaxKit.class, defaultConfig);
}
if (CONFIGS.containsKey(kit)) {
return CONFIGS.get(kit);
} else {
// recursive call until we read the Super duper DefaultSyntaxKit
Class superKit = kit.getSuperclass();
@SuppressWarnings("unchecked")
Configuration defaults = getConfig(superKit);
Configuration mine = new Configuration(kit, defaults);
loadConfig(mine, kit);
CONFIGS.put(kit, mine);
return mine;
}
}
public Map<String, String> getAbbreviations() {
// if we have not loaded the abbreviations, then load them now:
if (abbrvs == null) {
String cl = this.getClass().getName().replace('.', '/').toLowerCase();
abbrvs = JarServiceProvider.readStringsMap(cl + "/abbreviations.properties");
}
return abbrvs;
}
/**
* Adds an abbrevisation to this kit's abbreviations.
* @param abbr
* @param template
*/
public static void addAbbreviation(String abbr, String template) {
if (abbrvs == null) {
abbrvs = new HashMap<String, String>();
}
abbrvs.put(abbr, template);
}
/**
* Get the template for the given abbreviation
* @param abbr
* @return
*/
public static String getAbbreviation(String abbr) {
return abbrvs == null ? null : abbrvs.get(abbr);
}
private static void loadConfig(Configuration conf, Class<? extends EditorKit> kit) {
String url = kit.getName().replace(".", "/") + "/config";
Properties p = JarServiceProvider.readProperties(url);
if (p.size() == 0) {
LOG.info("unable to load configuration for: " + kit + " from: " + url + ".properties");
} else {
conf.putAll(p);
}
}
@Override
public String getContentType() {
return "text/" + this.getClass().getSimpleName().replace("SyntaxKit", "").toLowerCase();
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane;
import java.io.IOException;
import jsyntaxpane.lexers.SimpleRegexLexer;
/**
*
* @author Ayman Al-Sairafi
*/
public class JavaRegexKit extends DefaultSyntaxKit {
public JavaRegexKit() throws IOException {
super(new SimpleRegexLexer("javaRegex.properties"));
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane;
import java.util.List;
import javax.swing.text.Segment;
/**
* Lexers must implement these methods. These are used in the Tokenizer
*
* A Lexer should be tied to one document.
*
* @author Ayman Al-Sairafi
*/
public interface Lexer {
/**
* This is the only method a Lexer needs to implement. It will be passed
* a Reader, and it should return non-overlapping Tokens for each recognized token
* in the stream.
* @param segment Text to parse.
* @param ofst offset to add to start of each token (useful for nesting)
* @param tokens List of Tokens to be added. This is done so that the caller creates the
* appropriate List implementation and size. The parse method just adds to the list
*/
public void parse(Segment segment, int ofst, List<Token> tokens);
}

View File

@@ -0,0 +1,595 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.event.DocumentEvent;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.PlainDocument;
import javax.swing.text.Segment;
/**
* A document that supports being highlighted. The document maintains an
* internal List of all the Tokens. The Tokens are updated using
* a Lexer, passed to it during construction.
*
* @author Ayman Al-Sairafi
*/
public class SyntaxDocument extends PlainDocument {
Lexer lexer;
List<Token> tokens;
CompoundUndoMan undo;
public SyntaxDocument(Lexer lexer) {
super();
putProperty(PlainDocument.tabSizeAttribute, 4);
this.lexer = lexer;
// Listen for undo and redo events
undo = new CompoundUndoMan(this);
}
/**
* Parse the entire document and return list of tokens that do not already
* exist in the tokens list. There may be overlaps, and replacements,
* which we will cleanup later.
* @return list of tokens that do not exist in the tokens field
*/
private void parse() {
// if we have no lexer, then we must have no tokens...
if (lexer == null) {
tokens = null;
return;
}
List<Token> toks = new ArrayList<Token>(getLength() / 10);
long ts = System.nanoTime();
int len = getLength();
try {
Segment seg = new Segment();
getText(0, getLength(), seg);
lexer.parse(seg, 0, toks);
} catch (BadLocationException ex) {
log.log(Level.SEVERE, null, ex);
} finally {
if (log.isLoggable(Level.FINEST)) {
log.finest(String.format("Parsed %d in %d ms, giving %d tokens\n",
len, (System.nanoTime() - ts) / 1000000, toks.size()));
}
tokens = toks;
}
}
@Override
protected void fireChangedUpdate(DocumentEvent e) {
parse();
super.fireChangedUpdate(e);
}
@Override
protected void fireInsertUpdate(DocumentEvent e) {
parse();
super.fireInsertUpdate(e);
}
@Override
protected void fireRemoveUpdate(DocumentEvent e) {
parse();
super.fireRemoveUpdate(e);
}
/**
* Replace the token with the replacement string
* @param token
* @param replacement
*/
public void replaceToken(Token token, String replacement) {
try {
replace(token.start, token.length, replacement, null);
} catch (BadLocationException ex) {
log.log(Level.WARNING, "unable to replace token: " + token, ex);
}
}
/**
* This class is used to iterate over tokens between two positions
*
*/
class TokenIterator implements ListIterator<Token> {
int start;
int end;
int ndx = 0;
@SuppressWarnings("unchecked")
private TokenIterator(int start, int end) {
this.start = start;
this.end = end;
if (tokens != null && !tokens.isEmpty()) {
Token token = new Token(TokenType.COMMENT, start, end - start);
ndx = Collections.binarySearch((List) tokens, token);
// we will probably not find the exact token...
if (ndx < 0) {
// so, start from one before the token where we should be...
// -1 to get the location, and another -1 to go back..
ndx = (-ndx - 1 - 1 < 0) ? 0 : (-ndx - 1 - 1);
Token t = tokens.get(ndx);
// if the prev token does not overlap, then advance one
if (t.end() <= start) {
ndx++;
}
}
}
}
@Override
public boolean hasNext() {
if (tokens == null) {
return false;
}
if (ndx >= tokens.size()) {
return false;
}
Token t = tokens.get(ndx);
if (t.start >= end) {
return false;
}
return true;
}
@Override
public Token next() {
return tokens.get(ndx++);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public boolean hasPrevious() {
if (tokens == null) {
return false;
}
if (ndx <= 0) {
return false;
}
Token t = tokens.get(ndx);
if (t.end() <= start) {
return false;
}
return true;
}
@Override
public Token previous() {
return tokens.get(ndx--);
}
@Override
public int nextIndex() {
return ndx + 1;
}
@Override
public int previousIndex() {
return ndx - 1;
}
@Override
public void set(Token e) {
throw new UnsupportedOperationException();
}
@Override
public void add(Token e) {
throw new UnsupportedOperationException();
}
}
/**
* Return an iterator of tokens between p0 and p1.
* @param start start position for getting tokens
* @param end position for last token
* @return Iterator for tokens that overal with range from start to end
*/
public Iterator<Token> getTokens(int start, int end) {
return new TokenIterator(start, end);
}
/**
* Find the token at a given position. May return null if no token is
* found (whitespace skipped) or if the position is out of range:
* @param pos
* @return
*/
public Token getTokenAt(int pos) {
if (tokens == null || tokens.isEmpty() || pos > getLength()) {
return null;
}
Token tok = null;
Token tKey = new Token(TokenType.DEFAULT, pos, 1);
@SuppressWarnings("unchecked")
int ndx = Collections.binarySearch((List) tokens, tKey);
if (ndx < 0) {
// so, start from one before the token where we should be...
// -1 to get the location, and another -1 to go back..
ndx = (-ndx - 1 - 1 < 0) ? 0 : (-ndx - 1 - 1);
Token t = tokens.get(ndx);
if ((t.start <= pos) && (pos <= t.end())) {
tok = t;
}
} else {
tok = tokens.get(ndx);
}
return tok;
}
public Token getWordAt(int offs, Pattern p) {
Token word = null;
try {
Element line = getParagraphElement(offs);
if (line == null) {
return word;
}
int lineStart = line.getStartOffset();
int lineEnd = Math.min(line.getEndOffset(), getLength());
Segment seg = new Segment();
getText(lineStart, lineEnd - lineStart, seg);
if (seg.count > 0) {
// we need to get the word using the words pattern p
Matcher m = p.matcher(seg);
int o = offs - lineStart;
while (m.find()) {
if (m.start() <= o && o <= m.end()) {
word = new Token(TokenType.DEFAULT, m.start() + lineStart, m.end() - m.start());
break;
}
}
}
} catch (BadLocationException ex) {
Logger.getLogger(SyntaxDocument.class.getName()).log(Level.SEVERE, null, ex);
} finally {
return word;
}
}
/**
* Return the token following the current token, or null
* <b>This is an expensive operation, so do not use it to update the gui</b>
* @param tok
* @return
*/
public Token getNextToken(Token tok) {
int n = tokens.indexOf(tok);
if ((n >= 0) && (n < (tokens.size() - 1))) {
return tokens.get(n + 1);
} else {
return null;
}
}
/**
* Return the token prior to the given token, or null
* <b>This is an expensive operation, so do not use it to update the gui</b>
* @param tok
* @return
*/
public Token getPrevToken(Token tok) {
int n = tokens.indexOf(tok);
if ((n > 0) && (!tokens.isEmpty())) {
return tokens.get(n - 1);
} else {
return null;
}
}
/**
* This is used to return the other part of a paired token in the document.
* A paired part has token.pairValue <> 0, and the paired token will
* have the negative of t.pairValue.
* This method properly handles nestings of same pairValues, but overlaps
* are not checked.
* if The document does not contain a paired token, then null is returned.
* @param t
* @return the other pair's token, or null if nothing is found.
*/
public Token getPairFor(Token t) {
if (t == null || t.pairValue == 0) {
return null;
}
Token p = null;
int ndx = tokens.indexOf(t);
// w will be similar to a stack. The openners weght is added to it
// and the closers are subtracted from it (closers are already negative)
int w = t.pairValue;
int direction = (t.pairValue > 0) ? 1 : -1;
boolean done = false;
int v = Math.abs(t.pairValue);
while (!done) {
ndx += direction;
if (ndx < 0 || ndx >= tokens.size()) {
break;
}
Token current = tokens.get(ndx);
if (Math.abs(current.pairValue) == v) {
w += current.pairValue;
if (w == 0) {
p = current;
done = true;
}
}
}
return p;
}
/**
* Perform an undo action, if possible
*/
public void doUndo() {
if (undo.canUndo()) {
undo.undo();
parse();
}
}
/**
* Perform a redo action, if possible.
*/
public void doRedo() {
if (undo.canRedo()) {
undo.redo();
parse();
}
}
/**
* Return a matcher that matches the given pattern on the entire document
* @param pattern
* @return matcher object
*/
public Matcher getMatcher(Pattern pattern) {
return getMatcher(pattern, 0, getLength());
}
/**
* Return a matcher that matches the given pattern in the part of the
* document starting at offset start. Note that the matcher will have
* offset starting from <code>start</code>
*
* @param pattern
* @param start
* @return matcher that <b>MUST</b> be offset by start to get the proper
* location within the document
*/
public Matcher getMatcher(Pattern pattern, int start) {
return getMatcher(pattern, start, getLength() - start);
}
/**
* Return a matcher that matches the given pattern in the part of the
* document starting at offset start and ending at start + length.
* Note that the matcher will have
* offset starting from <code>start</code>
*
* @param pattern
* @param start
* @param length
* @return matcher that <b>MUST</b> be offset by start to get the proper
* location within the document
*/
public Matcher getMatcher(Pattern pattern, int start, int length) {
Matcher matcher = null;
if (getLength() == 0) {
return null;
}
if (start >= getLength()) {
return null;
}
try {
if (start < 0) {
start = 0;
}
if (start + length > getLength()) {
length = getLength() - start;
}
Segment seg = new Segment();
getText(start, length, seg);
matcher = pattern.matcher(seg);
} catch (BadLocationException ex) {
log.log(Level.SEVERE, "Requested offset: " + ex.offsetRequested(), ex);
}
return matcher;
}
/**
* This will discard all undoable edits
*/
public void clearUndos() {
undo.discardAllEdits();
}
/**
* Gets the line at given position. The line returned will NOT include
* the line terminator '\n'
* @param pos Position (usually from text.getCaretPosition()
* @return the STring of text at given position
* @throws BadLocationException
*/
public String getLineAt(int pos) throws BadLocationException {
Element e = getParagraphElement(pos);
Segment seg = new Segment();
getText(e.getStartOffset(), e.getEndOffset() - e.getStartOffset(), seg);
char last = seg.last();
if (last == '\n' || last == '\r') {
seg.count--;
}
return seg.toString();
}
/**
* Deletes the line at given position
* @param pos
* @throws javax.swing.text.BadLocationException
*/
public void removeLineAt(int pos)
throws BadLocationException {
Element e = getParagraphElement(pos);
remove(e.getStartOffset(), getElementLength(e));
}
/**
* Replace the line at given position with the given string, which can span
* multiple lines
* @param pos
* @param newLines
* @throws javax.swing.text.BadLocationException
*/
public void replaceLineAt(int pos, String newLines)
throws BadLocationException {
Element e = getParagraphElement(pos);
replace(e.getStartOffset(), getElementLength(e), newLines, null);
}
/**
* Helper method to get the length of an element and avoid getting
* a too long element at the end of the document
* @param e
* @return
*/
private int getElementLength(Element e) {
int end = e.getEndOffset();
if (end >= (getLength() - 1)) {
end--;
}
return end - e.getStartOffset();
}
/**
* Gets the text without the comments. For example for the string
* <code>{ // it's a comment</code> this method will return "{ ".
* @param aStart start of the text.
* @param anEnd end of the text.
* @return String for the line without comments (if exists).
*/
public synchronized String getUncommentedText(int aStart, int anEnd) {
readLock();
StringBuilder result = new StringBuilder();
Iterator<Token> iter = getTokens(aStart, anEnd);
while (iter.hasNext()) {
Token t = iter.next();
if (!TokenType.isComment(t)) {
result.append(t.getText(this));
}
}
readUnlock();
return result.toString();
}
/**
* Returns the starting position of the line at pos
* @param pos
* @return starting position of the line
*/
public int getLineStartOffset(int pos) {
return getParagraphElement(pos).getStartOffset();
}
/**
* Returns the end position of the line at pos.
* Does a bounds check to ensure the returned value does not exceed
* document length
* @param pos
* @return
*/
public int getLineEndOffset(int pos) {
int end = 0;
end = getParagraphElement(pos).getEndOffset();
if (end >= getLength()) {
end = getLength();
}
return end;
}
/**
* Return the number of lines in this document
* @return
*/
public int getLineCount() {
Element e = getDefaultRootElement();
int cnt = e.getElementCount();
return cnt;
}
/**
* Return the line number at given position. The line numbers are zero based
* @param pos
* @return
*/
public int getLineNumberAt(int pos) {
int lineNr = getDefaultRootElement().getElementIndex(pos);
return lineNr;
}
@Override
public String toString() {
return "SyntaxDocument(" + lexer + ", " + ((tokens == null) ? 0 : tokens.size()) + " tokens)@" +
hashCode();
}
/**
* We override this here so that the replace is treated as one operation
* by the undomanager
* @param offset
* @param length
* @param text
* @param attrs
* @throws BadLocationException
*/
@Override
public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
remove(offset, length);
undo.startCombine();
insertString(offset, text, attrs);
}
/**
* Append the given string to the text of this document.
* @param str
* @return this document
*/
public SyntaxDocument append(String str) {
try {
insertString(getLength(), str, null);
} catch (BadLocationException ex) {
log.log(Level.WARNING, "Error appending str", ex);
}
return this;
}
// our logger instance...
private static final Logger log = Logger.getLogger(SyntaxDocument.class.getName());
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import javax.swing.text.Segment;
import javax.swing.text.TabExpander;
/**
* This class represents the Style for a TokenType. This class is responsible
* for actually drawing a Token on the View.
*
* @author Ayman Al-Sairafi
*/
public final class SyntaxStyle {
private Color color;
private int fontStyle;
public SyntaxStyle() {
super();
}
public SyntaxStyle(Color color, boolean bold, boolean italic) {
super();
this.color = color;
setBold(bold);
setItalic(italic);
}
public SyntaxStyle(Color color, int fontStyle) {
super();
this.color = color;
this.fontStyle = fontStyle;
}
public SyntaxStyle(String str) {
String[] parts = str.split("\\s*,\\s*");
if (parts.length != 2) {
throw new IllegalArgumentException("style not correct format: " + str);
}
this.color = new Color(Integer.decode(parts[0]));
this.fontStyle = Integer.decode(parts[1]);
}
public boolean isBold() {
return (fontStyle & Font.BOLD) != 0;
}
public void setBold(Boolean bold) {
if (bold) {
fontStyle |= Font.BOLD;
} else {
int mask = -1 ^ Font.BOLD;
fontStyle = (fontStyle & (mask));
}
}
public String getColorString() {
return String.format("0x%06x", color.getRGB() & 0x00ffffff);
}
public void setColorString(String color) {
this.color = Color.decode(color);
}
public Boolean isItalic() {
return (fontStyle & Font.ITALIC) != 0;
}
public void setItalic(Boolean italic) {
if (italic) {
fontStyle |= Font.ITALIC;
} else {
fontStyle = (fontStyle & (-1 ^ Font.ITALIC));
}
}
public int getFontStyle() {
return fontStyle;
}
public Color getColor() {
return color;
}
/**
* Draw text. This can directly call the Utilities.drawTabbedText.
* Sub-classes can override this method to provide any other decorations.
* @param segment - the source of the text
* @param x - the X origin >= 0
* @param y - the Y origin >= 0
* @param graphics - the graphics context
* @param e - how to expand the tabs. If this value is null, tabs will be
* expanded as a space character.
* @param startOffset - starting offset of the text in the document >= 0
* @return
*/
public int drawText(Segment segment, int x, int y,
Graphics graphics, TabExpander e, int startOffset) {
graphics.setFont(graphics.getFont().deriveFont(getFontStyle()));
FontMetrics fontMetrics = graphics.getFontMetrics();
int a = fontMetrics.getAscent();
int h = a + fontMetrics.getDescent();
//JPEXS: UniTools for multi fonts
int w = UniTools.getTabbedTextWidth(graphics,segment,0, e, startOffset);
int rX = x - 1;
int rY = y - a;
int rW = w + 2;
int rH = h;
if ((getFontStyle() & 0x10) != 0) {
graphics.setColor(Color.decode("#EEEEEE"));
graphics.fillRect(rX, rY, rW, rH);
}
graphics.setColor(getColor());
//JPEXS: UniTools for multi fonts
x = UniTools.drawTabbedText(segment, x, y, graphics, e, startOffset);
if ((getFontStyle() & 0x8) != 0) {
graphics.setColor(Color.RED);
graphics.drawRect(rX, rY, rW, rH);
}
return x;
}
}

View File

@@ -0,0 +1,143 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.swing.text.Segment;
import javax.swing.text.TabExpander;
import jsyntaxpane.util.Configuration;
import jsyntaxpane.util.JarServiceProvider;
/**
* The Styles to use for each TokenType. The defaults are created here, and
* then the resource META-INF/services/syntaxstyles.properties is read and
* merged. You can also pass a properties instance and merge your prefered
* styles into the default styles.
*
* Text is drawn by forwarding the drawText request to the SyntaxStyle for the
* that matches the given TokenType
*
* @author Ayman Al-Sairafi
*/
public class SyntaxStyles {
public static final Pattern STYLE_PATTERN = Pattern.compile("Style\\.(\\w+)");
/**
* You can call the mergeStyles method with a Properties file to customize
* the existing styles. Any existing styles will be overwritten by the
* styles you provide.
* @param styles
*/
public void mergeStyles(Properties styles) {
for (Map.Entry e : styles.entrySet()) {
String tokenType = e.getKey().toString();
String style = e.getValue().toString();
try {
TokenType tt = TokenType.valueOf(tokenType);
SyntaxStyle tokenStyle = new SyntaxStyle(style);
put(tt, tokenStyle);
} catch (IllegalArgumentException ex) {
LOG.warning("illegal token type or style for: " + tokenType);
}
}
}
Map<TokenType, SyntaxStyle> styles;
private static SyntaxStyles instance = createInstance();
private static final Logger LOG = Logger.getLogger(SyntaxStyles.class.getName());
private static SyntaxStyle DEFAULT_STYLE = new SyntaxStyle(Color.BLACK, Font.PLAIN);
private SyntaxStyles() {
}
/**
* Create default styles
* @return
*/
private static SyntaxStyles createInstance() {
SyntaxStyles syntaxstyles = new SyntaxStyles();
Properties styles = JarServiceProvider.readProperties(SyntaxStyles.class);
syntaxstyles.mergeStyles(styles);
return syntaxstyles;
}
/**
* Returns the Default Singleton
* @return
*/
public static SyntaxStyles getInstance() {
return instance;
}
public static SyntaxStyles read(Configuration config) {
SyntaxStyles ss = createInstance();
// Configuration styleConf = config.subConfig(STYLE_PROPERTY_KEY);
for (Configuration.StringKeyMatcher m : config.getKeys(STYLE_PATTERN)) {
String type = m.group1;
try {
ss.put(TokenType.valueOf(type), new SyntaxStyle(m.value));
} catch (IllegalArgumentException e) {
Logger.getLogger(SyntaxStyles.class.getName()).warning(
String.format("Invalid Token Type [%s] for Style of ", type));
}
}
return ss;
}
public void put(TokenType type, SyntaxStyle style) {
if (styles == null) {
styles = new HashMap<TokenType, SyntaxStyle>();
}
styles.put(type, style);
}
/**
* Return the style for the given TokenType
* @param type
* @return
*/
public SyntaxStyle getStyle(TokenType type) {
if (styles != null && styles.containsKey(type)) {
return styles.get(type);
} else {
return DEFAULT_STYLE;
}
}
/**
* Draw the given Token. This will simply find the proper SyntaxStyle for
* the TokenType and then asks the proper Style to draw the text of the
* Token.
* @param segment
* @param x
* @param y
* @param graphics
* @param e
* @param token
* @return
*/
public int drawText(Segment segment, int x, int y,
Graphics graphics, TabExpander e, Token token) {
SyntaxStyle s = getStyle(token.type);
return s.drawText(segment, x, y, graphics, e, token.start);
}
}

View File

@@ -0,0 +1,127 @@
<?xml version="1.1" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.6" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="3"/>
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="SyntaxTester.title" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jCmbLangs" min="-2" pref="135" max="-2" attributes="0"/>
<EmptySpace pref="441" max="32767" attributes="0"/>
<Component id="lblCaretPos" min="-2" pref="119" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="lblToken" pref="221" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="484" max="-2" attributes="0"/>
</Group>
<Component id="jToolBar1" alignment="0" pref="715" max="32767" attributes="1"/>
<Component id="jScrollPane1" alignment="0" pref="715" max="32767" attributes="1"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="jToolBar1" min="-2" pref="25" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="382" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="lblToken" min="-2" pref="19" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblCaretPos" alignment="3" pref="21" max="32767" attributes="0"/>
<Component id="jCmbLangs" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="lblCaretPos">
<Properties>
<Property name="horizontalAlignment" type="int" value="11"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="SyntaxTester.lblCaretPos.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JEditorPane" name="jEdtTest">
<Properties>
<Property name="contentType" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="SyntaxTester.jEdtTest.contentType" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Monospaced" size="13" style="0"/>
</Property>
<Property name="caretColor" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="ff" green="cc" red="99" type="rgb"/>
</Property>
</Properties>
<Events>
<EventHandler event="caretUpdate" listener="javax.swing.event.CaretListener" parameters="javax.swing.event.CaretEvent" handler="jEdtTestCaretUpdate"/>
</Events>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="lblToken">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Courier New" size="12" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="SyntaxTester.lblToken.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="jCmbLangs">
<Properties>
<Property name="maximumRowCount" type="int" value="20"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="jCmbLangsItemStateChanged"/>
</Events>
</Component>
<Container class="javax.swing.JToolBar" name="jToolBar1">
<Properties>
<Property name="rollover" type="boolean" value="true"/>
<Property name="focusable" type="boolean" value="false"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
</Container>
</SubComponents>
</Form>

View File

@@ -0,0 +1,198 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane;
import java.awt.Color;
import java.awt.event.ItemEvent;
import java.io.IOException;
import java.io.StringReader;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultComboBoxModel;
import javax.swing.text.EditorKit;
import jsyntaxpane.actions.ActionUtils;
import jsyntaxpane.actions.CaretMonitor;
public class SyntaxTester extends javax.swing.JFrame {
/** Creates new form Tester */
public SyntaxTester() {
// this is a test for adding regex lexer. It wont work unless the
// JavaRegex.properties is found in the classpath
// DefaultSyntaxKit.registerContentType("text/aa_regex", "jsyntaxpane.JavaRegexKit");
initComponents();
jCmbLangs.setModel(new DefaultComboBoxModel(DefaultSyntaxKit.getContentTypes()));
// jEdtTest.setContentType(jCmbLangs.getItemAt(0).toString());
jCmbLangs.setSelectedItem("text/java");
new CaretMonitor(jEdtTest, lblCaretPos);
}
/**
* This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
lblCaretPos = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane();
jEdtTest = new javax.swing.JEditorPane();
lblToken = new javax.swing.JLabel();
jCmbLangs = new javax.swing.JComboBox();
jToolBar1 = new javax.swing.JToolBar();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle"); // NOI18N
setTitle(bundle.getString("SyntaxTester.title")); // NOI18N
lblCaretPos.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
lblCaretPos.setText(bundle.getString("SyntaxTester.lblCaretPos.text")); // NOI18N
jEdtTest.setContentType(bundle.getString("SyntaxTester.jEdtTest.contentType")); // NOI18N
jEdtTest.setFont(new java.awt.Font("Monospaced", 0, 13));
jEdtTest.setCaretColor(new java.awt.Color(153, 204, 255));
jEdtTest.addCaretListener(new javax.swing.event.CaretListener() {
public void caretUpdate(javax.swing.event.CaretEvent evt) {
jEdtTestCaretUpdate(evt);
}
});
jScrollPane1.setViewportView(jEdtTest);
lblToken.setFont(new java.awt.Font("Courier New", 0, 12));
lblToken.setText(bundle.getString("SyntaxTester.lblToken.text")); // NOI18N
jCmbLangs.setMaximumRowCount(20);
jCmbLangs.setFocusable(false);
jCmbLangs.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
jCmbLangsItemStateChanged(evt);
}
});
jToolBar1.setRollover(true);
jToolBar1.setFocusable(false);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addComponent(jCmbLangs, javax.swing.GroupLayout.PREFERRED_SIZE, 135, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 441, Short.MAX_VALUE)
.addComponent(lblCaretPos, javax.swing.GroupLayout.PREFERRED_SIZE, 119, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(lblToken, javax.swing.GroupLayout.DEFAULT_SIZE, 221, Short.MAX_VALUE)
.addGap(484, 484, 484))
.addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 715, Short.MAX_VALUE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 715, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 382, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(lblToken, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblCaretPos, javax.swing.GroupLayout.DEFAULT_SIZE, 21, Short.MAX_VALUE)
.addComponent(jCmbLangs, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void jEdtTestCaretUpdate(javax.swing.event.CaretEvent evt) {//GEN-FIRST:event_jEdtTestCaretUpdate
SyntaxDocument sDoc = ActionUtils.getSyntaxDocument(jEdtTest);
if (sDoc != null) {
Token t = sDoc.getTokenAt(evt.getDot());
if (t != null) {
CharSequence tData = t.getText(sDoc);
if (t.length > 40) {
tData = tData.subSequence(0, 40);
}
lblToken.setText(t.toString() + ": " + tData);
} else {
// null token, remove the status
lblToken.setText(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("NO_TOKEN_AT_CURSOR"));
}
}
}//GEN-LAST:event_jEdtTestCaretUpdate
private void jCmbLangsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_jCmbLangsItemStateChanged
if (evt.getStateChange() == ItemEvent.SELECTED) {
String lang = jCmbLangs.getSelectedItem().toString();
// save the state of the current JEditorPane, as it's Document is about
// to be replaced.
String oldText = jEdtTest.getText();
// install a new DefaultSyntaxKit on the JEditorPane for the requested language.
jEdtTest.setContentType(lang);
// Recreate the Toolbar
jToolBar1.removeAll();
EditorKit kit = jEdtTest.getEditorKit();
if (kit instanceof DefaultSyntaxKit) {
DefaultSyntaxKit defaultSyntaxKit = (DefaultSyntaxKit) kit;
defaultSyntaxKit.addToolBarActions(jEdtTest, jToolBar1);
}
jToolBar1.validate();
try {
// setText should not be called (read the JavaDocs). Better use the read
// method and create a new document.
jEdtTest.read(new StringReader(oldText), lang);
} catch (IOException ex) {
Logger.getLogger(SyntaxTester.class.getName()).log(Level.SEVERE, null, ex);
}
}
jEdtTest.requestFocusInWindow();
}//GEN-LAST:event_jCmbLangsItemStateChanged
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
DefaultSyntaxKit.initKit();
new SyntaxTester().setVisible(true);
} catch (Exception e) {
e.printStackTrace();
System.exit(2);
}
}
});
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JComboBox jCmbLangs;
private javax.swing.JEditorPane jEdtTest;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JToolBar jToolBar1;
private javax.swing.JLabel lblCaretPos;
private javax.swing.JLabel lblToken;
// End of variables declaration//GEN-END:variables
}

View File

@@ -0,0 +1,270 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Toolkit;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.PlainView;
import javax.swing.text.Position;
import javax.swing.text.Segment;
import javax.swing.text.ViewFactory;
import jsyntaxpane.util.Configuration;
public class SyntaxView extends PlainView {
public static final String PROPERTY_RIGHT_MARGIN_COLOR = "RightMarginColor";
public static final String PROPERTY_RIGHT_MARGIN_COLUMN = "RightMarginColumn";
public static final String PROPERTY_SINGLE_COLOR_SELECT = "SingleColorSelect";
private static final Logger log = Logger.getLogger(SyntaxView.class.getName());
private SyntaxStyle DEFAULT_STYLE = SyntaxStyles.getInstance().getStyle(TokenType.DEFAULT);
private final boolean singleColorSelect;
private final int rightMarginColumn;
private final Color rightMarginColor;
private final SyntaxStyles styles;
/**
* Construct a new view using the given configuration and prefix given
*
* @param element
* @param config
*/
public SyntaxView(Element element, Configuration config) {
super(element);
singleColorSelect = config.getBoolean(PROPERTY_SINGLE_COLOR_SELECT, false);
rightMarginColor = new Color(config.getInteger(PROPERTY_RIGHT_MARGIN_COLOR,
0xFF7777));
rightMarginColumn = config.getInteger(PROPERTY_RIGHT_MARGIN_COLUMN,
0);
styles = SyntaxStyles.read(config);
}
@Override
protected int drawUnselectedText(Graphics graphics, int x, int y, int p0,
int p1) {
setRenderingHits((Graphics2D) graphics);
Font saveFont = graphics.getFont();
Color saveColor = graphics.getColor();
SyntaxDocument doc = (SyntaxDocument) getDocument();
Segment segment = getLineBuffer();
// Draw the right margin first, if needed. This way the text overalys
// the margin
if (rightMarginColumn > 0) {
int m_x = rightMarginColumn * graphics.getFontMetrics().charWidth('m');
int h = graphics.getFontMetrics().getHeight();
graphics.setColor(rightMarginColor);
graphics.drawLine(m_x, y, m_x, y - h);
}
try {
// Colour the parts
Iterator<Token> i = doc.getTokens(p0, p1);
int start = p0;
while (i.hasNext()) {
Token t = i.next();
// if there is a gap between the next token start and where we
// should be starting (spaces not returned in tokens), then draw
// it in the default type
if (start < t.start) {
doc.getText(start, t.start - start, segment);
x = DEFAULT_STYLE.drawText(segment, x, y, graphics, this, start);
}
// t and s are the actual start and length of what we should
// put on the screen. assume these are the whole token....
int l = t.length;
int s = t.start;
// ... unless the token starts before p0:
if (s < p0) {
// token is before what is requested. adgust the length and s
l -= (p0 - s);
s = p0;
}
// if token end (s + l is still the token end pos) is greater
// than p1, then just put up to p1
if (s + l > p1) {
l = p1 - s;
}
doc.getText(s, l, segment);
x = styles.drawText(segment, x, y, graphics, this, t);
start = t.end();
}
// now for any remaining text not tokenized:
if (start < p1) {
doc.getText(start, p1 - start, segment);
x = DEFAULT_STYLE.drawText(segment, x, y, graphics, this, start);
}
} catch (BadLocationException ex) {
log.log(Level.SEVERE, "Requested: " + ex.offsetRequested(), ex);
} finally {
graphics.setFont(saveFont);
graphics.setColor(saveColor);
}
return x;
}
@Override
protected int drawSelectedText(Graphics graphics, int x, int y, int p0, int p1)
throws BadLocationException {
if (singleColorSelect) {
if (rightMarginColumn > 0) {
int m_x = rightMarginColumn * graphics.getFontMetrics().charWidth('m');
int h = graphics.getFontMetrics().getHeight();
graphics.setColor(rightMarginColor);
graphics.drawLine(m_x, y, m_x, y - h);
}
return super.drawUnselectedText(graphics, x, y, p0, p1);
} else {
return drawUnselectedText(graphics, x, y, p0, p1);
}
}
/**
* Sets the Rendering Hints o nthe Graphics. This is used so that
* any painters can set the Rendering Hits to match the view.
* @param g2d
*/
public static void setRenderingHits(Graphics2D g2d) {
g2d.addRenderingHints(sysHints);
}
@Override
protected void updateDamage(javax.swing.event.DocumentEvent changes,
Shape a,
ViewFactory f) {
super.updateDamage(changes, a, f);
java.awt.Component host = getContainer();
host.repaint();
}
/**
* The values for the string key for Text Anti-Aliasing
*/
private static RenderingHints sysHints;
static {
sysHints = null;
try {
Toolkit toolkit = Toolkit.getDefaultToolkit();
@SuppressWarnings("unchecked")
Map<RenderingHints.Key,?> map = (Map<RenderingHints.Key,?>)
toolkit.getDesktopProperty("awt.font.desktophints");
sysHints = new RenderingHints(map);
} catch (Throwable t) {
}
}
//JPEXS: PlainView adaptation for multi fonts (UniTools)
@Override
public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
// line coordinates
Document doc = getDocument();
Element map = getElement();
int lineIndex = map.getElementIndex(pos);
if (lineIndex < 0) {
return lineToRect(a, 0);
}
Rectangle lineArea = lineToRect(a, lineIndex);
// determine span from the start of the line
int tabBase = lineArea.x;
Element line = map.getElement(lineIndex);
int p0 = line.getStartOffset();
Segment s = new Segment();
doc.getText(p0, pos - p0, s);
int xOffs = UniTools.getTabbedTextWidth(s, metrics, tabBase, this,p0);
// fill in the results and return
lineArea.x += xOffs;
lineArea.width = 1;
lineArea.height = metrics.getHeight();
return lineArea;
}
//JPEXS: PlainView adaptation for multi fonts (UniTools)
@Override
public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {
// PENDING(prinz) properly calculate bias
bias[0] = Position.Bias.Forward;
Rectangle alloc = a.getBounds();
Document doc = getDocument();
int x = (int) fx;
int y = (int) fy;
if (y < alloc.y) {
// above the area covered by this icon, so the the position
// is assumed to be the start of the coverage for this view.
return getStartOffset();
} else if (y > alloc.y + alloc.height) {
// below the area covered by this icon, so the the position
// is assumed to be the end of the coverage for this view.
return getEndOffset() - 1;
} else {
// positioned within the coverage of this view vertically,
// so we figure out which line the point corresponds to.
// if the line is greater than the number of lines contained, then
// simply use the last line as it represents the last possible place
// we can position to.
Element map = doc.getDefaultRootElement();
int fontHeight = metrics.getHeight();
int lineIndex = (fontHeight > 0 ?
Math.abs((y - alloc.y) / fontHeight) :
map.getElementCount() - 1);
if (lineIndex >= map.getElementCount()) {
return getEndOffset() - 1;
}
Element line = map.getElement(lineIndex);
int dx = 0;
if (lineIndex == 0) {
//alloc.x += firstLineOffset;
// alloc.width -= firstLineOffset;
}
if (x < alloc.x) {
// point is to the left of the line
return line.getStartOffset();
} else if (x > alloc.x + alloc.width) {
// point is to the right of the line
return line.getEndOffset() - 1;
} else {
// Determine the offset into the text
try {
int p0 = line.getStartOffset();
int p1 = line.getEndOffset() - 1;
Segment s = new Segment();
doc.getText(p0, p1 - p0, s);
int tabBase = alloc.x;
int offs = p0 + UniTools.getTabbedTextOffset(s, metrics,
tabBase, x, this, p0);
//SegmentCache.releaseSharedSegment(s);
return offs;
} catch (BadLocationException e) {
// should not happen
return -1;
}
}
}
}
}

View File

@@ -0,0 +1,155 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane;
import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Segment;
/**
* A Token in a Document. Tokens do NOT store a reference to the
* underlying SyntaxDocument, and must generally be obtained from
* the SyntaxDocument methods. The reason for not storing the
* SyntaxDocument is simply for memory, as the number of Tokens
* per document can be large, you may end up with twice the memory
* in a SyntaxDocument with Tokens than a simple PlainDocument.
*
* @author Ayman Al-Sairafi
*/
public class Token implements Serializable, Comparable {
public final TokenType type;
public final int start;
public final int length;
/**
* the pair value to use if this token is one of a pair:
* This is how it is used:
* The openning part will have a positive number X
* The closing part will have a negative number X
* X should be unique for a pair:
* e.g. for [ pairValue = +1
* for ] pairValue = -1
*/
public final byte pairValue;
/**
* The kind of the Document. This is only needed if proper Parsing
* of a document is needed and it makes certain operations faster.
* You can use any of the supplied Generic Values, or create your
* language specific uses by using USER_FIRST + x;
*/
public final short kind = 0;
/**
* Constructs a new token
* @param type
* @param start
* @param length
*/
public Token(TokenType type, int start, int length) {
this.type = type;
this.start = start;
this.length = length;
this.pairValue = 0;
}
/**
* Construct a new part of pair token
* @param type
* @param start
* @param length
* @param pairValue
*/
public Token(TokenType type, int start, int length, byte pairValue) {
this.type = type;
this.start = start;
this.length = length;
this.pairValue = pairValue;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Object) {
Token token = (Token) obj;
return ((this.start == token.start) &&
(this.length == token.length) &&
(this.type.equals(token.type)));
} else {
return false;
}
}
@Override
public int hashCode() {
return start;
}
@Override
public String toString() {
if (pairValue == 0) {
return String.format("%s (%d, %d)", type, start, length);
} else {
return String.format("%s (%d, %d) (%d)", type, start, length, pairValue);
}
}
@Override
public int compareTo(Object o) {
Token t = (Token) o;
if (this.start != t.start) {
return (this.start - t.start);
} else if (this.length != t.length) {
return (this.length - t.length);
} else {
return this.type.compareTo(t.type);
}
}
/**
* return the end position of the token.
* @return start + length
*/
public int end() {
return start + length;
}
/**
* Get the text of the token from this document
* @param doc
* @return
*/
public CharSequence getText(Document doc) {
Segment text = new Segment();
try {
doc.getText(start, length, text);
} catch (BadLocationException ex) {
Logger.getLogger(Token.class.getName()).log(Level.SEVERE, null, ex);
} finally {
return text;
}
}
public String getString(Document doc) {
String result = "";
try {
result = doc.getText(start, length);
} catch (BadLocationException ex) {
Logger.getLogger(Token.class.getName()).log(Level.SEVERE, null, ex);
} finally {
return result;
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane;
import java.io.Serializable;
import java.util.Comparator;
/**
* Two comparators to compare Tokens.
* @author Ayman Al-Sairafi
*/
public class TokenComparators {
public static final Comparator<Token> LONGEST_FIRST = new LongestFirst();
public static final Comparator<Token> SHORTEST_FIRST = new ShortestFirst();
private static class LongestFirst implements Comparator<Token>, Serializable {
@Override
public int compare(Token t1, Token t2) {
if (t1.start != t2.start) {
return (t1.start - t2.start);
} else if (t1.length != t2.length) {
return (t2.length - t1.length);
} else {
return t1.type.compareTo(t2.type);
}
}
}
private static class ShortestFirst implements Comparator<Token>, Serializable {
@Override
public int compare(Token t1, Token t2) {
if (t1.start != t2.start) {
return (t1.start - t2.start);
} else if (t1.length != t2.length) {
return (t1.length - t2.length);
} else {
return t1.type.compareTo(t2.type);
}
}
}
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane;
/**
* Constants used by Tokens.
* @author Ayman Al-Sairafi
*/
public class TokenConstants {
/**
* Token Kinds
*/
// Operators and separators - Suitable for Java Type Languages
public static final short EQ = 1; // =
public static final short GT = 2; // >
public static final short LT = 3; // <
public static final short NOT = 4; // !
public static final short COMP = 5; // ~
public static final short QUESTION = 6; // ?
public static final short COLON = 7; // :
public static final short EQEQ = 8; // ==
public static final short LTEQ = 9; // <=
public static final short GTEQ = 10; // >=
public static final short NOTEQ = 11; // !=
public static final short ANDAND = 12; // &&
public static final short OROR = 13; // ||
public static final short PLUSPLUS = 14; // ++
public static final short MINUSMINUS = 15; // --
public static final short PLUS = 16; // +
public static final short MINUS = 17; // -
public static final short MULT = 18; // *
public static final short DIV = 19; // /
public static final short AND = 20; // &
public static final short OR = 21; // |
public static final short XOR = 22; // ^
public static final short MOD = 23; // %
public static final short LSHIFT = 24; // <<
public static final short RSHIFT = 25; // >>
public static final short URSHIFT = 26; // >>>
public static final short PLUSEQ = 27; // +=
public static final short MINUSEQ = 28; // -=
public static final short MULTEQ = 29; // *=
public static final short DIVEQ = 30; // /=
public static final short ANDEQ = 31; // &=
public static final short OREQ = 32; // |=
public static final short XOREQ = 33; // ^=
public static final short MODEQ = 34; // %=
public static final short LSHIFTEQ = 35; // <<=
public static final short RSHIFTEQ = 36; // >>=
public static final short URSHIFTEQ = 37; // >>>=
public static final short LPAREN = 38; // (
public static final short RPAREN = 39; // )
public static final short LBRACE = 40; // {
public static final short RBRACE = 41; // }
public static final short LBRACK = 42; // [
public static final short RBRACK = 43; // ]
public static final short SEMICOLON = 44; // ;
public static final short COMMA = 46; // ,
public static final short DOT = 47; // .
// Keywords for Java Type Languages
public static final short KW_START = 255;
public static final short KW_abstract = KW_START + 0;
public static final short KW_assert = KW_START + 1;
public static final short KW_boolean = KW_START + 2;
public static final short KW_break = KW_START + 3;
public static final short KW_byte = KW_START + 4;
public static final short KW_case = KW_START + 5;
public static final short KW_catch = KW_START + 6;
public static final short KW_char = KW_START + 7;
public static final short KW_class = KW_START + 8;
public static final short KW_const = KW_START + 9;
public static final short KW_continue = KW_START + 10;
public static final short KW_do = KW_START + 11;
public static final short KW_double = KW_START + 12;
public static final short KW_else = KW_START + 13;
public static final short KW_extends = KW_START + 14;
public static final short KW_final = KW_START + 15;
public static final short KW_finally = KW_START + 16;
public static final short KW_float = KW_START + 17;
public static final short KW_for = KW_START + 18;
public static final short KW_default = KW_START + 19;
public static final short KW_implements = KW_START + 20;
public static final short KW_import = KW_START + 21;
public static final short KW_instanceof = KW_START + 22;
public static final short KW_int = KW_START + 23;
public static final short KW_interface = KW_START + 24;
public static final short KW_long = KW_START + 25;
public static final short KW_native = KW_START + 26;
public static final short KW_new = KW_START + 27;
public static final short KW_goto = KW_START + 28;
public static final short KW_if = KW_START + 29;
public static final short KW_public = KW_START + 30;
public static final short KW_short = KW_START + 31;
public static final short KW_super = KW_START + 32;
public static final short KW_switch = KW_START + 33;
public static final short KW_synchronized = KW_START + 34;
public static final short KW_package = KW_START + 35;
public static final short KW_private = KW_START + 36;
public static final short KW_protected = KW_START + 37;
public static final short KW_transient = KW_START + 38;
public static final short KW_return = KW_START + 39;
public static final short KW_void = KW_START + 40;
public static final short KW_static = KW_START + 41;
public static final short KW_while = KW_START + 42;
public static final short KW_this = KW_START + 43;
public static final short KW_throw = KW_START + 44;
public static final short KW_throws = KW_START + 45;
public static final short KW_try = KW_START + 46;
public static final short KW_volatile = KW_START + 47;
public static final short KW_strictfp = KW_START + 48;
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane;
/**
* These are the various token types supported by JSyntaxPane.
*
* @author ayman
*/
public enum TokenType {
OPERATOR, // Language operators
DELIMITER, // Delimiters. Constructs that are not necessarily operators for a language
KEYWORD, // language reserved keywords
KEYWORD2, // Other language reserved keywords, like C #defines
IDENTIFIER, // identifiers, variable names, class names
NUMBER, // numbers in various formats
STRING, // String
STRING2, // For highlighting meta chars within a String
COMMENT, // comments
COMMENT2, // special stuff within comments
REGEX, // regular expressions
REGEX2, // special chars within regular expressions
TYPE, // Types, usually not keywords, but supported by the language
TYPE2, // Types from standard libraries
TYPE3, // Types for users
DEFAULT, // any other text
WARNING, // Text that should be highlighted as a warning
ERROR; // Text that signals an error
/**
* Tests if the given token is a Comment Token.
* @param t
* @return
*/
public static boolean isComment(Token t) {
if (t != null && (t.type == COMMENT || t.type == COMMENT2)) {
return true;
} else {
return false;
}
}
/**
* Tests if the given token is a Keyword Token.
* @param t
* @return
*/
public static boolean isKeyword(Token t) {
if (t != null && (t.type == KEYWORD || t.type == KEYWORD2)) {
return true;
} else {
return false;
}
}
/**
* Tests if the given token is a String Token.
* @param t
* @return
*/
public static boolean isString(Token t) {
if (t != null && (t.type == STRING || t.type == STRING2)) {
return true;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,154 @@
package jsyntaxpane;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JLabel;
import javax.swing.text.Segment;
import javax.swing.text.TabExpander;
import javax.swing.text.Utilities;
import javax.swing.text.View;
/**
*
* @author JPEXS
*/
public class UniTools {
private static List<String> backupFonts =new ArrayList<String>();
private static boolean fontExists(String name){
GraphicsEnvironment g=GraphicsEnvironment.getLocalGraphicsEnvironment();
List<String> availFonts=Arrays.asList(g.getAvailableFontFamilyNames());
for(int i=0;i<availFonts.size();i++){
availFonts.set(i, availFonts.get(i).toLowerCase());
}
return availFonts.contains(name.toLowerCase());
}
private static String backupCandidates[] = new String[]{"Unifont","Arial Unicode MS"};
private static Font defaultUniFont=null;
static {
for(String bc:backupCandidates){
if(fontExists(bc)){
defaultUniFont = new Font(bc,Font.PLAIN,10);
}
}
if(defaultUniFont==null){
defaultUniFont = new JLabel().getFont();
}
}
public static int getTabbedTextOffset(Segment segment, FontMetrics metrics, int tabBase,int x,TabExpander e, int startOffset){
List<Segment> segments=new ArrayList<Segment>();
List<Boolean> unis=new ArrayList<Boolean>();
Font origFont=metrics.getFont();
getSegments(origFont, segment, segments, unis);
Graphics g=new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB).getGraphics();
Font uniFont = defaultUniFont.deriveFont(origFont.getStyle(),origFont.getSize2D());
int ret=0;
int pos=0;
for(int i=0;i<segments.size();i++){
Segment seg=segments.get(i);
ret += Utilities.getTabbedTextOffset(seg, g.getFontMetrics(unis.get(i)?uniFont:origFont), tabBase,x, e, startOffset+pos);
pos += seg.length();
}
return ret;
}
private static void getSegments(Font f,Segment segment,List<Segment> segments,List<Boolean> unis){
int start=0;
int len=0;
boolean uni=false;
for(int i=0;i<segment.length();i++){
boolean newuni=false;
if(!f.canDisplay(segment.charAt(i))){
newuni=true;
}
if(i>0 && uni!=newuni){
Segment s =new Segment(segment.array, segment.offset+start, len);
segments.add(s);
unis.add(uni);
start = i;
len=0;
}
uni=newuni;
len++;
}
if(len>0){
Segment s =new Segment(segment.array, segment.offset+start, len);
segments.add(s);
unis.add(uni);
}
}
public static int getTabbedTextWidth(Segment segment,FontMetrics f,int x,TabExpander e, int startOffset){
Graphics g=new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB).getGraphics();
g.setFont(f.getFont());
return getTabbedTextWidth(g,segment,x,e,startOffset);
}
public static int getTabbedTextWidth(Graphics g,Segment segment,int x,TabExpander e, int startOffset){
List<Segment> segments=new ArrayList<Segment>();
List<Boolean> unis=new ArrayList<Boolean>();
getSegments(g.getFont(), segment, segments, unis);
Font origFont=g.getFont();
Font uniFont = defaultUniFont.deriveFont(origFont.getStyle(),origFont.getSize2D());
int ret=0;
int pos=0;
for(int i=0;i<segments.size();i++){
Segment seg=segments.get(i);
ret += Utilities.getTabbedTextWidth(seg, g.getFontMetrics(unis.get(i)?uniFont:origFont), 0, e, startOffset+pos);
pos += seg.length();
}
return ret;
}
public static int drawTabbedText(Segment segment, int x, int y, Graphics g, TabExpander e, int startOffset){
List<Segment> segments=new ArrayList<Segment>();
List<Boolean> unis=new ArrayList<Boolean>();
getSegments(g.getFont(), segment, segments, unis);
Font origFont=g.getFont();
Font uniFont = defaultUniFont.deriveFont(origFont.getStyle(),origFont.getSize2D());
int ret=x;
int pos=0;
for(int i=0;i<segments.size();i++){
Segment seg=segments.get(i);
if(unis.get(i)){
g.setFont(uniFont);
}else{
g.setFont(origFont);
}
ret = Utilities.drawTabbedText(seg, ret, y, g, e, startOffset+pos);
pos += seg.length();
}
g.setFont(origFont);
return ret;
}
public static int stringWidth(Graphics g,String string){
List<Segment> segments=new ArrayList<Segment>();
List<Boolean> unis=new ArrayList<Boolean>();
Segment segment=new Segment(string.toCharArray(), 0, string.length());
getSegments(g.getFont(), segment, segments, unis);
Font origFont=g.getFont();
Font uniFont = defaultUniFont.deriveFont(origFont.getStyle(),origFont.getSize2D());
int ret=0;
for(int i=0;i<segments.size();i++){
Segment seg=segments.get(i);
ret+=g.getFontMetrics(unis.get(i)?uniFont:origFont).stringWidth(seg.toString());
}
return ret;
}
}

View File

@@ -0,0 +1,623 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.Component;
import java.awt.Frame;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.KeyEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.Action;
import javax.swing.JComboBox;
import javax.swing.JEditorPane;
import javax.swing.MutableComboBoxModel;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.EditorKit;
import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import javax.swing.text.PlainDocument;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
/**
* Various utility methods to work on JEditorPane and its SyntaxDocument
* for use by Actions
*
* @author Ayman Al-Sairafi
*/
public class ActionUtils {
private ActionUtils() {
}
private static ActionUtils instance = null;
/**
* Get the Singleton instance. Will be created lazily.
* @return
*/
public static synchronized ActionUtils getInstance() {
if(instance == null) {
instance = new ActionUtils();
}
return instance;
}
/**
* Get the indentation of a line of text. This is the subString from
* beginning of line to the first non-space char
* @param line the line of text
* @return indentation of line.
*/
public static String getIndent(String line) {
if (line == null || line.length() == 0) {
return "";
}
int i = 0;
while (i < line.length() && line.charAt(i) == ' ') {
i++;
}
return line.substring(0, i);
}
/**
* Return the lines that span the selection (split as an array of Strings)
* if there is no selection then current line is returned.
*
* Note that the strings returned will not contain the terminating line feeds
* If the document is empty, then an empty string array is returned. So
* you can always iterate over the returned array without a null check
*
* The text component will then have the full lines set as selection
* @param target
* @return String[] of lines spanning selection / or line containing dot
*/
public static String[] getSelectedLines(JTextComponent target) {
String[] lines = null;
try {
PlainDocument pDoc = (PlainDocument) target.getDocument();
int start = pDoc.getParagraphElement(target.getSelectionStart()).getStartOffset();
int end;
if (target.getSelectionStart() == target.getSelectionEnd()) {
end = pDoc.getParagraphElement(target.getSelectionEnd()).getEndOffset();
} else {
// if more than one line is selected, we need to subtract one from the end
// so that we do not select the line with the caret and no selection in it
end = pDoc.getParagraphElement(target.getSelectionEnd() - 1).getEndOffset();
}
target.select(start, end);
lines = pDoc.getText(start, end - start).split("\n");
target.select(start, end);
} catch (BadLocationException ex) {
Logger.getLogger(ActionUtils.class.getName()).log(Level.SEVERE, null, ex);
lines = EMPTY_STRING_ARRAY;
}
return lines;
}
/**
* Return the line of text at the TextComponent's current position
* @param target
* @return
*/
public static String getLine(JTextComponent target) {
return getLineAt(target, target.getCaretPosition());
}
/**
* Return the line of text at the given position. The returned value may
* be null. It will not contain the trailing new-line character.
* @param target the text component
* @param pos char position
* @return
*/
public static String getLineAt(JTextComponent target, int pos) {
String line = null;
Document doc = target.getDocument();
if (doc instanceof PlainDocument) {
PlainDocument pDoc = (PlainDocument) doc;
int start = pDoc.getParagraphElement(pos).getStartOffset();
int end = pDoc.getParagraphElement(pos).getEndOffset();
try {
line = doc.getText(start, end - start);
if (line != null && line.endsWith("\n")) {
line = line.substring(0, line.length() - 1);
}
} catch (BadLocationException ex) {
Logger.getLogger(ActionUtils.class.getName()).log(Level.SEVERE, null, ex);
}
}
return line;
}
/**
* Returns the Frame that contains this component or null if the component
* is not within a Window or the containing window is not a frame
* @param comp
* @return
*/
public static Frame getFrameFor(Component comp) {
Window w = SwingUtilities.getWindowAncestor(comp);
if (w != null && w instanceof Frame) {
Frame frame = (Frame) w;
return frame;
}
return null;
}
/**
* Returns the the Token at pos as a String
* @param doc
* @param pos
* @return
*/
public static String getTokenStringAt(
SyntaxDocument doc, int pos) {
String word = "";
Token t = doc.getTokenAt(pos);
if (t != null) {
try {
word = doc.getText(t.start, t.length);
} catch (BadLocationException ex) {
Logger.getLogger(ActionUtils.class.getName()).log(Level.SEVERE, null, ex);
}
}
return word;
}
/**
* A helper function that will return the SyntaxDocument attached to the
* given text component. Return null if the document is not a
* SyntaxDocument, or if the text component is null
* @param component
* @return
*/
public static SyntaxDocument getSyntaxDocument(JTextComponent component) {
if (component == null) {
return null;
}
Document doc = component.getDocument();
if (doc instanceof SyntaxDocument) {
return (SyntaxDocument) doc;
} else {
return null;
}
}
/**
* Gets the Line Number at the give position of the editor component.
* The first line number is ZERO
* @param editor
* @param pos
* @return line number
* @throws javax.swing.text.BadLocationException
*/
public static int getLineNumber(JTextComponent editor, int pos)
throws BadLocationException {
if (getSyntaxDocument(editor) != null) {
SyntaxDocument sdoc = getSyntaxDocument(editor);
return sdoc.getLineNumberAt(pos);
} else {
Document doc = editor.getDocument();
return doc.getDefaultRootElement().getElementIndex(pos);
}
}
/**
* Gets the column number at given position of editor. The first column is
* ZERO
* @param editor
* @param pos
* @return the 0 based column number
* @throws javax.swing.text.BadLocationException
*/
public static int getColumnNumber(JTextComponent editor, int pos)
throws BadLocationException {
// speedup if the pos is 0
if(pos == 0) {
return 0;
}
Rectangle r = editor.modelToView(pos);
int start = editor.viewToModel(new Point(0, r.y));
int column = pos - start;
return column;
}
/**
* Get the closest position within the document of the component that
* has given line and column.
* @param editor
* @param line the first being 1
* @param column the first being 1
* @return the closest positon for the text component at given line and
* column
*/
public static int getDocumentPosition(JTextComponent editor, int line,
int column) {
int lineHeight = editor.getFontMetrics(editor.getFont()).getHeight();
int charWidth = editor.getFontMetrics(editor.getFont()).charWidth('m');
int y = line * lineHeight;
int x = column * charWidth;
Point pt = new Point(x, y);
int pos = editor.viewToModel(pt);
return pos;
}
public static int getLineCount(JTextComponent pane) {
SyntaxDocument sdoc = getSyntaxDocument(pane);
if (sdoc != null) {
return sdoc.getLineCount();
}
int count = 0;
try {
int p = pane.getDocument().getLength() - 1;
if (p > 0) {
count = getLineNumber(pane, p);
}
} catch (BadLocationException ex) {
Logger.getLogger(ActionUtils.class.getName()).log(Level.SEVERE, null, ex);
}
return count;
}
/**
* Insert the given item into the combo box, and set it as first selected
* item. If the item already exists, it is removed, so there are no
* duplicates.
* @param combo
* @param item the item to insert. if it's null, then nothing is inserted
*/
public static void insertIntoCombo(JComboBox combo, Object item) {
if(item == null) {
return;
}
MutableComboBoxModel model = (MutableComboBoxModel) combo.getModel();
if (model.getSize() == 0) {
model.insertElementAt(item, 0);
return;
}
Object o = model.getElementAt(0);
if (o.equals(item)) {
return;
}
model.removeElement(item);
model.insertElementAt(item, 0);
combo.setSelectedIndex(0);
}
public static void insertMagicString(JTextComponent target, String result) {
try {
insertMagicString(target, target.getCaretPosition(), result);
} catch (BadLocationException ex) {
Logger.getLogger(ActionUtils.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Repeat the string source repeat times.
* If repeats == 0 then empty String is returned
* if source is null, then empty string is returned
* @param source
* @param repeat
* @return source String repeated repeat times.
*/
public static String repeatString(String source, int repeat) {
if (repeat < 0) {
throw new IllegalArgumentException("Cannot repeat " + repeat + " times.");
}
if (repeat == 0 || source == null || source.length() == 0) {
return "";
}
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < repeat; i++) {
buffer.append(source);
}
return buffer.toString();
}
/**
* Checks if the given string is null, empty or contains whitespace only
* @param string
* @return true if string is null, empty or contains whitespace only, false
* otherwise.
*/
public static boolean isEmptyOrBlanks(String string) {
if (string == null || string.length() == 0) {
return true;
}
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
if (!Character.isWhitespace(c)) {
return false;
}
}
return true;
}
/**
* Return the TabStop property for the given text component, or 0 if not
* used
* @param text
* @return
*/
public static int getTabSize(JTextComponent text) {
Integer tabs = (Integer) text.getDocument().getProperty(PlainDocument.tabSizeAttribute);
return (null == tabs) ? 0 : tabs.intValue();
}
/**
* Insert the given String into the textcomponent. If the string contains
* the | vertical BAr char, then it will not be inserted, and the cursor will
* be set to its location.
* If there are TWO vertical bars, then the text between them will be selected
* If the toInsert String is multiLine, then indentation of all following lines
* will be the same as the first line. TAB characters will be replaced by
* the number of spaces in the document's TAB property.
* @param target
* @param dot
* @param toInsert
* @throws javax.swing.text.BadLocationException
*/
public static void insertMagicString(JTextComponent target, int dot, String toInsert)
throws BadLocationException {
Document doc = target.getDocument();
String[] lines = toInsert.split("\n");
if (lines.length > 1) {
// multi line strings will need to be indented
String tabToSpaces = getTab(target);
String currentLine = getLineAt(target, dot);
String currentIndent = getIndent(currentLine);
StringBuilder sb = new StringBuilder(toInsert.length());
boolean firstLine = true;
for (String l : lines) {
if (!firstLine) {
sb.append(currentIndent);
}
firstLine = false;
// replace tabs with spaces.
sb.append(l.replace("\t", tabToSpaces));
sb.append("\n");
}
toInsert = sb.toString();
}
if (toInsert.indexOf('|') >= 0) {
int ofst = toInsert.indexOf('|');
int ofst2 = toInsert.indexOf('|', ofst + 1);
toInsert = toInsert.replace("|", "");
doc.insertString(dot, toInsert, null);
dot = target.getCaretPosition();
int strLength = toInsert.length();
if (ofst2 > 0) {
// note that we already removed the first |, so end offset is now
// one less than what it was.
target.select(dot + ofst - strLength, dot + ofst2 - strLength - 1);
} else {
target.setCaretPosition(dot + ofst - strLength);
}
} else {
doc.insertString(dot, toInsert, null);
}
}
/**
* Expand the string template and replaces the selection with the expansion
* of the template. The template String may contain any of the following
* special tags.
*
* <li>{@code #{selection}} replaced with the selection, if any. If there is
* no selection, then the {@code #{selection}} tag will be removed.
* <li>{@code #{p:any text}} will be replaced by {@code any text} and then
* set selection to {@code any text}
*
* This method properly handles indentation as follows:
* The indentation of the whole block will match the indentation of the caret
* line, or the line with the beginning of the selection, if the selection is
* in whole line, i.e.e one or more lines of selected text. {@see selectLines()}
*
* @param target JEditorCOmponent to be affected
* @param templateLines template split as a String array of lines.
*
* @see insertLinesTemplate
*/
public static void insertLinesTemplate(JTextComponent target, String[] templateLines) {
// get some stuff we'll need:
String thisIndent = getIndent(getLineAt(target, target.getSelectionStart()));
String[] selLines = getSelectedLines(target);
int selStart = -1, selEnd = -1;
StringBuffer sb = new StringBuffer();
for (String tLine : templateLines) {
int selNdx = tLine.indexOf("#{selection}");
if (selNdx >= 0) {
// for each of the selected lines:
for (String selLine : selLines) {
sb.append(tLine.subSequence(0, selNdx));
sb.append(selLine);
sb.append('\n');
}
} else {
sb.append(thisIndent);
// now check for any ptags
Matcher pm = PTAGS_PATTERN.matcher(tLine);
int lineStart = sb.length();
while (pm.find()) {
selStart = pm.start() + lineStart;
pm.appendReplacement(sb, pm.group(1));
selEnd = sb.length();
}
pm.appendTail(sb);
sb.append('\n');
}
}
int ofst = target.getSelectionStart();
target.replaceSelection(sb.toString());
if (selStart >= 0) {
// target.setCaretPosition(selStart);
target.select(ofst + selStart, ofst + selEnd);
}
}
/**
* Expand the string template and replaces the selection with the expansion
* of the template. The template String may contain any of the following
* special tags.
*
* <li>{@code #{selection}} replaced with the selection, if any. If there is
* no selection, then the {@code #{selection}} tag will be removed.
* <li>{@code #{p:AnyText}} will be replaced by {@code any text} and then
* set the text selection to {@code AnyText}
*
* This methood does NOT perform any indentation and the template should
* generally span one line only
*
* @param target
* @param template
*/
public static void insertSimpleTemplate(JTextComponent target, String template) {
String selected = target.getSelectedText();
selected = (selected == null) ? "" : selected;
StringBuffer sb = new StringBuffer(template.length());
Matcher pm = PTAGS_PATTERN.matcher(template.replace(TEMPLATE_SELECTION, selected));
int selStart = -1, selEnd = -1;
int lineStart = 0;
while (pm.find()) {
selStart = pm.start() + lineStart;
pm.appendReplacement(sb, pm.group(1));
selEnd = sb.length();
}
pm.appendTail(sb);
// String expanded = template.replace(TEMPLATE_SELECTION, selected);
if (selStart >= 0) {
selStart += target.getSelectionStart();
selEnd += target.getSelectionStart();
}
target.replaceSelection(sb.toString());
if (selStart >= 0) {
// target.setCaretPosition(selStart);
target.select(selStart, selEnd);
}
}
/**
* If the selection is multi lined, then the full lines are selected,
* otherwise, nothing is done.
* @param target
* @return true if the selection is multi-line, or a whole line
*/
public static boolean selectLines(JTextComponent target) {
if (target.getSelectionStart() == target.getSelectionEnd()) {
return false;
}
PlainDocument pDoc = (PlainDocument) target.getDocument();
Element es = pDoc.getParagraphElement(target.getSelectionStart());
// if more than one line is selected, we need to subtract one from the end
// so that we do not select the line with the caret and no selection in it
Element ee = pDoc.getParagraphElement(target.getSelectionEnd() - 1);
if (es.equals(ee) && ee.getEndOffset() != target.getSelectionEnd()) {
return false;
}
int start = es.getStartOffset();
int end = ee.getEndOffset();
target.select(start, end - 1);
return true;
}
/**
* Sets the caret position of the given target to the given line and column
* @param target
* @param line the first being 1
* @param column the first being 1
*/
public static void setCaretPosition(JTextComponent target, int line, int column) {
int p = getDocumentPosition(target, line, column);
target.setCaretPosition(p);
}
/**
* Return a string with number of spaces equal to the tab-stop of the TextComponent
* @param target
* @return
*/
public static String getTab(JTextComponent target) {
return SPACES.substring(0, getTabSize(target));
}
/**
* Searches all actions of a JTextComponent for ab action of the given class and returns
* the first one that matches that class, or null if no Action is found
* @param <T>
* @param target
* @param aClass
* @return Action object of that class or null
*/
public static <T extends Action> T getAction(JTextComponent target, Class<T> aClass) {
for (Object k : target.getActionMap().allKeys()) {
Action a = target.getActionMap().get(k);
if (aClass.isInstance(a)) {
@SuppressWarnings("unchecked")
T t = (T) a;
return t;
}
}
return null;
}
/**
* Return the DefaultSyntaxKit of this target, or null if the target does not
* have a DefaultSyntaxKit
* @param target
* @return kit or null
*/
public static DefaultSyntaxKit getSyntaxKit(JTextComponent target) {
DefaultSyntaxKit kit = null;
if (target instanceof JEditorPane) {
JEditorPane jEditorPane = (JEditorPane) target;
EditorKit k = jEditorPane.getEditorKit();
if (k instanceof DefaultSyntaxKit) {
kit = (DefaultSyntaxKit) k;
}
}
return kit;
}
/**
* Create and send a KeyPress KeyEvent to the component given
* @param target Editor to get the action
* @param v_key from KeyEvent.V_ constants
* @param modifiers from KeyEvent.*MASK constants
*/
public static void sendKeyPress(JTextComponent target, int v_key, int modifiers) {
KeyEvent ke = new KeyEvent(target, KeyEvent.KEY_PRESSED, System.currentTimeMillis(),
modifiers, v_key, KeyEvent.CHAR_UNDEFINED);
target.dispatchEvent(ke);
}
// This is used internally to avoid NPE if we have no Strings
final static String[] EMPTY_STRING_ARRAY = new String[0];
// This is used to quickly create Strings of at most 16 spaces (using substring)
final static String SPACES = " ";
/**
* The Pattern to use for PTags in insertSimpleTemplate
*/
public static final Pattern PTAGS_PATTERN = Pattern.compile("\\#\\{p:([^}]*)\\}");
public static final String TEMPLATE_SELECTION = "#{selection}";
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import javax.swing.JLabel;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
/**
* This class can be used to display the caret location in friendly manner for
* an EditorPane.
*
* @author Ayman Al-Sairafi
*/
public class CaretMonitor implements CaretListener {
private JLabel label;
private JTextComponent text;
/**
* The format string to use when there is no selected:
* the arguments are:
* 1 based line number
* 1 based column number
* 0 based position
*/
private String noSelectionFormat = "%d:%d (%d)";
/**
* The format string to use when something is selected:
* the arguments are:
* 1 based line number for selection start
* 1 based column number for selection start
* 1 based line number for selection end
* 1 based column number for selection end
* length of selection
* 0 based start position
* 0 based end position
*/
private String selectionFormat = "%d:%d - %d:%d (%d)";
public CaretMonitor(JTextComponent text, JLabel label) {
this.label = label;
this.text = text;
text.addCaretListener(this);
updateLabel(text.getCaretPosition());
}
@Override
public void caretUpdate(CaretEvent evt) {
updateLabel(evt.getDot());
}
protected void updateLabel(int pos) {
if (text.getDocument() instanceof SyntaxDocument) {
try {
if (text.getSelectionStart() == text.getSelectionEnd()) {
String loc = String.format(noSelectionFormat,
ActionUtils.getLineNumber(text, pos) + 1,
ActionUtils.getColumnNumber(text, pos) + 1,
pos);
label.setText(loc);
} else {
int start = text.getSelectionStart();
int end = text.getSelectionEnd();
String loc = String.format(selectionFormat,
ActionUtils.getLineNumber(text, start) + 1,
ActionUtils.getColumnNumber(text, start) + 1,
ActionUtils.getLineNumber(text, end) + 1,
ActionUtils.getColumnNumber(text, end) + 1,
(end - start),
start,
end);
label.setText(loc);
}
} catch (BadLocationException ex) {
label.setText("Ex: " + ex.getMessage());
}
} else {
label.setText(String.format(noSelectionFormat, 1, 1, 1));
}
}
@Override
protected void finalize() throws Throwable {
text.removeCaretListener(this);
super.finalize();
}
public String getNoSelectionFormat() {
return noSelectionFormat;
}
public void setNoSelectionFormat(String noSelectionFormat) {
this.noSelectionFormat = noSelectionFormat;
}
public String getSelectionFormat() {
return selectionFormat;
}
public void setSelectionFormat(String selectionFormat) {
this.selectionFormat = selectionFormat;
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.Map;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
import jsyntaxpane.actions.gui.ComboCompletionDialog;
import jsyntaxpane.util.JarServiceProvider;
/**
* ComboBox like Completion Action:
* This will display a list of items to choose from, it can be used similar to
* IntelliSense. The List is obtained from a plain text file, each line being
* an item in the list.
*
* @author Ayman Al-Sairafi
*/
public class ComboCompletionAction extends DefaultSyntaxAction {
Map<String, String> completions;
ComboCompletionDialog dlg;
private List<String> items;
public ComboCompletionAction() {
super("COMBO_COMPLETION");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sdoc,
int dot, ActionEvent e) {
if (sdoc == null) {
return;
}
Token token = sdoc.getTokenAt(dot);
String abbrev = "";
if (token != null) {
abbrev = token.getString(sdoc);
target.select(token.start, token.end());
}
if (dlg == null) {
dlg = new ComboCompletionDialog(target);
}
dlg.displayFor(abbrev, items);
}
public void setItemsURL(String value) {
items = JarServiceProvider.readLines(value);
}
/**
* Gets the items to display in the combo
* @return
*/
public List<String> getItems() {
return items;
}
/**
* Sets the items to display in the combo.
* @param items
*/
public void setItems(List<String> items) {
this.items = items;
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
import jsyntaxpane.actions.gui.ComboCompletionDialog;
import jsyntaxpane.util.StringUtils;
/**
* This action will try to complete the word at the cursor by
* looking for a matching word in this document that starts with
* the same letters.
*
* This makes use of the SyntaxDocument.getWordAt, which requires
* a Regexp Pattern. The Pattern should match any word regardless of
* the Tokens.
*
* This Regexp is configurable with {@code ACTION_NAME.WordsRegexp}.
* The default Regexp is \w+ (any word char)
*
* @author Ayman Al-Sairafi
*/
public class CompleteWordAction extends DefaultSyntaxAction {
public CompleteWordAction() {
super("COMPLETE_WORD");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sdoc,
int dot, ActionEvent e) {
Token current = sdoc.getWordAt(dot, wordsPattern);
if (current == null) {
return;
}
String cw = current.getString(sdoc);
target.select(current.start, current.end());
sdoc.readLock();
List<String> matches = new ArrayList<String>();
Matcher m = sdoc.getMatcher(wordsPattern, 0, current.start);
addWords(m, cw, matches);
m = sdoc.getMatcher(wordsPattern, current.end(), sdoc.getLength() - current.end());
addWords(m, cw, matches);
sdoc.readUnlock();
if (matches.size() == 0) {
return;
}
if (matches.size() == 1) {
target.replaceSelection(matches.get(0));
return;
}
if (dlg == null) {
dlg = new ComboCompletionDialog(target);
}
dlg.displayFor(cw, matches);
}
public void setWordsRegexp(String value) {
wordsPattern = Pattern.compile(value);
}
/**
* Add words from the matcher m that match the word abbr to matches
* List
* @param m matcher instance, could be null, to iterate through
* @param abbr abbriviated word
* @param matches List of matches
*/
private void addWords(Matcher m, String abbr, List<String> matches) {
while (m != null && m.find()) {
String word = m.group();
if (StringUtils.camelCaseMatch(word, abbr)) {
if (!matches.contains(word)) {
matches.add(word);
}
}
}
}
private ComboCompletionDialog dlg;
private Pattern wordsPattern = DEFAULT_WORDS_REGEXP;
private static final Pattern DEFAULT_WORDS_REGEXP = Pattern.compile("\\w+");
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.net.URL;
import java.util.regex.Pattern;
import javax.swing.ImageIcon;
import javax.swing.text.JTextComponent;
import javax.swing.text.TextAction;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.util.Configuration;
import jsyntaxpane.util.ReflectUtils;
/**
* The DefaultSyntaxAction. You can extend this class or implement the interface
* SyntaxAction to create your own actions.
*
* @author Ayman Al-Sairafi
*/
abstract public class DefaultSyntaxAction extends TextAction implements SyntaxAction {
public DefaultSyntaxAction(String actionName) {
super(actionName);
putValue(NAME, actionName);
}
@Override
public void config(Configuration config, String name) {
// find setter methods for each property key:
String actionName = name.substring(ACTION_PREFIX.length());
for (Configuration.StringKeyMatcher m : config.getKeys(
Pattern.compile(Pattern.quote(name) + "\\.((\\w|-)+)"))) {
if (!ReflectUtils.callSetter(this, m.group1, m.value)) {
putValue(m.group1, m.value);
}
}
// if we did not put a name, use the action name
if (getValue(NAME) == null) {
putValue(NAME, actionName);
}
// if we did not put an icon, try and find one using our name
if (getValue(SMALL_ICON) == null) {
setSmallIcon(actionName + ".png");
}
}
@Override
public void actionPerformed(ActionEvent e) {
JTextComponent text = getTextComponent(e);
SyntaxDocument sdoc = ActionUtils.getSyntaxDocument(text);
if (text != null) {
actionPerformed(text, sdoc, text.getCaretPosition(), e);
}
}
/**
* Convenience method that will be called if the Action is performed on a
* JTextComponent. SyntaxActions should generally override this method.
* @param target (non-null JTextComponent from Action.getSource
* @param sDoc (SyntaxDOcument of the text component, could be null)
* @param dot (position of caret at text document)
* @param e actual ActionEvent passed to actionPerformed
*/
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public String toString() {
return "Action " + getValue(NAME) + "of type " + this.getClass().getSimpleName();
}
/**
* Configure the MenuText for the Action
* @param text
*/
public final void setMenuText(String text) {
putValue(NAME, text);
// also set the SHORT_DESCRIPTIOn if it was not set, so we have
// at least some tooltip for toolbar buttons
if (getValue(SHORT_DESCRIPTION) == null) {
putValue(SHORT_DESCRIPTION, text);
}
}
/**
* Configure the ToolTip for the Action
* @param text
*/
public final void setToolTip(String text) {
putValue(SHORT_DESCRIPTION, text);
}
/**
* Sets the Large Icon for this action from given url
*
* @param url
*/
public final void setLargeIcon(String url) {
URL loc = this.getClass().getResource(LARGE_ICONS_LOC_PREFIX + url);
if (loc != null) {
ImageIcon i = new ImageIcon(loc);
putValue(LARGE_ICON_KEY, i);
}
}
/**
* Configure the SmallIcon for the Action
* @param url
*/
public final void setSmallIcon(String url) {
URL loc = this.getClass().getResource(SMALL_ICONS_LOC_PREFIX + url);
if (loc != null) {
ImageIcon i = new ImageIcon(loc);
putValue(SMALL_ICON, i);
}
}
public static final String ACTION_PREFIX = "Action.";
public static final String SMALL_ICONS_LOC_PREFIX = "/META-INF/images/small-icons/";
public static final String LARGE_ICONS_LOC_PREFIX = "/META-INF/images/large-icons/";
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
/**
* This Action deletes the current line, or all the highlighted lines.
* @author Ayman Al-Sairafi
*/
public class DeleteLinesAction extends DefaultSyntaxAction {
public DeleteLinesAction() {
super("DELETE_LINES");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sdoc,
int dot, ActionEvent e) {
try {
int st = sdoc.getLineStartOffset(target.getSelectionStart());
int en = sdoc.getLineEndOffset(target.getSelectionEnd());
sdoc.remove(st, en - st);
} catch (BadLocationException ex) {
Logger.getLogger(DeleteLinesAction.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

View File

@@ -0,0 +1,275 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.Component;
import java.text.MessageFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.actions.gui.QuickFindDialog;
import jsyntaxpane.actions.gui.ReplaceDialog;
/**
* Data that is shared by Find / Replace and Find Next actions for a Document
* The data here will be added as a property of the Document using the key
* PROPERTY_KEY. Only through the getFtmEditor can you crate a new instance.
*
* The class is responsible for handling the doFind and doReplace all actions.
*
* The class is also responsible for displaying the Find / Replace dialog
*
* @author Ayman Al-Sairafi
*/
public class DocumentSearchData {
private static final String PROPERTY_KEY = "SearchData";
private Pattern pattern = null;
private boolean wrap = true;
private ReplaceDialog replaceDlg;
private QuickFindDialog quickFindDlg;
/**
* This prevent creating a new instance. You must call the getFromEditor
* to crate a new instance attached to a Document
*
*/
private DocumentSearchData() {
}
public Pattern getPattern() {
return pattern;
}
/**
* Set the pattern to the given compiled pattern.
* @see this#setPattern(String, boolean, boolean)
* @param pattern
*/
public void setPattern(Pattern pattern) {
this.pattern = pattern;
}
/**
* Sets the pattern from a string and flags
* @param pat String of pattern
* @param regex true if the pattern should be a regexp
* @param ignoreCase true to ignore case
* @throws java.util.regex.PatternSyntaxException
*/
public void setPattern(String pat, boolean regex, boolean ignoreCase)
throws PatternSyntaxException {
if (pat != null && pat.length() > 0) {
int flag = (regex) ? 0 : Pattern.LITERAL;
flag |= (ignoreCase) ? Pattern.CASE_INSENSITIVE : 0;
setPattern(Pattern.compile(pat, flag));
} else {
setPattern(null);
}
}
public boolean isWrap() {
return wrap;
}
public void setWrap(boolean wrap) {
this.wrap = wrap;
}
/**
* Get the Search data from a Document. If document does not have any
* search data, then a new instance is added, put and reurned.
* @param target JTextCOmponent we are attaching to
* @return
*/
public static DocumentSearchData getFromEditor(JTextComponent target) {
if (target == null) {
return null;
}
Object o = target.getDocument().getProperty(PROPERTY_KEY);
if (o instanceof DocumentSearchData) {
DocumentSearchData documentSearchData = (DocumentSearchData) o;
return documentSearchData;
} else {
DocumentSearchData newDSD = new DocumentSearchData();
target.getDocument().putProperty(PROPERTY_KEY, newDSD);
return newDSD;
}
}
/**
* Perform a replace all operation on the given component.
* Note that this create a new duplicate String big as the entire
* document and then assign it to the target text component
* @param target
* @param replacement
*/
public void doReplaceAll(JTextComponent target, String replacement) {
if (replacement == null) {
replacement = "";
}
SyntaxDocument sDoc = ActionUtils.getSyntaxDocument(target);
if (sDoc == null) {
return;
}
if (getPattern() == null) {
return;
}
Matcher matcher = sDoc.getMatcher(getPattern());
String newText = matcher.replaceAll(replacement);
try {
sDoc.replace(0, sDoc.getLength(), newText, null);
} catch (BadLocationException ex) {
Logger.getLogger(DocumentSearchData.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Replace single occurrence of match with the replacement.
* @param target
* @param replacement
*/
public void doReplace(JTextComponent target, String replacement) {
if (target.getSelectedText() != null) {
target.replaceSelection(replacement == null ? "" : replacement);
doFindNext(target);
}
}
/**
* FInd the previous match
* @param target
* @return
*/
public boolean doFindPrev(JTextComponent target) {
if (getPattern() == null) {
return false;
}
SyntaxDocument sDoc = ActionUtils.getSyntaxDocument(target);
if (sDoc == null) {
return false;
}
int dot = target.getSelectionStart();
Matcher matcher = sDoc.getMatcher(getPattern());
if (matcher == null) {
return false;
}
// we have no way of jumping to last match, so we need to
// go throw all matches, and stop when we reach current pos
int start = -1;
int end = -1;
while (matcher.find()) {
if (matcher.end() >= dot) {
break;
}
start = matcher.start();
end = matcher.end();
}
if (end > 0) {
target.select(start, end);
return true;
} else {
return false;
}
}
/**
* Perform a FindNext operation on the given text component. Position
* the caret at the start of the next found pattern.
* @param target
* @return true if pattern is found, false otherwise
*/
public boolean doFindNext(JTextComponent target) {
if (getPattern() == null) {
return false;
}
SyntaxDocument sDoc = ActionUtils.getSyntaxDocument(target);
if (sDoc == null) {
return false;
}
int start = target.getSelectionEnd();
if (target.getSelectionEnd() == target.getSelectionStart()) {
// we must advance the position by one, otherwise we will find
// the same text again
start++;
}
if (start >= sDoc.getLength()) {
start = sDoc.getLength();
}
Matcher matcher = sDoc.getMatcher(getPattern(), start);
if (matcher != null && matcher.find()) {
// since we used an offset in the matcher, the matcher location
// MUST be offset by that location
target.select(matcher.start() + start, matcher.end() + start);
return true;
} else {
if (isWrap()) {
matcher = sDoc.getMatcher(getPattern());
if (matcher != null && matcher.find()) {
target.select(matcher.start(), matcher.end());
return true;
} else {
return false;
}
} else {
return false;
}
}
}
/**
* Display an OptionPane dialog that the search string is not found
* @param target
*/
public void msgNotFound(Component target) {
JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(target),
MessageFormat.format(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("DocumentSearchData.SearchStringNotFound"), getPattern()),
java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("DocumentSearchData.Find"), JOptionPane.INFORMATION_MESSAGE);
}
public void showQuickFindDialogEx(JTextComponent target,boolean ignoreCase,boolean regularExpresion) {
if (quickFindDlg == null) {
quickFindDlg = new QuickFindDialog(target, this);
}
quickFindDlg.showFor(target);
quickFindDlg.setIgnoreCase(ignoreCase);
quickFindDlg.setRegularExpression(regularExpresion);
}
/**
* Show the Find and Replace dialog for the given frame
* @param target
*/
public void showReplaceDialog(JTextComponent target) {
if (replaceDlg == null) {
replaceDlg = new ReplaceDialog(target, this);
}
replaceDlg.setVisible(true);
}
public void showQuickFindDialog(JTextComponent target) {
if (quickFindDlg == null) {
quickFindDlg = new QuickFindDialog(target, this);
}
quickFindDlg.showFor(target);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
/**
* This Action duplicates the current line, or all the highlighted lines.
* @author Ayman Al-Sairafi
*/
public class DuplicateLinesAction extends DefaultSyntaxAction {
public DuplicateLinesAction() {
super("DUPLICATE_LINES");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sdoc,
int dot, ActionEvent e) {
try {
int st = sdoc.getLineStartOffset(target.getSelectionStart());
int en = sdoc.getLineEndOffset(target.getSelectionEnd());
String dupLines = sdoc.getText(st, en - st);
sdoc.insertString(st, dupLines, null);
} catch (BadLocationException ex) {
Logger.getLogger(DuplicateLinesAction.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

View File

@@ -0,0 +1,26 @@
package jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
/**
* This class performs a Find Next operation by using the current pattern
*/
public class FindNextAction extends DefaultSyntaxAction {
public FindNextAction() {
super("find-next");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sdoc,
int dot, ActionEvent e) {
DocumentSearchData dsd = DocumentSearchData.getFromEditor(target);
if (dsd != null) {
if(!dsd.doFindNext(target)) {
dsd.msgNotFound(target);
}
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
/**
* Finder class. This class contains the general Find, Find Next,
* Find Previous, and the Find Marker Actions.
*
* Note that all Actions are subclasses of this class because all actions
* require the find text to be shared among them. This is the best approach
* to have all Action classes share this same data.
*
* @author Ayman Al-Sairafi
*/
public class FindReplaceAction extends DefaultSyntaxAction {
public FindReplaceAction() {
super("FIND_REPLACE");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sdoc,
int dot, ActionEvent e) {
DocumentSearchData dsd = DocumentSearchData.getFromEditor(target);
dsd.showReplaceDialog(target);
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import jsyntaxpane.actions.gui.GotoLineDialog;
import java.awt.event.ActionEvent;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
/**
* This actions displays the GotoLine dialog
*/
public class GotoLineAction extends DefaultSyntaxAction {
public GotoLineAction() {
super("GOTO_LINE");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sdoc,
int dot, ActionEvent e) {
GotoLineDialog.showForEditor(target);
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.actions.gui.HTMLPreviewFrame;
/**
* Show an HTML Preview window.
* This will automatically update on changes to the underlying document.
*
*/
public class HTMLPreviewAction extends DefaultSyntaxAction {
public static final String HTML_PREVIEW_WINDOW = "html-preview-window";
public HTMLPreviewAction() {
super("HTML_PREVIEW");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
// have the document property
Object obj = sDoc.getProperty(HTML_PREVIEW_WINDOW);
if(obj == null) {
HTMLPreviewFrame dlg = new HTMLPreviewFrame(sDoc);
sDoc.putProperty( HTML_PREVIEW_WINDOW,dlg);
dlg.setVisible(true);
} else {
HTMLPreviewFrame dlg = (HTMLPreviewFrame) obj;
dlg.setVisible(enabled);
}
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.util.Map;
import java.util.regex.Pattern;
import javax.swing.JEditorPane;
import javax.swing.text.EditorKit;
import javax.swing.text.JTextComponent;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
/**
* IndentAction is used to replace Tabs with spaces. If there is selected
* text, then the lines spanning the selection will be shifted
* right by one tab-width space character.
*
* Since this is also used as an abbreviation completion action,
* Abbreviiations are processed by this event.
*
* FIXME: Move the abbreviation expansion to an ActionUtils proc
* @author Ayman Al-Sairafi
*
*/
public class IndentAction extends DefaultSyntaxAction {
public IndentAction() {
super("insert-tab");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
String selected = target.getSelectedText();
EditorKit kit = ((JEditorPane) target).getEditorKit();
Map<String, String> abbrvs = ((DefaultSyntaxKit) kit).getAbbreviations();
if (selected == null) {
// Check for abbreviations:
Token abbrToken = sDoc.getWordAt(dot, wordsPattern);
Integer tabStop = ActionUtils.getTabSize(target);
int lineStart = sDoc.getParagraphElement(dot).getStartOffset();
int column = dot - lineStart;
int needed = tabStop - (column % tabStop);
if (abbrvs == null || abbrToken == null) {
target.replaceSelection(ActionUtils.SPACES.substring(0, needed));
} else {
String abbr = abbrToken.getString(sDoc);
if (abbrvs.containsKey(abbr)) {
target.select(abbrToken.start, abbrToken.end());
abbr = abbrvs.get(abbr);
String[] abbrLines = abbr.split("\n");
if (abbrLines.length > 1) {
ActionUtils.insertLinesTemplate(target, abbrLines);
} else {
ActionUtils.insertSimpleTemplate(target, abbr);
}
} else {
target.replaceSelection(ActionUtils.SPACES.substring(0, needed));
}
}
} else {
String[] lines = ActionUtils.getSelectedLines(target);
int start = target.getSelectionStart();
StringBuilder sb = new StringBuilder();
for (String line : lines) {
sb.append(ActionUtils.getTab(target));
sb.append(line);
sb.append('\n');
}
target.replaceSelection(sb.toString());
target.select(start, start + sb.length());
}
}
private Pattern wordsPattern = Pattern.compile("\\w+");
public void setWordRegex(String regex) {
wordsPattern = Pattern.compile(regex);
}
public Pattern getWordRegex() {
return wordsPattern;
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
import jsyntaxpane.TokenType;
/**
* This class should be mapped to VK_ENTER. It performs proper indentation
* for Java Type languages and automatically inserts "*" in multi-line comments
* Initial Code contributed by ser... AT mail.ru
*
* @author Ayman Al-Sairafi
*/
public class JIndentAction extends DefaultSyntaxAction {
public JIndentAction() {
super("JINDENT");
}
/**
* {@inheritDoc}
* @param e
*/
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
int pos = target.getCaretPosition();
int start = sDoc.getParagraphElement(pos).getStartOffset();
String line = ActionUtils.getLine(target);
String lineToPos = line.substring(0, pos - start);
String prefix = ActionUtils.getIndent(line);
Token t = sDoc.getTokenAt(pos);
if (TokenType.isComment(t)) {
String trimmed = line.trim();
if (trimmed.startsWith("/*") && trimmed.endsWith("*/")) {
// it's a single line comment, do not do anything special
} else if (trimmed.endsWith("*/")) {
try {
// the prefix should be the line where the comment started
String commentStartLine = sDoc.getLineAt(t.start);
prefix = ActionUtils.getIndent(commentStartLine);
} catch (BadLocationException ex) {
Logger.getLogger(JIndentAction.class.getName()).log(Level.SEVERE, null, ex);
}
} else if (trimmed.startsWith("*")) {
prefix += "* ";
} else if (trimmed.startsWith("/**")) {
prefix += " * ";
} else if (trimmed.startsWith("/*")) {
prefix += " ";
}
} else if (lineToPos.trim().endsWith("{")) {
prefix += ActionUtils.getTab(target);
} else {
String noComment = sDoc.getUncommentedText(start, pos); // skip EOL comments
if (noComment.trim().endsWith("{")) {
prefix += ActionUtils.getTab(target);
}
}
target.replaceSelection("\n" + prefix);
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
public class JUnindentAction extends DefaultSyntaxAction {
/**
* creates new JUnindentAction.
* Initial Code contributed by ser... AT mail.ru
*/
public JUnindentAction() {
super("JUNINDENT");
}
/**
* {@inheritDoc}
*/
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
int pos = target.getCaretPosition();
int start = sDoc.getParagraphElement(pos).getStartOffset();
String line = ActionUtils.getLine(target);
if (ActionUtils.isEmptyOrBlanks(line)) {
try {
sDoc.insertString(pos, "}", null);
Token t = sDoc.getPairFor(sDoc.getTokenAt(pos));
if (null != t) {
String pairLine = ActionUtils.getLineAt(target, t.start);
String indent = ActionUtils.getIndent(pairLine);
sDoc.replace(start, line.length() + 1, indent + "}", null);
}
} catch (BadLocationException ble) {
target.replaceSelection("}");
}
} else {
target.replaceSelection("}");
}
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
/**
* This actions Jumps to the pair of the token at the cursor.
*/
public class JumpToPairAction extends DefaultSyntaxAction {
public JumpToPairAction() {
super("JUMP_TO_PAIR");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sdoc,
int dot, ActionEvent e) {
Token current = sdoc.getTokenAt(dot);
if (current == null) {
return;
}
Token pair = sdoc.getPairFor(current);
if (pair != null) {
target.setCaretPosition(pair.start);
}
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.util.Map;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
import jsyntaxpane.util.JarServiceProvider;
/**
* Completion Actions:
* All completions are based on a simple String to String Map.
*/
public class MapCompletionAction extends DefaultSyntaxAction {
Map<String, String> completions;
public MapCompletionAction() {
super("MAP_COMPLETION");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
Token token = sDoc.getTokenAt(dot);
if (token != null) {
String abbriv = ActionUtils.getTokenStringAt(sDoc, dot);
if (completions.containsKey(abbriv)) {
String completed = completions.get(abbriv);
if (completed.indexOf('|') >= 0) {
int ofst = completed.length() - completed.indexOf('|') - 1;
sDoc.replaceToken(token, completed.replace("|", ""));
target.setCaretPosition(target.getCaretPosition() - ofst);
} else {
sDoc.replaceToken(token, completed);
}
}
}
}
public void setCompletionsFile(String value) {
completions = JarServiceProvider.readStringsMap(value);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.util.HashMap;
import java.util.Map;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
/**
* A Pair action inserts a pair of characters (left and right) around the
* current selection, and then places the caret between them
*
* The pairs are hard-coded here.
*/
public class PairAction extends DefaultSyntaxAction {
public PairAction() {
super("PAIR_ACTION");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
String left = e.getActionCommand();
String right = PAIRS.get(left);
String selected = target.getSelectedText();
if (selected != null) {
target.replaceSelection(left + selected + right);
} else {
target.replaceSelection(left + right);
target.setCaretPosition(target.getCaretPosition() - right.length());
}
}
private static Map<String, String> PAIRS = new HashMap<String, String>(4);
static {
PAIRS.put("(", ")");
PAIRS.put("[", "]");
PAIRS.put("\"", "\"");
PAIRS.put("'", "'");
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2009 Stefan Bechtold (stefan.bechtold@googlemail.com)
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import javax.swing.text.JTextComponent;
import javax.swing.text.TextAction;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.util.Configuration;
public class PythonIndentAction extends DefaultSyntaxAction {
/**
* creates new PythonIndentAction.
*/
public PythonIndentAction() {
super("PYTHONINDENT");
}
/**
* {@inheritDoc}
* @param e
*/
@Override
public void actionPerformed(ActionEvent e) {
JTextComponent target = getTextComponent(e);
if (target != null) {
SyntaxDocument sDoc = ActionUtils.getSyntaxDocument(target);
int pos = target.getCaretPosition();
int start = sDoc.getParagraphElement(pos).getStartOffset();
String line = ActionUtils.getLine(target);
String lineToPos = line.substring(0, pos - start);
String prefix = ActionUtils.getIndent(line);
int tabSize = ActionUtils.getTabSize(target);
if (lineToPos.trim().endsWith(":")) {
prefix += ActionUtils.SPACES.substring(0, tabSize);
} else {
String noComment = sDoc.getUncommentedText(start, pos); // skip EOL comments
if (noComment.trim().endsWith(":")) {
prefix += ActionUtils.SPACES.substring(0, tabSize);
}
}
target.replaceSelection("\n" + prefix);
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
/**
*
* @author Ayman Al-Sairafi
*/
public class QuickFindAction extends DefaultSyntaxAction {
public QuickFindAction() {
super("quick-find");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
DocumentSearchData.getFromEditor(target).showQuickFindDialog(target);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import javax.swing.text.JTextComponent;
import javax.swing.text.TextAction;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.util.Configuration;
/**
* Redo action
*/
public class RedoAction extends DefaultSyntaxAction {
public RedoAction() {
super("REDO");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
if (sDoc != null) {
sDoc.doRedo();
}
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import jsyntaxpane.actions.gui.ReflectCompletionDialog;
import java.awt.event.ActionEvent;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
/**
* ComboBox like Completion Action:
* This will display a list of items to choose from, its can be used similar to
* IntelliSense
*
* @author Ayman Al-Sairafi
*/
public class ReflectCompletionAction extends DefaultSyntaxAction {
ReflectCompletionDialog dlg;
public ReflectCompletionAction() {
super("REFLECT_COMPLETION");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
Token t = sDoc.getTokenAt(dot);
if(t != null) {
target.select(t.start, t.end());
}
if (dlg == null) {
dlg = new ReflectCompletionDialog(target);
}
dlg.displayFor(target);
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.regex.Pattern;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.JOptionPane;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.util.Configuration;
import jsyntaxpane.util.JarServiceProvider;
/**
* This class executes a script every time it is called.
* Anything can be done using any script.
*
* @author Ayman Al-Sairafi
*/
public class ScriptAction extends DefaultSyntaxAction {
public ScriptAction() {
super("scripted-action");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
if (getValue(SCRIPT_FUNCTION) != null) {
String f = getValue(SCRIPT_FUNCTION).toString();
try {
engine.put("TARGET", target);
engine.put("SDOC", sDoc);
engine.put("DOT", dot);
engine.put("EVENT", e);
engine.put("ACTION", this);
engine.put("AU", ActionUtils.getInstance());
invocable.invokeFunction(f);
} catch (ScriptException ex) {
showScriptError(target, ex);
} catch (NoSuchMethodException ex) {
showScriptError(target, ex);
}
} else {
JOptionPane.showMessageDialog(target, java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("ScriptAction.NoScriptConfigured"),
java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("ScriptAction.ErrorInScript"), JOptionPane.WARNING_MESSAGE);
}
}
public void setFunction(String name) {
putValue(SCRIPT_FUNCTION, name);
}
@Override
public void config(Configuration config, String name) {
super.config(config, name);
// now read and store all of our scripts.
for (Configuration.StringKeyMatcher m : config.getKeys(Pattern.compile("Script\\.((\\w|-)+)\\.URL"))) {
getScriptFromURL(m.value);
}
}
/**
*
* @param url
*/
public void getScriptFromURL(String url) {
InputStream is = JarServiceProvider.findResource(url, this.getClass().getClassLoader());
if (is != null) {
Reader reader = new InputStreamReader(is);
try {
engine.eval(reader);
} catch (ScriptException ex) {
showScriptError(null, ex);
}
} else {
JOptionPane.showMessageDialog(null, java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("ScriptAction.NoScriptFoundIn") + url,
java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("ScriptAction.ErrorInScript"), JOptionPane.WARNING_MESSAGE);
}
}
private void showScriptError(JTextComponent target, Exception ex) {
JOptionPane.showMessageDialog(target, ex.getMessage(),
java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("ScriptAction.ErrorInScript"), JOptionPane.WARNING_MESSAGE);
}
/**
* The key used to store the Script Name for the this action
*/
static final String SCRIPT_FUNCTION = "SCRIPT_FUNCTION";
static final ScriptEngine engine;
static final Invocable invocable;
static {
engine = new ScriptEngineManager().getEngineByExtension("js");
invocable = (Invocable) engine;
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.text.MessageFormat;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
/**
* Executes the script in the component's text using a ScriptEngine
* The Configuration must contain the key [prefix.]ACTION_NAME.ScriptExtension
* and its value is the ScriptExtension that getEngineByExtension returns
* If no engine is found, then an option is given to the user to disable the action
*
* @author Ayman Al-Sairafi
*/
public class ScriptRunnerAction extends DefaultSyntaxAction {
public ScriptRunnerAction() {
super("SCRIPT_EXECUTE");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
try {
ScriptEngine eng = getEngine(target);
if (eng != null) {
getEngine(target).eval(target.getText());
}
} catch (ScriptException ex) {
JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(target),
java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("ScriptRunnerAction.ErrorExecutingScript") + ex.getMessage(),
java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("ScriptRunnerAction.ScriptError"),
JOptionPane.ERROR_MESSAGE);
ActionUtils.setCaretPosition(target,
ex.getLineNumber(),
ex.getColumnNumber());
}
}
private ScriptEngine getEngine(JTextComponent target) {
if (engine == null) {
if (sem == null) {
sem = new ScriptEngineManager();
}
engine = sem.getEngineByExtension(scriptExtension);
}
if (engine == null) {
int result = JOptionPane.showOptionDialog(target,
MessageFormat.format(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("ScriptRunnerAction.ScriptEngineNotFound"), scriptExtension),
"jsyntaxpane",
JOptionPane.YES_NO_OPTION,
JOptionPane.ERROR_MESSAGE,
null,
null,
null);
if (result == JOptionPane.YES_OPTION) {
setEnabled(false);
}
}
return engine;
}
public void setScriptExtension(String value) {
scriptExtension = value;
}
static ScriptEngineManager sem;
private ScriptEngine engine;
private String scriptExtension;
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.util.Map;
import javax.swing.JEditorPane;
import javax.swing.JOptionPane;
import javax.swing.text.JTextComponent;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.actions.gui.ShowAbbsDialog;
/**
* Display all abbreviations for a JTextComponent., if it has any.
* Abbreviations are obtained from the IndentAction, so if the target does not
* have an instance of that actions, nothing is displayed.
* @author Ayman Al-Sairafi
*/
public class ShowAbbsAction extends DefaultSyntaxAction {
public ShowAbbsAction() {
super("show-abbreviations");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
// find the abbreviations actions:
DefaultSyntaxKit kit = ActionUtils.getSyntaxKit(target);
if (kit != null) {
Map<String, String> abbs = kit.getAbbreviations();
if (abbs == null || abbs.isEmpty()) {
JOptionPane.showMessageDialog(target,
java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("ShowAbbsAction.NoAbbsForType"));
} else {
new ShowAbbsDialog((JEditorPane) target, abbs);
}
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.text.CharacterIterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import javax.swing.text.Segment;
import jsyntaxpane.SyntaxDocument;
/**
*
* @author Ayman Al-Sairafi
*/
public class SmartHomeAction extends DefaultSyntaxAction {
public SmartHomeAction() {
super("smart-home");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
try {
target.setCaretPosition(getSmartHomeOffset(target, sDoc, dot));
} catch (BadLocationException ex) {
Logger.getLogger(SmartHomeAction.class.getName()).log(Level.SEVERE, null, ex);
}
}
static int getSmartHomeOffset(JTextComponent target, SyntaxDocument sDoc,
int dot) throws BadLocationException {
Element el = sDoc.getParagraphElement(dot);
Segment seg = new Segment();
sDoc.getText(el.getStartOffset(),
el.getEndOffset() - el.getStartOffset() - 1, seg);
int homeOffset = 0;
int dotLineOffset = dot - el.getStartOffset();
boolean inText = false;
// see the location of first non-space offset
for (int i = 0; i < dotLineOffset; i++) {
if (!Character.isWhitespace(seg.charAt(i))) {
inText = true;
break;
}
}
// if we are at first char in line, or we are past the non space
// chars in the line, then we move to non-space char
// otherwise, we move to first char of line
if (dotLineOffset == 0 || inText) {
for (char ch = seg.first();
ch != CharacterIterator.DONE && Character.isWhitespace(ch);
ch = seg.next()) {
homeOffset++;
}
}
return el.getStartOffset() + homeOffset;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
/**
*
* @author Ayman Al-Sairafi
*/
public class SmartHomeSelectAction extends DefaultSyntaxAction {
public SmartHomeSelectAction() {
super("smart-home-select");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
try {
target.moveCaretPosition(SmartHomeAction.getSmartHomeOffset(target, sDoc, dot));
} catch (BadLocationException ex) {
Logger.getLogger(SmartHomeSelectAction.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import javax.swing.Action;
import jsyntaxpane.util.Configuration;
/**
* All JSyntaxPane Keyboard related actions implement this class. These
* classes are created dynamically, and then registered to the SyntaxKit.
*
* A class may have multiple TextActions that may be related. Each EditorKit
* that is installed will have only one instance of each class, even if more
* than one action is specified.
*
* The key value pairs in the COnfiguration are of the form:
*
* [EditorKit.]Action.NAME = class, keyboard key
*
* @author Ayman Al-Sairafi
*/
public interface SyntaxAction extends Action {
/**
* Configure the actions in this class
* @param config
* @param name Name of the action, (prefixed by Action.)
* will be obtained from the property Key as the
* text following the Action.
*/
public void config(Configuration config, String name);
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
/**
* This action replaces the selection with the configured template in
* the config ACTION-NAME.Template
*
* There are two kinds of templates:
* <li>Simple Templates are replaced as is</li>
* <li>Whole Line Templates will ensure a whole line is selected.
* Each line in the selection will be prefixed, and postfixed with whatever appears
* on the line in the template</li>
*
*/
public class TemplateAction extends DefaultSyntaxAction {
private String template;
private String[] tlines = null;
private boolean wholeLines;
private boolean mustHaveSelection;
public TemplateAction() {
super("template");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sdoc,
int dot, ActionEvent e) {
if (mustHaveSelection) {
if (target.getSelectionEnd() == target.getSelectionStart()) {
return;
}
}
if (wholeLines) {
if(tlines == null) {
tlines = template.split("\n");
}
ActionUtils.insertLinesTemplate(target, tlines);
} else {
ActionUtils.insertSimpleTemplate(target, template);
}
}
public void setWholeLines(String value) {
wholeLines = Boolean.parseBoolean(value);
}
public void setTemplate(String t) {
template = t;
}
public void setMustHaveSelection(String value) {
mustHaveSelection = Boolean.parseBoolean(value);
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
/**
* This action will toggle comments on or off on selected whole lines.
*
* @author Ayman Al-Sairafi
*/
public class ToggleCommentsAction extends DefaultSyntaxAction {
protected String lineCommentStart = "// ";
protected Pattern lineCommentPattern = null;
/**
* creates new JIndentAction.
* Initial Code contributed by ser... AT mail.ru
*/
public ToggleCommentsAction() {
super("toggle-comment");
}
/**
* {@inheritDoc}
* @param e
*/
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
if (lineCommentPattern == null) {
lineCommentPattern = Pattern.compile("(^" + lineCommentStart + ")(.*)");
}
String[] lines = ActionUtils.getSelectedLines(target);
int start = target.getSelectionStart();
StringBuffer toggled = new StringBuffer();
for (int i = 0; i < lines.length; i++) {
Matcher m = lineCommentPattern.matcher(lines[i]);
if (m.find()) {
toggled.append(m.replaceFirst("$2"));
} else {
toggled.append(lineCommentStart);
toggled.append(lines[i]);
}
toggled.append('\n');
}
target.replaceSelection(toggled.toString());
target.select(start, start + toggled.length());
}
public void setLineComments(String value) {
lineCommentStart = value.replace("\"", "");
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import javax.swing.JEditorPane;
import javax.swing.text.JTextComponent;
import jsyntaxpane.DefaultSyntaxKit;
/**
* This Action will Toggle any SyntaxComponents on the EditorPane
* You need the configuration Key prefix.ACTION_NAME.Component = componentclassname
* Where:
* ACTION_NAME is the name given to the action (prefix.Action.ACTION_NAME)
* componentclassname is the fully qualified class name of the component
* @author Ayman Al-Sairafi
*/
public class ToggleComponentAction extends DefaultSyntaxAction {
private String componentName;
public ToggleComponentAction() {
super("toggle-component");
putValue(SELECTED_KEY, Boolean.TRUE);
}
public void setComponent(String name) {
componentName = name;
}
@Override
public String toString() {
return super.toString() + "(" + componentName + ")";
}
@Override
public void actionPerformed(ActionEvent e) {
JTextComponent target = getTextComponent(e);
if (target instanceof JEditorPane) {
JEditorPane jEditorPane = (JEditorPane) target;
DefaultSyntaxKit kit = (DefaultSyntaxKit) jEditorPane.getEditorKit();
boolean status = kit.toggleComponent(jEditorPane, componentName);
putValue(SELECTED_KEY, status);
}
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import javax.swing.text.JTextComponent;
import javax.swing.text.TextAction;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.util.Configuration;
/**
* Undo action
*/
public class UndoAction extends DefaultSyntaxAction {
public UndoAction() {
super("UNDO");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
if (sDoc != null) {
sDoc.doUndo();
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
/**
* This is usually mapped to Shift-TAB to unindent the selection. The
* current line, or the selected lines are un-indented by the tabstop of the
* document.
*/
public class UnindentAction extends DefaultSyntaxAction {
public UnindentAction() {
super("UNINDENT");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
String indent = ActionUtils.getTab(target);
String[] lines = ActionUtils.getSelectedLines(target);
int start = target.getSelectionStart();
StringBuilder sb = new StringBuilder();
for (String line : lines) {
if (line.startsWith(indent)) {
sb.append(line.substring(indent.length()));
} else if (line.startsWith("\t")) {
sb.append(line.substring(1));
} else {
sb.append(line);
}
sb.append('\n');
}
target.replaceSelection(sb.toString());
target.select(start, start + sb.length());
}
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import jsyntaxpane.SyntaxDocument;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* Attempt to prettify an XML document.
* @author Ayman Al-Sairafi
*/
public class XmlPrettifyAction extends DefaultSyntaxAction {
public XmlPrettifyAction() {
super("XML_PRETTIFY");
}
@Override
public void actionPerformed(ActionEvent e) {
if (transformer == null) {
return;
}
JTextComponent target = getTextComponent(e);
try {
SyntaxDocument sdoc = ActionUtils.getSyntaxDocument(target);
StringWriter out = new StringWriter(sdoc.getLength());
StringReader reader = new StringReader(target.getText());
InputSource src = new InputSource(reader);
Document doc = getDocBuilder().parse(src);
//Setup indenting to "pretty print"
getTransformer().transform(new DOMSource(doc), new StreamResult(out));
target.setText(out.toString());
} catch (SAXParseException ex) {
showErrorMessage(target,
String.format("XML error: %s\nat(%d, %d)",
ex.getMessage(), ex.getLineNumber(), ex.getColumnNumber()));
ActionUtils.setCaretPosition(target, ex.getLineNumber(), ex.getColumnNumber() - 1);
} catch (TransformerException ex) {
showErrorMessage(target, ex.getMessageAndLocation());
} catch (SAXException ex) {
showErrorMessage(target, ex.getLocalizedMessage());
} catch (IOException ex) {
showErrorMessage(target, ex.getLocalizedMessage());
}
}
static Transformer transformer;
static DocumentBuilderFactory docBuilderFactory;
static DocumentBuilder docBuilder;
private static void showErrorMessage(JTextComponent text, String msg) {
Component parent = SwingUtilities.getWindowAncestor(text);
JOptionPane.showMessageDialog(parent, msg, "JsyntaxPAne XML", JOptionPane.ERROR_MESSAGE);
}
public static Transformer getTransformer() {
if (transformer == null) {
TransformerFactory tfactory = TransformerFactory.newInstance();
try {
transformer = tfactory.newTransformer();
} catch (TransformerConfigurationException ex) {
throw new IllegalArgumentException("Unable to create transformer. ", ex);
}
}
return transformer;
}
public void setIndent(String text) {
getTransformer().setOutputProperty(OutputKeys.INDENT, text);
}
public void setStandAlone(String text) {
getTransformer().setOutputProperty(OutputKeys.STANDALONE, text);
}
public void setSOmitDeclaration(String text) {
getTransformer().setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, text);
}
public void setIndentAmount(String text) {
getTransformer().setOutputProperty("{http://xml.apache.org/xslt}indent-amount", text);
}
public void setIgnoreComments(String ic) {
getDocBuilderFactory().setIgnoringComments(Boolean.parseBoolean(ic));
}
public void setIgnoreWhiteSpace(String value) {
getDocBuilderFactory().setIgnoringElementContentWhitespace(Boolean.parseBoolean(value));
}
public static DocumentBuilderFactory getDocBuilderFactory() {
if (docBuilderFactory == null) {
docBuilderFactory = DocumentBuilderFactory.newInstance();
}
return docBuilderFactory;
}
public DocumentBuilder getDocBuilder() {
if (docBuilder == null) {
try {
docBuilder = getDocBuilderFactory().newDocumentBuilder();
} catch (ParserConfigurationException ex) {
throw new IllegalArgumentException("Unable to create document builder", ex);
}
}
return docBuilder;
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions;
import java.awt.event.ActionEvent;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
import jsyntaxpane.TokenType;
/**
* Completes an the Tag.
* @author Ayman Al-Sairafi
*/
public class XmlTagCompleteAction extends DefaultSyntaxAction {
public XmlTagCompleteAction() {
super("XML_TAG_COMPLETE");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
Token tok = sDoc.getTokenAt(dot);
while (tok != null && tok.type != TokenType.TYPE) {
tok = sDoc.getPrevToken(tok);
}
if (tok == null) {
target.replaceSelection(">");
} else {
CharSequence tag = tok.getText(sDoc);
int savepos = target.getSelectionStart();
target.replaceSelection("></" + tag.subSequence(1, tag.length()) + ">");
target.setCaretPosition(savepos + 1);
}
}
}

View File

@@ -0,0 +1,71 @@
<?xml version="1.1" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="resizable" type="boolean" value="false"/>
<Property name="undecorated" type="boolean" value="true"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jTxtItem" alignment="0" pref="375" max="32767" attributes="0"/>
<Component id="jScrollPane1" alignment="0" pref="375" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jTxtItem" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="111" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JTextField" name="jTxtItem">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<Events>
<EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jTxtItemKeyPressed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="jLstItems">
<Properties>
<Property name="selectionMode" type="int" value="0"/>
<Property name="focusable" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="jLstItemsMouseClicked"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@@ -0,0 +1,247 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions.gui;
import java.awt.Font;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import jsyntaxpane.actions.ActionUtils;
import jsyntaxpane.util.StringUtils;
import jsyntaxpane.util.SwingUtils;
/**
*
* @author Ayman Al-Sairafi
*/
public class ComboCompletionDialog
extends javax.swing.JDialog implements EscapeListener {
/**
* The result returned to the caller
*/
private String result = null;
/**
* Our target component
*/
private JTextComponent target;
public String escapeChars = ";(= \t\n\r";
public List<String> items;
/**
* Creates new form ComboCompletionDialog
* @param target
*/
public ComboCompletionDialog(JTextComponent target) {
super(ActionUtils.getFrameFor(target), true);
initComponents();
jTxtItem.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
refilterList();
}
@Override
public void removeUpdate(DocumentEvent e) {
refilterList();
}
@Override
public void changedUpdate(DocumentEvent e) {
refilterList();
}
});
// This will allow the textfield to receive TAB keys
jTxtItem.setFocusTraversalKeysEnabled(false);
this.target = target;
SwingUtils.addEscapeListener(this);
}
/**
* Display the Completion Dialog with initial abbrev and using the given items
* The dialog is responsible for showing itself and for updating the target
* with the text, depending on user actions.
*
* The dialog will be aligned to the selectionStart of the target component
* and when a selection is made, replaceSelection will be called on dialog
*
* @param abbrev
* @param items
*/
public void displayFor(String abbrev, List<String> items) {
this.items = items;
try {
Window window = SwingUtilities.getWindowAncestor(target);
Rectangle rt = target.modelToView(target.getSelectionStart());
Point loc = new Point(rt.x, rt.y);
setLocationRelativeTo(window);
// convert the location from Text Componet coordinates to
// Frame coordinates...
loc = SwingUtilities.convertPoint(target, loc, window);
// and then to Screen coordinates
SwingUtilities.convertPointToScreen(loc, window);
setLocation(loc);
} catch (BadLocationException ex) {
Logger.getLogger(ComboCompletionDialog.class.getName()).log(Level.SEVERE, null, ex);
} finally {
Font font = target.getFont();
jTxtItem.setFont(font);
jLstItems.setFont(font);
doLayout();
jTxtItem.setText(abbrev);
refilterList();
setVisible(true);
}
}
private void refilterList() {
String prefix = jTxtItem.getText();
Vector<String> filtered = new Vector<String>();
Object selected = jLstItems.getSelectedValue();
for (String s : items) {
if (StringUtils.camelCaseMatch(s, prefix)) {
filtered.add(s);
}
}
jLstItems.setListData(filtered);
if (selected != null && filtered.contains(selected)) {
jLstItems.setSelectedValue(selected, true);
} else {
jLstItems.setSelectedIndex(0);
}
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jTxtItem = new javax.swing.JTextField();
jScrollPane1 = new javax.swing.JScrollPane();
jLstItems = new javax.swing.JList();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setResizable(false);
setUndecorated(true);
jTxtItem.setBorder(null);
jTxtItem.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
jTxtItemKeyPressed(evt);
}
});
jLstItems.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
jLstItems.setFocusable(false);
jLstItems.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
jLstItemsMouseClicked(evt);
}
});
jScrollPane1.setViewportView(jLstItems);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jTxtItem, javax.swing.GroupLayout.DEFAULT_SIZE, 375, Short.MAX_VALUE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 375, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jTxtItem, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 111, Short.MAX_VALUE))
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void jTxtItemKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTxtItemKeyPressed
int i = jLstItems.getSelectedIndex();
switch (evt.getKeyCode()) {
case KeyEvent.VK_ESCAPE:
result = jTxtItem.getText();
target.replaceSelection(result);
setVisible(false);
return;
case KeyEvent.VK_DOWN:
if (i < jLstItems.getModel().getSize() - 1) {
i++;
}
jLstItems.setSelectedIndex(i);
jLstItems.ensureIndexIsVisible(i);
break;
case KeyEvent.VK_UP:
if (i > 0) {
i--;
}
jLstItems.setSelectedIndex(i);
jLstItems.ensureIndexIsVisible(i);
break;
}
if (escapeChars.indexOf(evt.getKeyChar()) >= 0) {
if (jLstItems.getSelectedIndex() >= 0) {
result = jLstItems.getSelectedValue().toString();
} else {
result = jTxtItem.getText();
}
char pressed = evt.getKeyChar();
// we need to just accept ENTER, and replace the tab with a single
// space
if (pressed != '\n') {
result += (pressed == '\t') ? ' ' : pressed;
}
target.replaceSelection(result);
setVisible(false);
}
}//GEN-LAST:event_jTxtItemKeyPressed
private void jLstItemsMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jLstItemsMouseClicked
if(evt.getClickCount() == 2) {
String selected = jLstItems.getSelectedValue().toString();
target.replaceSelection(selected);
setVisible(false);
}
}//GEN-LAST:event_jLstItemsMouseClicked
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JList jLstItems;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextField jTxtItem;
// End of variables declaration//GEN-END:variables
@Override
public void escapePressed() {
setVisible(false);
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions.gui;
import javax.swing.RootPaneContainer;
/**
* This interface is used by dialogs that will need to listen to ESC key.
* When the ESC key is pressed, escapePressed is called.
* @author Ayman Al-Sairafi
*/
public interface EscapeListener extends RootPaneContainer {
/**
* This method will be called when ESC key is pressed.
*/
public void escapePressed();
}

View File

@@ -0,0 +1,78 @@
<?xml version="1.1" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="GotoLineDialog.title" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="modal" type="boolean" value="true"/>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
<Property name="resizable" type="boolean" value="false"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jCmbLineNumbers" min="-2" pref="104" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jBtnOk" pref="47" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jCmbLineNumbers" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jBtnOk" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JComboBox" name="jCmbLineNumbers">
<Properties>
<Property name="editable" type="boolean" value="true"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jCmbLineNumbersActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="jBtnOk">
<Properties>
<Property name="action" type="javax.swing.Action" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection component="jCmbLineNumbers" name="action" type="property"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="GotoLineDialog.jBtnOk.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jBtnOkActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@@ -0,0 +1,153 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions.gui;
import java.lang.ref.WeakReference;
import jsyntaxpane.actions.*;
import javax.swing.JOptionPane;
import javax.swing.text.JTextComponent;
import jsyntaxpane.util.SwingUtils;
/**
* A simple dialog to prompt for a line number and go to it
* @author Ayman Al-Sairafi
*/
public class GotoLineDialog
extends javax.swing.JDialog implements EscapeListener {
private static final String PROPERTY_KEY = "GOTOLINE_DIALOG";
private WeakReference<JTextComponent> text;
/**
* Creates new form GotoLineDialog
* @param text
*/
private GotoLineDialog(JTextComponent text) {
super(ActionUtils.getFrameFor(text), false);
initComponents();
this.text = new WeakReference<JTextComponent>(text);
setLocationRelativeTo(text.getRootPane());
getRootPane().setDefaultButton(jBtnOk);
text.getDocument().putProperty(PROPERTY_KEY, this);
SwingUtils.addEscapeListener(this);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jCmbLineNumbers = new javax.swing.JComboBox();
jBtnOk = new javax.swing.JButton();
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle"); // NOI18N
setTitle(bundle.getString("GotoLineDialog.title")); // NOI18N
setModal(true);
setName(""); // NOI18N
setResizable(false);
jCmbLineNumbers.setEditable(true);
jCmbLineNumbers.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jCmbLineNumbersActionPerformed(evt);
}
});
jBtnOk.setAction(jCmbLineNumbers.getAction());
jBtnOk.setText(bundle.getString("GotoLineDialog.jBtnOk.text")); // NOI18N
jBtnOk.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jBtnOkActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jCmbLineNumbers, javax.swing.GroupLayout.PREFERRED_SIZE, 104, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jBtnOk, javax.swing.GroupLayout.DEFAULT_SIZE, 47, Short.MAX_VALUE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jCmbLineNumbers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jBtnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void setTextPos() {
Object line = jCmbLineNumbers.getSelectedItem();
if (line != null) {
try {
int lineNr = Integer.parseInt(line.toString());
ActionUtils.insertIntoCombo(jCmbLineNumbers, line);
ActionUtils.setCaretPosition(text.get(), lineNr, 0);
setVisible(false);
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(this, "Invalid Number: " + line,
"Number Error", JOptionPane.ERROR_MESSAGE);
}
}
}
private void jCmbLineNumbersActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCmbLineNumbersActionPerformed
if (evt.getActionCommand().equals("comboBoxEdited")) {
setTextPos();
}
}//GEN-LAST:event_jCmbLineNumbersActionPerformed
private void jBtnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jBtnOkActionPerformed
setTextPos();
}//GEN-LAST:event_jBtnOkActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton jBtnOk;
private javax.swing.JComboBox jCmbLineNumbers;
// End of variables declaration//GEN-END:variables
/**
* Create or return the GotoLine dialog for a given ext component
* @param text
*/
public static void showForEditor(JTextComponent text) {
GotoLineDialog dlg = null;
if (text.getDocument().getProperty(PROPERTY_KEY) == null) {
dlg = new GotoLineDialog(text);
} else {
dlg = (GotoLineDialog) text.getDocument().getProperty(PROPERTY_KEY);
}
dlg.jCmbLineNumbers.requestFocusInWindow();
dlg.setVisible(true);
}
@Override
public void escapePressed() {
setVisible(false);
}
}

View File

@@ -0,0 +1,59 @@
<?xml version="1.1" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="HTMLPreviewFrame.title" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
<Events>
<EventHandler event="windowClosed" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="onWindowClosed"/>
</Events>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="0" pref="688" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="0" pref="449" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JEditorPane" name="jEdtHtml">
<Properties>
<Property name="contentType" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="HTMLPreviewFrame.jEdtHtml.contentType" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="editable" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions.gui;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import jsyntaxpane.actions.HTMLPreviewAction;
/**
*
* @author Ayman Al-Sairafi
*/
public class HTMLPreviewFrame extends javax.swing.JFrame implements DocumentListener {
Document doc;
/**
* Creates new form HTMLPreviewFrame
* @param doc
*/
public HTMLPreviewFrame(Document doc) {
initComponents();
this.doc = doc;
doc.addDocumentListener(this);
updateHTML();
}
private void updateHTML() {
try {
jEdtHtml.setText(doc.getText(0, doc.getLength()));
} catch (BadLocationException ex) {
Logger.getLogger(HTMLPreviewFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jEdtHtml = new javax.swing.JEditorPane();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle"); // NOI18N
setTitle(bundle.getString("HTMLPreviewFrame.title")); // NOI18N
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosed(java.awt.event.WindowEvent evt) {
onWindowClosed(evt);
}
});
jEdtHtml.setContentType(bundle.getString("HTMLPreviewFrame.jEdtHtml.contentType")); // NOI18N
jEdtHtml.setEditable(false);
jScrollPane1.setViewportView(jEdtHtml);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 688, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 449, Short.MAX_VALUE)
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void onWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_onWindowClosed
doc.removeDocumentListener(this);
doc.putProperty(HTMLPreviewAction.HTML_PREVIEW_WINDOW, null);
doc = null;
}//GEN-LAST:event_onWindowClosed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JEditorPane jEdtHtml;
private javax.swing.JScrollPane jScrollPane1;
// End of variables declaration//GEN-END:variables
@Override
public void insertUpdate(DocumentEvent e) {
updateHTML();
}
@Override
public void removeUpdate(DocumentEvent e) {
updateHTML();
}
@Override
public void changedUpdate(DocumentEvent e) {
updateHTML();
}
}

View File

@@ -0,0 +1,262 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions.gui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.swing.ImageIcon;
import javax.swing.JList;
import javax.swing.JPanel;
import jsyntaxpane.SyntaxView;
import jsyntaxpane.UniTools;
import jsyntaxpane.actions.ActionUtils;
import jsyntaxpane.util.ReflectUtils;
/**
* This class will render a Member. There are Method, Field and Constructor subclasses
* @author Ayman Al-Sairafi
*/
abstract class MemberCell extends JPanel {
private final JList list;
private final boolean isSelected;
private final Color backColor;
private final Member member;
private final Class theClass;
public MemberCell(JList list, boolean isSelected, Color backColor, Member member, Class clazz) {
super();
this.list = list;
this.isSelected = isSelected;
this.backColor = backColor;
this.member = member;
this.theClass = clazz;
}
@Override
public void paintComponent(Graphics g) {
SyntaxView.setRenderingHits((Graphics2D) g);
g.setFont(list.getFont());
super.paintComponent(g);
FontMetrics fm = g.getFontMetrics();
g.setColor(isSelected ? list.getSelectionBackground() : backColor);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(isSelected ? list.getSelectionForeground() : list.getForeground());
g.drawImage(getIcon(), 2, 0, null);
int x = 6 + getIcon().getWidth(this);
int y = fm.getHeight();
if (member.getDeclaringClass().equals(theClass)) {
Font bold = list.getFont().deriveFont(Font.BOLD);
g.setFont(bold);
}
x = drawString(getMemberName(), x, y, g);
g.setFont(list.getFont());
x = drawString(getArguments(), x, y, g);
String right = getReturnType();
//JPEXS: UniTools for multi fonts
int rw = UniTools.stringWidth(g, right);
g.drawString(right, getWidth() - rw - 4, fm.getAscent());
}
@Override
public Dimension getPreferredSize() {
Font font = list.getFont();
Graphics g = getGraphics();
FontMetrics fm = g.getFontMetrics(font);
// total text for this component:
String total = getMemberName() + getArguments() + getReturnType() + " ";
//JPEXS: UniTools for multi fonts
return new Dimension(UniTools.stringWidth(g,total) + 20, Math.max(fm.getHeight(), 16));
}
private int drawString(String string, int x, int y, Graphics g) {
if(ActionUtils.isEmptyOrBlanks(string)) {
return x;
}
//JPEXS: UniTools for multi fonts
int w = UniTools.stringWidth(g, string);
g.drawString(string, x, y);
return x + w;
}
/**
* Read all relevant icons and returns the Map. The loc should contain the
* fully qualified URL for the icons. The icon names read will have the words
* _private, protected, _static, _static_private and _static_protected and the
* extension ".png" appended.
* @param loc root for icon locations
* @return Map (can be used directly with getModifiers & 0xf)
*/
Map<Integer, Image> readIcons(String loc) {
Map<Integer, Image> icons = new HashMap<Integer, Image>();
icons.put(Modifier.PUBLIC, readImage(loc, ""));
icons.put(Modifier.PRIVATE, readImage(loc, "_private"));
icons.put(Modifier.PROTECTED, readImage(loc, "_protected"));
icons.put(Modifier.STATIC | Modifier.PUBLIC, readImage(loc, "_static"));
icons.put(Modifier.STATIC | Modifier.PRIVATE, readImage(loc, "_static_private"));
icons.put(Modifier.STATIC | Modifier.PROTECTED, readImage(loc, "_static_protected"));
return icons;
}
private Image readImage(String iconLoc, String kind) {
String fullPath = iconLoc + kind + ".png";
URL loc = this.getClass().getResource(fullPath);
if (loc == null) {
return null;
} else {
Image i = new ImageIcon(loc).getImage();
return i;
}
}
protected String getMemberName() {
return member.getName();
}
abstract protected String getArguments();
abstract protected String getReturnType();
abstract protected Image getIcon();
}
/**
* Renders a Method
* @author Ayman Al-Sairafi
*/
class MethodCell extends MemberCell {
private final Method method;
public MethodCell(JList list, boolean isSelected, Color backColor, Method method, Class clazz) {
super(list, isSelected, backColor, method, clazz);
this.method = method;
}
@Override
protected String getArguments() {
return ReflectUtils.getParamsString(method.getParameterTypes());
}
@Override
protected String getReturnType() {
return method.getReturnType().getSimpleName();
}
@Override
protected Image getIcon() {
int type = method.getModifiers() & 0xf; // only get public/private/protected/static
if (icons == null) {
icons = readIcons(METHOD_ICON_LOC);
}
return icons.get(type);
}
private static Map<Integer, Image> icons = null;
public static final String METHOD_ICON_LOC = "/META-INF/images/completions/method";
}
/**
* Renders a Field
* @author Ayman Al-Sairafi
*/
class FieldCell extends MemberCell {
private final Field field;
public FieldCell(JList list, boolean isSelected, Color backColor, Field field, Class clazz) {
super(list, isSelected, backColor, field, clazz);
this.field = field;
}
@Override
protected String getArguments() {
return "";
}
@Override
protected String getReturnType() {
return field.getType().getSimpleName();
}
@Override
protected Image getIcon() {
int type = field.getModifiers() & 0xf; // only get public/private/protected/static
if (icons == null) {
icons = readIcons(FIELD_ICON_LOC);
}
if (icons.get(type) == null) {
System.err.println("Unable to get icon for type: " + field.getModifiers());
}
return icons.get(type);
}
private static Map<Integer, Image> icons = null;
public static final String FIELD_ICON_LOC = "/META-INF/images/completions/field";
}
/**
* Renders a Field
* @author Ayman Al-Sairafi
*/
class ConstructorCell extends MemberCell {
private final Constructor cons;
public ConstructorCell(JList list, boolean isSelected, Color backColor, Constructor cons, Class clazz) {
super(list, isSelected, backColor, cons, clazz);
this.cons = cons;
}
@Override
protected String getMemberName() {
return cons.getDeclaringClass().getSimpleName();
}
@Override
protected String getArguments() {
return ReflectUtils.getParamsString(cons.getParameterTypes());
}
@Override
protected String getReturnType() {
return cons.getDeclaringClass().getSimpleName();
}
@Override
protected Image getIcon() {
int type = cons.getModifiers() & 0x7; // only get public/private/protected, mask out static
if (icons == null) {
icons = readIcons(FIELD_ICON_LOC);
}
if (icons.get(type) == null) {
System.out.println("Unable to get icon for type: " + cons.getModifiers());
}
return icons.get(type);
}
private static Map<Integer, Image> icons = null;
public static final String FIELD_ICON_LOC = "/META-INF/images/completions/constructor";
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions.gui;
import java.awt.Color;
import java.awt.Component;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JList;
class MembersListRenderer extends DefaultListCellRenderer {
static final Color evensColor = new Color(0xeeffee);
private ReflectCompletionDialog dlg;
public MembersListRenderer(ReflectCompletionDialog dlg) {
this.dlg = dlg;
}
@Override
public Component getListCellRendererComponent(final JList list, Object value, final int index,
final boolean isSelected, boolean cellHasFocus) {
Color back = (index % 2 == 1) ? list.getBackground() : evensColor;
if (value instanceof Method) {
final Method method = (Method) value;
return new MethodCell(list, isSelected, back, method, dlg.getTheClass());
} else if (value instanceof Field) {
Field field = (Field) value;
return new FieldCell(list, isSelected, back, field, dlg.getTheClass());
} else if (value instanceof Constructor) {
Constructor cons = (Constructor) value;
return new ConstructorCell(list, isSelected, back, cons, dlg.getTheClass());
} else {
Component comp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
comp.setBackground(back);
return comp;
}
}
}

View File

@@ -0,0 +1,177 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="40" green="40" id="darkGray" palette="1" red="40" type="palette"/>
</Property>
<Property name="name" type="java.lang.String" value="QuickFindDialog" noResource="true"/>
<Property name="undecorated" type="boolean" value="true"/>
<Property name="resizable" type="boolean" value="false"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jToolBar1" alignment="0" pref="684" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jToolBar1" min="-2" max="-2" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JToolBar" name="jToolBar1">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
<EtchetBorder/>
</Border>
</Property>
<Property name="floatable" type="boolean" value="false"/>
<Property name="rollover" type="boolean" value="true"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
<SubComponents>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator1">
</Component>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="jTxtFind"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="QuickFindDialog.jLabel1.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator2">
</Component>
<Component class="javax.swing.JTextField" name="jTxtFind">
<Properties>
<Property name="columns" type="int" value="30"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo">
<LineBorder/>
</Border>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[200, 24]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[60, 24]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator3">
</Component>
<Component class="javax.swing.JButton" name="jBtnPrev">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/META-INF/images/small-icons/go-up.png"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="opaque" type="boolean" value="false"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jBtnPrevActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="jBtnNext">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/META-INF/images/small-icons/go-down.png"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[2, 2, 2, 2]"/>
</Property>
<Property name="opaque" type="boolean" value="false"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jBtnNextActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="jChkIgnoreCase">
<Properties>
<Property name="mnemonic" type="int" value="67"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="QuickFindDialog.jChkIgnoreCase.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
<Property name="opaque" type="boolean" value="false"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_allCodePost" type="java.lang.String" value="jChkIgnoreCase.addActionListener(this);"/>
</AuxValues>
</Component>
<Component class="javax.swing.JCheckBox" name="jChkRegExp">
<Properties>
<Property name="mnemonic" type="int" value="82"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="QuickFindDialog.jChkRegExp.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
<Property name="opaque" type="boolean" value="false"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_allCodePost" type="java.lang.String" value="jChkRegExp.addActionListener(this);&#xa;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JCheckBox" name="jChkWrap">
<Properties>
<Property name="mnemonic" type="int" value="87"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="QuickFindDialog.jChkWrap.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
<Property name="opaque" type="boolean" value="false"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_allCodePost" type="java.lang.String" value="jChkWrap.addActionListener(this);&#xa;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator4">
</Component>
<Component class="javax.swing.JLabel" name="jLblStatus">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font bold="true" component="jLblStatus" property="font" relativeSize="true" size="-2"/>
</FontInfo>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" id="red" palette="1" red="ff" type="palette"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@@ -0,0 +1,328 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions.gui;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.ref.WeakReference;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import jsyntaxpane.actions.ActionUtils;
import jsyntaxpane.actions.DocumentSearchData;
import jsyntaxpane.components.Markers;
import jsyntaxpane.components.Markers.SimpleMarker;
import jsyntaxpane.util.SwingUtils;
/**
* QuickFind Dialog. Firefox like dialog shown at bottom of editor.
* @author Ayman Al-Sairafi
*/
public class QuickFindDialog extends javax.swing.JDialog
implements DocumentListener, ActionListener, EscapeListener {
private SimpleMarker marker = new SimpleMarker(Color.PINK);
private WeakReference<JTextComponent> target;
private WeakReference<DocumentSearchData> dsd;
private int oldCaretPosition;
/**
* This will be set to true if ESC key is used to quit the form.
* In that case, the caret will be restored to its old pos, otherwise
* it will remain where the user probably clicked.
*/
private boolean escaped = false;
//JPEXS added
public void setIgnoreCase(boolean ignoreCase){
jChkIgnoreCase.setSelected(ignoreCase);
}
//JPEXS added
public void setRegularExpression(boolean regularExpresion){
jChkRegExp.setSelected(regularExpresion);
}
//JPEXS added
public void setWrap(boolean wrap){
jChkWrap.setSelected(wrap);
}
/**
* Creates new form QuickFindDialog
*
* @param target
* @param data search data
*/
public QuickFindDialog(final JTextComponent target, DocumentSearchData data) {
super(ActionUtils.getFrameFor(target), false);
initComponents();
SwingUtils.addEscapeListener(this);
dsd = new WeakReference<DocumentSearchData>(data);
}
public void showFor(final JTextComponent target) {
oldCaretPosition = target.getCaretPosition();
Container view = target.getParent();
Dimension wd = getSize();
//JPEXS fix:
//wd.width = target.getVisibleRect().width;
Point loc = new Point(0, view.getHeight()-getHeight()/*JPEXS fix*/);
setSize(wd);
setLocationRelativeTo(view);
SwingUtilities.convertPointToScreen(loc, view);
setLocation(loc);
jTxtFind.setFont(target.getFont());
jTxtFind.getDocument().addDocumentListener(this);
WindowAdapter closeListener = new WindowAdapter() {
@Override
public void windowDeactivated(WindowEvent e) {
target.getDocument().removeDocumentListener(QuickFindDialog.this);
Markers.removeMarkers(target, marker);
if (escaped) {
Rectangle aRect;
try {
aRect = target.modelToView(oldCaretPosition);
target.setCaretPosition(oldCaretPosition);
target.scrollRectToVisible(aRect);
} catch (BadLocationException ex) {
}
}
dispose();
}
};
addWindowListener(closeListener);
this.target = new WeakReference<JTextComponent>(target);
Pattern p = dsd.get().getPattern();
if (p != null) {
jTxtFind.setText(p.pattern());
}
jChkWrap.setSelected(dsd.get().isWrap());
setVisible(true);
}
/**
* This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jToolBar1 = new javax.swing.JToolBar();
jSeparator1 = new javax.swing.JToolBar.Separator();
jLabel1 = new javax.swing.JLabel();
jSeparator2 = new javax.swing.JToolBar.Separator();
jTxtFind = new javax.swing.JTextField();
jSeparator3 = new javax.swing.JToolBar.Separator();
jBtnPrev = new javax.swing.JButton();
jBtnNext = new javax.swing.JButton();
jChkIgnoreCase = new javax.swing.JCheckBox();
jChkRegExp = new javax.swing.JCheckBox();
jChkWrap = new javax.swing.JCheckBox();
jSeparator4 = new javax.swing.JToolBar.Separator();
jLblStatus = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setBackground(java.awt.Color.darkGray);
setName("QuickFindDialog"); // NOI18N
setResizable(false);
setUndecorated(true);
jToolBar1.setBorder(javax.swing.BorderFactory.createEtchedBorder());
jToolBar1.setFloatable(false);
jToolBar1.setRollover(true);
jToolBar1.add(jSeparator1);
jLabel1.setLabelFor(jTxtFind);
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle"); // NOI18N
jLabel1.setText(bundle.getString("QuickFindDialog.jLabel1.text")); // NOI18N
jToolBar1.add(jLabel1);
jToolBar1.add(jSeparator2);
jTxtFind.setColumns(30);
jTxtFind.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
jTxtFind.setMaximumSize(new java.awt.Dimension(200, 24));
jTxtFind.setMinimumSize(new java.awt.Dimension(60, 24));
jToolBar1.add(jTxtFind);
jToolBar1.add(jSeparator3);
jBtnPrev.setIcon(new javax.swing.ImageIcon(getClass().getResource("/META-INF/images/small-icons/go-up.png"))); // NOI18N
jBtnPrev.setFocusable(false);
jBtnPrev.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
jBtnPrev.setOpaque(false);
jBtnPrev.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
jBtnPrev.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jBtnPrevActionPerformed(evt);
}
});
jToolBar1.add(jBtnPrev);
jBtnNext.setIcon(new javax.swing.ImageIcon(getClass().getResource("/META-INF/images/small-icons/go-down.png"))); // NOI18N
jBtnNext.setFocusable(false);
jBtnNext.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
jBtnNext.setMargin(new java.awt.Insets(2, 2, 2, 2));
jBtnNext.setOpaque(false);
jBtnNext.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
jBtnNext.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jBtnNextActionPerformed(evt);
}
});
jToolBar1.add(jBtnNext);
jChkIgnoreCase.setMnemonic('C');
jChkIgnoreCase.setText(bundle.getString("QuickFindDialog.jChkIgnoreCase.text")); // NOI18N
jChkIgnoreCase.setFocusable(false);
jChkIgnoreCase.setOpaque(false);
jChkIgnoreCase.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
jToolBar1.add(jChkIgnoreCase);
jChkIgnoreCase.addActionListener(this);
jChkRegExp.setMnemonic('R');
jChkRegExp.setText(bundle.getString("QuickFindDialog.jChkRegExp.text")); // NOI18N
jChkRegExp.setFocusable(false);
jChkRegExp.setOpaque(false);
jChkRegExp.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
jToolBar1.add(jChkRegExp);
jChkRegExp.addActionListener(this);
jChkWrap.setMnemonic('W');
jChkWrap.setText(bundle.getString("QuickFindDialog.jChkWrap.text")); // NOI18N
jChkWrap.setFocusable(false);
jChkWrap.setOpaque(false);
jChkWrap.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
jToolBar1.add(jChkWrap);
jChkWrap.addActionListener(this);
jToolBar1.add(jSeparator4);
jLblStatus.setFont(jLblStatus.getFont().deriveFont(jLblStatus.getFont().getStyle() | java.awt.Font.BOLD, jLblStatus.getFont().getSize()-2));
jLblStatus.setForeground(java.awt.Color.red);
jToolBar1.add(jLblStatus);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 684, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void jBtnNextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jBtnNextActionPerformed
if (dsd.get().doFindNext(target.get())) {
jLblStatus.setText(null);
} else {
jLblStatus.setText(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("QuickFindDialog.NotFound"));
}
}//GEN-LAST:event_jBtnNextActionPerformed
private void jBtnPrevActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jBtnPrevActionPerformed
if (dsd.get().doFindPrev(target.get())) {
jLblStatus.setText(null);
} else {
jLblStatus.setText(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("QuickFindDialog.NotFound"));
}
}//GEN-LAST:event_jBtnPrevActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton jBtnNext;
private javax.swing.JButton jBtnPrev;
private javax.swing.JCheckBox jChkIgnoreCase;
private javax.swing.JCheckBox jChkRegExp;
private javax.swing.JCheckBox jChkWrap;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLblStatus;
private javax.swing.JToolBar.Separator jSeparator1;
private javax.swing.JToolBar.Separator jSeparator2;
private javax.swing.JToolBar.Separator jSeparator3;
private javax.swing.JToolBar.Separator jSeparator4;
private javax.swing.JToolBar jToolBar1;
private javax.swing.JTextField jTxtFind;
// End of variables declaration//GEN-END:variables
@Override
public void insertUpdate(DocumentEvent e) {
updateFind();
}
@Override
public void removeUpdate(DocumentEvent e) {
updateFind();
}
@Override
public void changedUpdate(DocumentEvent e) {
updateFind();
}
private void updateFind() {
JTextComponent t = target.get();
DocumentSearchData d = dsd.get();
String toFind = jTxtFind.getText();
if (toFind == null || toFind.isEmpty()) {
jLblStatus.setText(null);
return;
}
try {
d.setWrap(jChkWrap.isSelected());
d.setPattern(toFind,
jChkRegExp.isSelected(),
jChkIgnoreCase.isSelected());
// The dsd doFindNext will always find from current pos,
// so we need to relocate to our saved pos before we call doFindNext
jLblStatus.setText(null);
t.setCaretPosition(oldCaretPosition);
if (!d.doFindNext(t)) {
jLblStatus.setText(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("QuickFindDialog.NotFound"));
} else {
jLblStatus.setText(null);
}
} catch (PatternSyntaxException e) {
jLblStatus.setText(e.getDescription());
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JCheckBox) {
updateFind();
}
}
@Override
public void escapePressed() {
escaped = true;
setVisible(false);
}
}

View File

@@ -0,0 +1,95 @@
<?xml version="1.1" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="name" type="java.lang.String" value="CompletionDialog" noResource="true"/>
<Property name="resizable" type="boolean" value="false"/>
<Property name="undecorated" type="boolean" value="true"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jTxtItem" alignment="0" pref="437" max="32767" attributes="0"/>
<Component id="jScrollPane1" alignment="0" pref="437" max="32767" attributes="0"/>
<Component id="jCmbClassName" alignment="0" pref="437" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jTxtItem" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="156" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="jCmbClassName" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JTextField" name="jTxtItem">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<Events>
<EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jTxtItemKeyPressed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="jLstItems">
<Properties>
<Property name="selectionMode" type="int" value="0"/>
<Property name="cellRenderer" type="javax.swing.ListCellRenderer" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new jsyntaxpane.actions.gui.MembersListRenderer(this)" type="code"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="jLstItemsMouseClicked"/>
</Events>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JComboBox" name="jCmbClassName">
<Properties>
<Property name="editable" type="boolean" value="true"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="2">
<StringItem index="0" value="Object"/>
<StringItem index="1" value="String"/>
</StringArray>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="jCmbClassNameItemStateChanged"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_SerializeTo" type="java.lang.String" value="ReflectCompletionDialog_jCmbClassName"/>
</AuxValues>
</Component>
</SubComponents>
</Form>

View File

@@ -0,0 +1,342 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions.gui;
import java.awt.Font;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.KeyEvent;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import jsyntaxpane.actions.ActionUtils;
import jsyntaxpane.util.ReflectUtils;
import jsyntaxpane.util.StringUtils;
import jsyntaxpane.util.SwingUtils;
/**
*
* @author Ayman Al-Sairafi
*/
public class ReflectCompletionDialog
extends javax.swing.JDialog implements EscapeListener {
/**
* The class we are displaying its members:
*/
private Class theClass;
/**
* The current filter, to avoid refiltering the items
*/
public String escapeChars = ";(= \t\n";
public List<Member> items;
private final JTextComponent target;
/**
* Creates new form ReflectCompletionDialog
* @param target Text component for this dialog
*/
public ReflectCompletionDialog(JTextComponent target) {
super(SwingUtilities.getWindowAncestor(target), ModalityType.APPLICATION_MODAL);
initComponents();
this.target = target;
jTxtItem.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
refilterList();
}
@Override
public void removeUpdate(DocumentEvent e) {
refilterList();
}
@Override
public void changedUpdate(DocumentEvent e) {
refilterList();
}
});
// This will allow the textfield to receive TAB keys
jTxtItem.setFocusTraversalKeysEnabled(false);
// Add action so we automatically filter on comboBox Enter Key
jCmbClassName.getEditor().addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateItems();
}
});
SwingUtils.addEscapeListener(this);
}
public void setFonts(Font font) {
jTxtItem.setFont(font);
jLstItems.setFont(font);
doLayout();
}
private String getSelection() {
String result;
if (jLstItems.getSelectedIndex() >= 0) {
Object selected = jLstItems.getSelectedValue();
if (selected instanceof Method) {
result = ReflectUtils.getJavaCallString((Method) selected);
} else if (selected instanceof Constructor) {
result = ReflectUtils.getJavaCallString((Constructor) selected);
} else if (selected instanceof Field) {
result = ((Field) selected).getName();
} else {
result = selected.toString();
}
} else {
result = jTxtItem.getText();
}
return result;
}
private void refilterList() {
String prefix = jTxtItem.getText();
Vector<Member> filtered = new Vector<Member>();
Object selected = jLstItems.getSelectedValue();
for (Member m : items) {
if (StringUtils.camelCaseMatch(m.getName(), prefix)) {
filtered.add(m);
}
}
jLstItems.setListData(filtered);
if (selected != null && filtered.contains(selected)) {
jLstItems.setSelectedValue(selected, true);
} else {
jLstItems.setSelectedIndex(0);
}
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jTxtItem = new javax.swing.JTextField();
jScrollPane1 = new javax.swing.JScrollPane();
jLstItems = new javax.swing.JList();
jCmbClassName = new javax.swing.JComboBox();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setName("CompletionDialog"); // NOI18N
setResizable(false);
setUndecorated(true);
jTxtItem.setBorder(null);
jTxtItem.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
jTxtItemKeyPressed(evt);
}
});
jLstItems.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
jLstItems.setCellRenderer(new jsyntaxpane.actions.gui.MembersListRenderer(this));
jLstItems.setFocusable(false);
jLstItems.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
jLstItemsMouseClicked(evt);
}
});
jScrollPane1.setViewportView(jLstItems);
jCmbClassName.setEditable(true);
jCmbClassName.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Object", "String" }));
jCmbClassName.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
jCmbClassNameItemStateChanged(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jTxtItem, javax.swing.GroupLayout.DEFAULT_SIZE, 437, Short.MAX_VALUE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 437, Short.MAX_VALUE)
.addComponent(jCmbClassName, 0, 437, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jTxtItem, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 156, Short.MAX_VALUE)
.addGap(0, 0, 0)
.addComponent(jCmbClassName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void jTxtItemKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTxtItemKeyPressed
int i = jLstItems.getSelectedIndex();
switch (evt.getKeyCode()) {
case KeyEvent.VK_ESCAPE:
target.setCaretPosition(target.getSelectionEnd());
setVisible(false);
return;
case KeyEvent.VK_DOWN:
i++;
break;
case KeyEvent.VK_UP:
i--;
break;
case KeyEvent.VK_HOME:
i = 0;
break;
case KeyEvent.VK_END:
i = jLstItems.getModel().getSize() - 1;
break;
case KeyEvent.VK_PAGE_DOWN:
i += jLstItems.getVisibleRowCount();
break;
case KeyEvent.VK_PAGE_UP:
i -= jLstItems.getVisibleRowCount();
break;
}
if (escapeChars.indexOf(evt.getKeyChar()) >= 0) {
String result = getSelection();
char pressed = evt.getKeyChar();
// we need to just accept ENTER, and replace the tab with a single
// space
if (pressed != '\n') {
result += (pressed == '\t') ? ' ' : pressed;
}
target.replaceSelection(result);
setVisible(false);
} else {
// perform bounds checks for i
if (i >= jLstItems.getModel().getSize()) {
i = jLstItems.getModel().getSize() - 1;
}
if (i < 0) {
i = 0;
}
jLstItems.setSelectedIndex(i);
jLstItems.ensureIndexIsVisible(i);
}
}//GEN-LAST:event_jTxtItemKeyPressed
private void jCmbClassNameItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_jCmbClassNameItemStateChanged
if (evt.getStateChange() == ItemEvent.SELECTED) {
updateItems();
}
}//GEN-LAST:event_jCmbClassNameItemStateChanged
private void jLstItemsMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jLstItemsMouseClicked
if (evt.getClickCount() == 2) {
String selected = getSelection();
target.replaceSelection(selected);
setVisible(false);
}
}//GEN-LAST:event_jLstItemsMouseClicked
private void updateItems() {
String className = jCmbClassName.getEditor().getItem().toString();
if (items == null) {
items = new ArrayList<Member>();
} else {
items.clear();
}
// we must have the class in the Combo:
Class aClass = ReflectUtils.findClass(className, ReflectUtils.DEFAULT_PACKAGES);
if (aClass != null) {
// for now, add everything:
theClass = aClass;
ReflectUtils.addConstrcutors(aClass, items);
ReflectUtils.addMethods(aClass, items);
ReflectUtils.addFields(aClass, items);
ActionUtils.insertIntoCombo(jCmbClassName, className);
jTxtItem.requestFocusInWindow();
}
refilterList();
}
public Class getTheClass() {
return theClass;
}
/**
* Set the items to display
* @param items
*/
public void setItems(List<Member> items) {
this.items = items;
}
/**
* Display the dialog.
* @param target text component (its Window will be the parent)
*/
public void displayFor(JTextComponent target) {
try {
int dot = target.getSelectionStart();
Window window = SwingUtilities.getWindowAncestor(target);
Rectangle rt = target.modelToView(dot);
Point loc = new Point(rt.x, rt.y);
// convert the location from Text Componet coordinates to
// Frame coordinates...
loc = SwingUtilities.convertPoint(target, loc, window);
// and then to Screen coordinates
SwingUtilities.convertPointToScreen(loc, window);
setLocationRelativeTo(window);
setLocation(loc);
} catch (BadLocationException ex) {
Logger.getLogger(ReflectCompletionDialog.class.getName()).log(Level.SEVERE, null, ex);
} finally {
setFonts(target.getFont());
updateItems();
jTxtItem.setText(target.getSelectedText());
setVisible(true);
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JComboBox jCmbClassName;
private javax.swing.JList jLstItems;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextField jTxtItem;
// End of variables declaration//GEN-END:variables
@Override
public void escapePressed() {
target.setCaretPosition(target.getSelectionEnd());
setVisible(false);
}
}

View File

@@ -0,0 +1,225 @@
<?xml version="1.1" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="ReplaceDialog.title" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
<Property name="resizable" type="boolean" value="false"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="jLblFind" min="-2" max="-2" attributes="0"/>
<Component id="jLblReplace" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jCmbFind" alignment="0" pref="289" max="32767" attributes="0"/>
<Component id="jCmbReplace" alignment="1" pref="289" max="32767" attributes="1"/>
<Component id="jChkRegex" alignment="0" pref="289" max="32767" attributes="0"/>
<Component id="jChkWrap" alignment="0" pref="289" max="32767" attributes="0"/>
<Component id="jChkIgnoreCase" alignment="0" pref="289" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jBtnReplace" alignment="1" pref="107" max="32767" attributes="0"/>
<Component id="jBtnNext" alignment="0" pref="107" max="32767" attributes="1"/>
<Component id="jBtnPrev" alignment="0" pref="107" max="32767" attributes="1"/>
<Component id="jTglHighlight" alignment="1" pref="107" max="32767" attributes="0"/>
<Component id="jBtnReplaceAll" alignment="1" pref="107" max="32767" attributes="1"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLblFind" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jCmbFind" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jBtnNext" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jBtnPrev" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jCmbReplace" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLblReplace" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jBtnReplace" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jChkWrap" alignment="3" min="-2" pref="23" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jChkRegex" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jBtnReplaceAll" alignment="3" min="-2" max="-2" attributes="1"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jChkIgnoreCase" alignment="3" min="-2" max="-2" attributes="1"/>
<Component id="jTglHighlight" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="jLblFind">
<Properties>
<Property name="displayedMnemonic" type="int" value="70"/>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="jCmbFind"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="ReplaceDialog.jLblFind.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="jBtnNext">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/META-INF/images/small-icons/go-next.png"/>
</Property>
<Property name="mnemonic" type="int" value="78"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="ReplaceDialog.jBtnNext.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jBtnNextActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="jBtnPrev">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/META-INF/images/small-icons/go-previous.png"/>
</Property>
<Property name="mnemonic" type="int" value="78"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="ReplaceDialog.jBtnPrev.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jBtnPrevActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="jBtnReplaceAll">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/META-INF/images/small-icons/edit-find-replace-all.png"/>
</Property>
<Property name="mnemonic" type="int" value="72"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="ReplaceDialog.jBtnReplaceAll.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jBtnReplaceAllActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="jChkWrap">
<Properties>
<Property name="mnemonic" type="int" value="87"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="ReplaceDialog.jChkWrap.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="ReplaceDialog.jChkWrap.toolTipText" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="jChkRegex">
<Properties>
<Property name="mnemonic" type="int" value="82"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="ReplaceDialog.jChkRegex.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="jChkIgnoreCase">
<Properties>
<Property name="mnemonic" type="int" value="73"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="ReplaceDialog.jChkIgnoreCase.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLblReplace">
<Properties>
<Property name="displayedMnemonic" type="int" value="82"/>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="jCmbReplace"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="ReplaceDialog.jLblReplace.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JToggleButton" name="jTglHighlight">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/META-INF/images/small-icons/highlight.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="ReplaceDialog.jTglHighlight.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jTglHighlightActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JComboBox" name="jCmbReplace">
<Properties>
<Property name="editable" type="boolean" value="true"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="jCmbFind">
<Properties>
<Property name="editable" type="boolean" value="true"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="jBtnReplace">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/META-INF/images/small-icons/edit-find-replace.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="ReplaceDialog.jBtnReplace.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jBtnReplaceActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@@ -0,0 +1,305 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions.gui;
import jsyntaxpane.actions.*;
import jsyntaxpane.components.Markers;
import java.awt.Color;
import java.awt.HeadlessException;
import java.util.regex.PatternSyntaxException;
import javax.swing.JOptionPane;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.JTextComponent;
import jsyntaxpane.util.SwingUtils;
/**
* A Find and Replace Dialog. The dialog will also act as a listener to
* Document changes so that all highlights are updated if the document is
* changed.
*
* @author Ayman Al-Sairafi
*/
public class ReplaceDialog extends javax.swing.JDialog
implements CaretListener, EscapeListener {
private JTextComponent textComponent;
private DocumentSearchData dsd;
private static Markers.SimpleMarker SEARCH_MARKER = new Markers.SimpleMarker(Color.YELLOW);
/**
* Creates new form FindDialog
* @param text
* @param dsd DocumentSerachData
*/
public ReplaceDialog(JTextComponent text,
DocumentSearchData dsd) {
super(ActionUtils.getFrameFor(text), false);
initComponents();
textComponent = text;
this.dsd = dsd;
textComponent.addCaretListener(this);
setLocationRelativeTo(text.getRootPane());
getRootPane().setDefaultButton(jBtnNext);
SwingUtils.addEscapeListener(this);
jBtnReplaceAll.setEnabled(text.isEditable() && text.isEnabled());
}
/**
* updates the highlights in the document when it is updated.
* This is called by the DocumentListener methods
*/
public void updateHighlights() {
Markers.removeMarkers(textComponent, SEARCH_MARKER);
if (jTglHighlight.isSelected()) {
Markers.markAll(textComponent, dsd.getPattern(), SEARCH_MARKER);
}
}
private void showRegexpError(PatternSyntaxException ex) throws HeadlessException {
JOptionPane.showMessageDialog(this, "Regexp error: " + ex.getMessage(),
"Regular Expression Error", JOptionPane.ERROR_MESSAGE);
jCmbFind.requestFocus();
}
/**
* update the finder object with data from our UI
*/
private void updateFinder() {
String regex = (String) jCmbFind.getSelectedItem();
try {
dsd.setPattern(regex,
jChkRegex.isSelected(),
jChkIgnoreCase.isSelected());
ActionUtils.insertIntoCombo(jCmbFind, regex);
} catch (PatternSyntaxException e) {
showRegexpError(e);
}
}
/**
* This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jLblFind = new javax.swing.JLabel();
jBtnNext = new javax.swing.JButton();
jBtnPrev = new javax.swing.JButton();
jBtnReplaceAll = new javax.swing.JButton();
jChkWrap = new javax.swing.JCheckBox();
jChkRegex = new javax.swing.JCheckBox();
jChkIgnoreCase = new javax.swing.JCheckBox();
jLblReplace = new javax.swing.JLabel();
jTglHighlight = new javax.swing.JToggleButton();
jCmbReplace = new javax.swing.JComboBox();
jCmbFind = new javax.swing.JComboBox();
jBtnReplace = new javax.swing.JButton();
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle"); // NOI18N
setTitle(bundle.getString("ReplaceDialog.title")); // NOI18N
setName(""); // NOI18N
setResizable(false);
jLblFind.setDisplayedMnemonic('F');
jLblFind.setLabelFor(jCmbFind);
jLblFind.setText(bundle.getString("ReplaceDialog.jLblFind.text")); // NOI18N
jBtnNext.setIcon(new javax.swing.ImageIcon(getClass().getResource("/META-INF/images/small-icons/go-next.png"))); // NOI18N
jBtnNext.setMnemonic('N');
jBtnNext.setText(bundle.getString("ReplaceDialog.jBtnNext.text")); // NOI18N
jBtnNext.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jBtnNextActionPerformed(evt);
}
});
jBtnPrev.setIcon(new javax.swing.ImageIcon(getClass().getResource("/META-INF/images/small-icons/go-previous.png"))); // NOI18N
jBtnPrev.setMnemonic('N');
jBtnPrev.setText(bundle.getString("ReplaceDialog.jBtnPrev.text")); // NOI18N
jBtnPrev.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jBtnPrevActionPerformed(evt);
}
});
jBtnReplaceAll.setIcon(new javax.swing.ImageIcon(getClass().getResource("/META-INF/images/small-icons/edit-find-replace-all.png"))); // NOI18N
jBtnReplaceAll.setMnemonic('H');
jBtnReplaceAll.setText(bundle.getString("ReplaceDialog.jBtnReplaceAll.text")); // NOI18N
jBtnReplaceAll.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jBtnReplaceAllActionPerformed(evt);
}
});
jChkWrap.setMnemonic('W');
jChkWrap.setText(bundle.getString("ReplaceDialog.jChkWrap.text")); // NOI18N
jChkWrap.setToolTipText(bundle.getString("ReplaceDialog.jChkWrap.toolTipText")); // NOI18N
jChkRegex.setMnemonic('R');
jChkRegex.setText(bundle.getString("ReplaceDialog.jChkRegex.text")); // NOI18N
jChkIgnoreCase.setMnemonic('I');
jChkIgnoreCase.setText(bundle.getString("ReplaceDialog.jChkIgnoreCase.text")); // NOI18N
jLblReplace.setDisplayedMnemonic('R');
jLblReplace.setLabelFor(jCmbReplace);
jLblReplace.setText(bundle.getString("ReplaceDialog.jLblReplace.text")); // NOI18N
jTglHighlight.setIcon(new javax.swing.ImageIcon(getClass().getResource("/META-INF/images/small-icons/highlight.png"))); // NOI18N
jTglHighlight.setText(bundle.getString("ReplaceDialog.jTglHighlight.text")); // NOI18N
jTglHighlight.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jTglHighlightActionPerformed(evt);
}
});
jCmbReplace.setEditable(true);
jCmbFind.setEditable(true);
jBtnReplace.setIcon(new javax.swing.ImageIcon(getClass().getResource("/META-INF/images/small-icons/edit-find-replace.png"))); // NOI18N
jBtnReplace.setText(bundle.getString("ReplaceDialog.jBtnReplace.text")); // NOI18N
jBtnReplace.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jBtnReplaceActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jLblFind)
.addComponent(jLblReplace))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jCmbFind, 0, 289, Short.MAX_VALUE)
.addComponent(jCmbReplace, javax.swing.GroupLayout.Alignment.TRAILING, 0, 289, Short.MAX_VALUE)
.addComponent(jChkRegex, javax.swing.GroupLayout.DEFAULT_SIZE, 289, Short.MAX_VALUE)
.addComponent(jChkWrap, javax.swing.GroupLayout.DEFAULT_SIZE, 289, Short.MAX_VALUE)
.addComponent(jChkIgnoreCase, javax.swing.GroupLayout.DEFAULT_SIZE, 289, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jBtnReplace, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
.addComponent(jBtnNext, javax.swing.GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
.addComponent(jBtnPrev, javax.swing.GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
.addComponent(jTglHighlight, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
.addComponent(jBtnReplaceAll, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLblFind)
.addComponent(jCmbFind, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jBtnNext))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jBtnPrev)
.addComponent(jCmbReplace, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLblReplace))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jBtnReplace)
.addComponent(jChkWrap, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(3, 3, 3)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jChkRegex)
.addComponent(jBtnReplaceAll))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jChkIgnoreCase)
.addComponent(jTglHighlight))
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void jBtnNextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jBtnNextActionPerformed
try {
updateFinder();
if (!dsd.doFindNext(textComponent)) {
dsd.msgNotFound(textComponent);
}
textComponent.requestFocusInWindow();
} catch (PatternSyntaxException ex) {
showRegexpError(ex);
}
}//GEN-LAST:event_jBtnNextActionPerformed
private void jBtnReplaceAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jBtnReplaceAllActionPerformed
try {
updateFinder();
String replacement = (String) jCmbReplace.getSelectedItem();
ActionUtils.insertIntoCombo(jCmbReplace, replacement);
jTglHighlight.setSelected(false);
dsd.doReplaceAll(textComponent, replacement);
textComponent.requestFocusInWindow();
} catch (PatternSyntaxException ex) {
showRegexpError(ex);
}
}//GEN-LAST:event_jBtnReplaceAllActionPerformed
private void jTglHighlightActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jTglHighlightActionPerformed
updateFinder();
updateHighlights();
}//GEN-LAST:event_jTglHighlightActionPerformed
private void jBtnPrevActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jBtnPrevActionPerformed
updateFinder();
dsd.doFindPrev(textComponent);
}//GEN-LAST:event_jBtnPrevActionPerformed
private void jBtnReplaceActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jBtnReplaceActionPerformed
jTglHighlight.setSelected(false);
String replacement = jCmbReplace.getSelectedItem() == null ?
"" : jCmbReplace.getSelectedItem().toString();
dsd.doReplace(textComponent, replacement);
}//GEN-LAST:event_jBtnReplaceActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton jBtnNext;
private javax.swing.JButton jBtnPrev;
private javax.swing.JButton jBtnReplace;
private javax.swing.JButton jBtnReplaceAll;
private javax.swing.JCheckBox jChkIgnoreCase;
private javax.swing.JCheckBox jChkRegex;
private javax.swing.JCheckBox jChkWrap;
private javax.swing.JComboBox jCmbFind;
private javax.swing.JComboBox jCmbReplace;
private javax.swing.JLabel jLblFind;
private javax.swing.JLabel jLblReplace;
private javax.swing.JToggleButton jTglHighlight;
// End of variables declaration//GEN-END:variables
@Override
public void caretUpdate(CaretEvent e) {
updateHighlights();
}
@Override
public void escapePressed() {
setVisible(false);
}
}

View File

@@ -0,0 +1,115 @@
<?xml version="1.1" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="jsyntaxpane/Bundle.properties" key="ShowAbbsDialog.title" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="locationByPlatform" type="boolean" value="true"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[600, 300]"/>
</Property>
<Property name="modal" type="boolean" value="true"/>
<Property name="name" type="java.lang.String" value="dlgShowAbbs" noResource="true"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jSplitPane1" pref="580" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jSplitPane1" min="-2" pref="337" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="jSplitPane1">
<Properties>
<Property name="dividerLocation" type="int" value="150"/>
<Property name="dividerSize" type="int" value="3"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[258, 400]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="left"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="jLstAbbs">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
<StringArray count="0"/>
</Property>
<Property name="selectionMode" type="int" value="0"/>
</Properties>
<Events>
<EventHandler event="valueChanged" listener="javax.swing.event.ListSelectionListener" parameters="javax.swing.event.ListSelectionEvent" handler="jLstAbbsValueChanged"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="jScrollPane2">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="right"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JEditorPane" name="jEdtAbbr">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[106, 400]"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@@ -0,0 +1,136 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.actions.gui;
import java.util.Arrays;
import java.util.Map;
import javax.swing.JEditorPane;
import jsyntaxpane.actions.ActionUtils;
import jsyntaxpane.util.SwingUtils;
/**
* Show abbreviations for a JEditorPane.
*
* @author Ayman Al-Sairafi
*/
public class ShowAbbsDialog
extends javax.swing.JDialog implements EscapeListener {
/**
* Creates new form ShowAbbsDialog
* @param parent
* @param abbs
*/
public ShowAbbsDialog(JEditorPane parent, Map<String, String> abbs) {
super(ActionUtils.getFrameFor(parent), true);
initComponents();
Object[] abbsList = abbs.keySet().toArray();
Arrays.sort(abbsList);
jLstAbbs.setListData(abbsList);
this.abbs = abbs;
jEdtAbbr.setEditorKit(parent.getEditorKit());
jLstAbbs.setSelectedIndex(0);
SwingUtils.addEscapeListener(this);
setVisible(true);
}
/**
* This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jSplitPane1 = new javax.swing.JSplitPane();
jScrollPane1 = new javax.swing.JScrollPane();
jLstAbbs = new javax.swing.JList();
jScrollPane2 = new javax.swing.JScrollPane();
jEdtAbbr = new javax.swing.JEditorPane();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle"); // NOI18N
setTitle(bundle.getString("ShowAbbsDialog.title")); // NOI18N
setLocationByPlatform(true);
setMinimumSize(new java.awt.Dimension(600, 300));
setModal(true);
setName("dlgShowAbbs"); // NOI18N
jSplitPane1.setDividerLocation(150);
jSplitPane1.setDividerSize(3);
jScrollPane1.setPreferredSize(new java.awt.Dimension(258, 400));
jLstAbbs.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
jLstAbbs.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
jLstAbbsValueChanged(evt);
}
});
jScrollPane1.setViewportView(jLstAbbs);
jSplitPane1.setLeftComponent(jScrollPane1);
jEdtAbbr.setEditable(false);
jEdtAbbr.setMinimumSize(new java.awt.Dimension(106, 400));
jScrollPane2.setViewportView(jEdtAbbr);
jSplitPane1.setRightComponent(jScrollPane2);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 580, Short.MAX_VALUE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jSplitPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 337, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void jLstAbbsValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_jLstAbbsValueChanged
if (evt.getValueIsAdjusting() == false) {
Object selected = jLstAbbs.getSelectedValue();
if (selected != null) {
jEdtAbbr.setText(abbs.get(selected.toString()));
}
}
}//GEN-LAST:event_jLstAbbsValueChanged
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JEditorPane jEdtAbbr;
private javax.swing.JList jLstAbbs;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JSplitPane jSplitPane1;
// End of variables declaration//GEN-END:variables
Map<String, String> abbs;
@Override
public void escapePressed() {
setVisible(false);
}
}

View File

@@ -0,0 +1,322 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.components;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.BorderFactory;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.SyntaxView;
import jsyntaxpane.actions.ActionUtils;
import jsyntaxpane.actions.gui.GotoLineDialog;
import jsyntaxpane.util.Configuration;
/**
* This class will display line numbers for a related text component. The text
* component must use the same line height for each line.
*
* This class was designed to be used as a component added to the row header
* of a JScrollPane.
*
* Original code from http://tips4java.wordpress.com/2009/05/23/text-component-line-number/
*
* @author Rob Camick
*
* Revised for jsyntaxpane
*
* @author Ayman Al-Sairafi
*/
public class LineNumbersRuler extends JPanel
implements CaretListener, DocumentListener, PropertyChangeListener, SyntaxComponent {
public static final String PROPERTY_BACKGROUND = "LineNumbers.Background";
public static final String PROPERTY_FOREGROUND = "LineNumbers.Foreground";
public static final String PROPERTY_CURRENT_BACK = "LineNumbers.CurrentBack";
public static final String PROPERTY_LEFT_MARGIN = "LineNumbers.LeftMargin";
public static final String PROPERTY_RIGHT_MARGIN = "LineNumbers.RightMargin";
public static final String PROPERTY_Y_OFFSET = "LineNumbers.YOFFset";
public static final int DEFAULT_R_MARGIN = 5;
public static final int DEFAULT_L_MARGIN = 5;
private Status status;
private final static int HEIGHT = Integer.MAX_VALUE - 1000000;
// Text component this TextTextLineNumber component is in sync with
private JEditorPane editor;
private int minimumDisplayDigits = 2;
// Keep history information to reduce the number of times the component
// needs to be repainted
private int lastDigits;
private int lastHeight;
private int lastLine;
private MouseListener mouseListener = null;
// The formatting to use for displaying numbers. Use in String.format(numbersFormat, line)
private String numbersFormat = "%3d";
private Color currentLineColor;
/**
* Get the JscrollPane that contains this EditorPane, or null if no
* JScrollPane is the parent of this editor
* @param editorPane
* @return
*/
public JScrollPane getScrollPane(JTextComponent editorPane) {
Container p = editorPane.getParent();
while (p != null) {
if (p instanceof JScrollPane) {
return (JScrollPane) p;
}
p = p.getParent();
}
return null;
}
@Override
public void config(Configuration config) {
int right = config.getInteger(PROPERTY_RIGHT_MARGIN, DEFAULT_R_MARGIN);
int left = config.getInteger(PROPERTY_LEFT_MARGIN, DEFAULT_L_MARGIN);
Color foreground = config.getColor(PROPERTY_FOREGROUND, Color.BLACK);
setForeground(foreground);
Color back = config.getColor(PROPERTY_BACKGROUND, Color.WHITE);
setBackground(back);
setBorder(BorderFactory.createEmptyBorder(0, left, 0, right));
currentLineColor = config.getColor(PROPERTY_CURRENT_BACK, back);
}
@Override
public void install(final JEditorPane editor) {
this.editor = editor;
setFont(editor.getFont());
// setMinimumDisplayDigits(3);
editor.getDocument().addDocumentListener(this);
editor.addCaretListener(this);
editor.addPropertyChangeListener(this);
JScrollPane sp = getScrollPane(editor);
sp.setRowHeaderView(this);
mouseListener = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
GotoLineDialog.showForEditor(editor);
}
};
addMouseListener(mouseListener);
status = Status.INSTALLING;
}
@Override
public void deinstall(JEditorPane editor) {
removeMouseListener(mouseListener);
status = Status.DEINSTALLING;
this.editor.getDocument().removeDocumentListener(this);
editor.removeCaretListener(this);
editor.removePropertyChangeListener(this);
JScrollPane sp = getScrollPane(editor);
if (sp != null) {
editor.getDocument().removeDocumentListener(this);
sp.setRowHeaderView(null);
}
}
/**
* Gets the minimum display digits
*
* @return the minimum display digits
*/
public int getMinimumDisplayDigits() {
return minimumDisplayDigits;
}
/**
* Specify the minimum number of digits used to calculate the preferred
* width of the component. Default is 3.
*
* @param minimumDisplayDigits the number digits used in the preferred
* width calculation
*/
public void setMinimumDisplayDigits(int minimumDisplayDigits) {
this.minimumDisplayDigits = minimumDisplayDigits;
setPreferredWidth();
}
/**
* Calculate the width needed to display the maximum line number
*/
private void setPreferredWidth() {
int lines = ActionUtils.getLineCount(editor);
int digits = Math.max(String.valueOf(lines).length(), minimumDisplayDigits);
// Update sizes when number of digits in the line number changes
if (lastDigits != digits) {
lastDigits = digits;
numbersFormat = "%" + digits + "d";
FontMetrics fontMetrics = getFontMetrics(getFont());
int width = fontMetrics.charWidth('0') * digits;
Insets insets = getInsets();
int preferredWidth = insets.left + insets.right + width;
Dimension d = getPreferredSize();
d.setSize(preferredWidth, HEIGHT);
setPreferredSize(d);
setSize(d);
}
}
/**
* Draw the line numbers
*/
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
FontMetrics fontMetrics = editor.getFontMetrics(editor.getFont());
Insets insets = getInsets();
int currentLine = -1;
try {
// get current line, and add one as we start from 1 for the display
currentLine = ActionUtils.getLineNumber(editor, editor.getCaretPosition()) + 1;
} catch (BadLocationException ex) {
// this wont happen, even if it does, we can ignore it and we will not have
// a current line to worry about...
}
int lh = fontMetrics.getHeight();
int maxLines = ActionUtils.getLineCount(editor);
SyntaxView.setRenderingHits((Graphics2D) g);
for (int line = 1; line <= maxLines; line++) {
String lineNumber = String.format(numbersFormat, line);
int y = line * lh;
if (line == currentLine) {
g.setColor(currentLineColor);
g.fillRect(0, y - lh + fontMetrics.getDescent() - 1, getWidth(), lh);
g.setColor(getForeground());
g.drawString(lineNumber, insets.left, y);
} else {
g.drawString(lineNumber, insets.left, y);
}
}
}
//
// Implement CaretListener interface
//
@Override
public void caretUpdate(CaretEvent e) {
// Get the line the caret is positioned on
int caretPosition = editor.getCaretPosition();
Element root = editor.getDocument().getDefaultRootElement();
int currentLine = root.getElementIndex(caretPosition);
// Need to repaint so the correct line number can be highlighted
if (lastLine != currentLine) {
repaint();
lastLine = currentLine;
}
}
//
// Implement DocumentListener interface
//
@Override
public void changedUpdate(DocumentEvent e) {
documentChanged();
}
@Override
public void insertUpdate(DocumentEvent e) {
documentChanged();
}
@Override
public void removeUpdate(DocumentEvent e) {
documentChanged();
}
/*
* A document change may affect the number of displayed lines of text.
* Therefore the lines numbers will also change.
*/
private void documentChanged() {
// Preferred size of the component has not been updated at the time
// the DocumentEvent is fired
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
int preferredHeight = editor.getPreferredSize().height;
// Document change has caused a change in the number of lines.
// Repaint to reflect the new line numbers
if (lastHeight != preferredHeight) {
setPreferredWidth();
repaint();
lastHeight = preferredHeight;
}
}
});
}
/**
* Implement PropertyChangeListener interface
*/
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("document")) {
if (evt.getOldValue() instanceof SyntaxDocument) {
SyntaxDocument syntaxDocument = (SyntaxDocument) evt.getOldValue();
syntaxDocument.removeDocumentListener(this);
}
if (evt.getNewValue() instanceof SyntaxDocument && status.equals(Status.INSTALLING)) {
SyntaxDocument syntaxDocument = (SyntaxDocument) evt.getNewValue();
syntaxDocument.addDocumentListener(this);
setPreferredWidth();
repaint();
}
} else if (evt.getNewValue() instanceof Font) {
setPreferredWidth();
repaint();
}
}
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.components;
import jsyntaxpane.actions.*;
import java.awt.Color;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
/**
* This class contains static utility methods to make highliting in text
* components easier.
*
* @author Ayman Al-Sairafi
*/
public class Markers {
// This subclass is used in our highlighting code
public static class SimpleMarker extends DefaultHighlighter.DefaultHighlightPainter {
public SimpleMarker(Color color) {
super(color);
}
}
/**
* Removes only our private highlights
* This is public so that we can remove the highlights when the editorKit
* is unregistered. SimpleMarker can be null, in which case all instances of
* our Markers are removed.
* @param component the text component whose markers are to be removed
* @param marker the SimpleMarker to remove
*/
public static void removeMarkers(JTextComponent component, SimpleMarker marker) {
Highlighter hilite = component.getHighlighter();
Highlighter.Highlight[] hilites = hilite.getHighlights();
for (int i = 0; i < hilites.length; i++) {
if (hilites[i].getPainter() instanceof SimpleMarker) {
SimpleMarker hMarker = (SimpleMarker) hilites[i].getPainter();
if (marker == null || hMarker.equals(marker)) {
hilite.removeHighlight(hilites[i]);
}
}
}
}
/**
* Remove all the markers from an JEditorPane
* @param editorPane
*/
public static void removeMarkers(JTextComponent editorPane) {
removeMarkers(editorPane, null);
}
/**
* add highlights for the given Token on the given pane
* @param pane
* @param token
* @param marker
*/
public static void markToken(JTextComponent pane, Token token, SimpleMarker marker) {
markText(pane, token.start, token.end(), marker);
}
/**
* add highlights for the given region on the given pane
* @param pane
* @param start
* @param end
* @param marker
*/
public static void markText(JTextComponent pane, int start, int end, SimpleMarker marker) {
try {
Highlighter hiliter = pane.getHighlighter();
int selStart = pane.getSelectionStart();
int selEnd = pane.getSelectionEnd();
// if there is no selection or selection does not overlap
if(selStart == selEnd || end < selStart || start > selStart) {
hiliter.addHighlight(start, end, marker);
return;
}
// selection starts within the highlight, highlight before slection
if(selStart > start && selStart < end ) {
hiliter.addHighlight(start, selStart, marker);
}
// selection ends within the highlight, highlight remaining
if(selEnd > start && selEnd < end ) {
hiliter.addHighlight(selEnd, end, marker);
}
} catch (BadLocationException ex) {
// nothing we can do if the request is out of bound
LOG.log(Level.SEVERE, null, ex);
}
}
/**
* Mark all text in the document that matches the given pattern
* @param pane control to use
* @param pattern pattern to match
* @param marker marker to use for highlighting
*/
public static void markAll(JTextComponent pane, Pattern pattern, SimpleMarker marker) {
SyntaxDocument sDoc = ActionUtils.getSyntaxDocument(pane);
if(sDoc == null || pattern == null) {
return;
}
Matcher matcher = sDoc.getMatcher(pattern);
// we may not have any matcher (due to undo or something, so don't do anything.
if(matcher==null) {
return;
}
while(matcher.find()) {
markText(pane, matcher.start(), matcher.end(), marker);
}
}
private static final Logger LOG = Logger.getLogger(Markers.class.getName());
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.components;
import java.awt.Color;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import jsyntaxpane.actions.*;
import javax.swing.JEditorPane;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
import jsyntaxpane.util.Configuration;
/**
* This class highlights any pairs of the given language. Pairs are defined
* with the Token.pairValue.
*
* @author Ayman Al-Sairafi
*/
public class PairsMarker implements CaretListener, SyntaxComponent, PropertyChangeListener {
public static final String PROPERTY_COLOR = "PairMarker.Color";
private JTextComponent pane;
private Markers.SimpleMarker marker;
private Status status;
public PairsMarker() {
}
@Override
public void caretUpdate(CaretEvent e) {
removeMarkers();
int pos = e.getDot();
SyntaxDocument doc = ActionUtils.getSyntaxDocument(pane);
Token token = doc.getTokenAt(pos);
if (token != null && token.pairValue != 0) {
Markers.markToken(pane, token, marker);
Token other = doc.getPairFor(token);
if (other != null) {
Markers.markToken(pane, other, marker);
}
}
}
/**
* Remove all the highlights from the editor pane. This should be called
* when the editorkit is removed.
*/
public void removeMarkers() {
Markers.removeMarkers(pane, marker);
}
@Override
public void config(Configuration config) {
Color markerColor = config.getColor(PROPERTY_COLOR, new Color(0xeeee33));
this.marker = new Markers.SimpleMarker(markerColor);
}
@Override
public void install(JEditorPane editor) {
pane = editor;
pane.addCaretListener(this);
status = Status.INSTALLING;
}
@Override
public void deinstall(JEditorPane editor) {
status = Status.DEINSTALLING;
pane.removeCaretListener(this);
removeMarkers();
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("document")) {
pane.removeCaretListener(this);
if (status.equals(Status.INSTALLING)) {
pane.addCaretListener(this);
removeMarkers();
}
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.components;
import javax.swing.JEditorPane;
import jsyntaxpane.util.Configuration;
/**
* A Component that is installed to the EditorKit to perform GUI operations
* on the Editor.
*
* @author Ayman Al-Sairafi
*/
public interface SyntaxComponent {
/**
* Configure the component using the given properties. The keys
* needed for configuration will be prefixed by the given prefix
* @param config configuration data
*/
public void config(Configuration config);
/**
* Called to install the component on an editor
* @param editor
*/
public void install(JEditorPane editor);
/**
* Called when the component is to be removed from the editor
* @param editor
*/
public void deinstall(JEditorPane editor);
/**
* The status is used to have proper propertyCHange support. We need to know if we are INSTALLING
* the component or DE-INSTALLING it
*/
static enum Status {
INSTALLING,
DEINSTALLING
}
}

View File

@@ -0,0 +1,146 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.components;
import java.beans.PropertyChangeEvent;
import jsyntaxpane.actions.*;
import java.awt.Color;
import java.beans.PropertyChangeListener;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Logger;
import javax.swing.JEditorPane;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
import jsyntaxpane.TokenType;
import jsyntaxpane.util.Configuration;
/**
* This class highlights Tokens within a document whenever the caret is moved
* to a TokenType provided in the config file.
*
* @author Ayman Al-Sairafi
*/
public class TokenMarker implements SyntaxComponent, CaretListener, PropertyChangeListener {
public static final String DEFAULT_TOKENTYPES = "IDENTIFIER, TYPE, TYPE2, TYPE3";
public static final String PROPERTY_COLOR = "TokenMarker.Color";
public static final String PROPERTY_TOKENTYPES = "TokenMarker.TokenTypes";
private static final Color DEFAULT_COLOR = new Color(0xFFEE66);
private JEditorPane pane;
private Set<TokenType> tokenTypes = new HashSet<TokenType>();
private Markers.SimpleMarker marker;
private Status status;
/**
* Constructs a new Token highlighter
*/
public TokenMarker() {
}
@Override
public void caretUpdate(CaretEvent e) {
markTokenAt(e.getDot());
}
public void markTokenAt(int pos) {
SyntaxDocument doc = ActionUtils.getSyntaxDocument(pane);
if (doc != null) {
Token token = doc.getTokenAt(pos);
removeMarkers();
if (token != null && tokenTypes.contains(token.type)) {
addMarkers(token);
}
}
}
/**
* removes all markers from the pane.
*/
public void removeMarkers() {
Markers.removeMarkers(pane, marker);
}
/**
* add highlights for the given pattern
* @param pattern
*/
void addMarkers(Token tok) {
SyntaxDocument sDoc = (SyntaxDocument) pane.getDocument();
sDoc.readLock();
// we need to create a STring, because the CharSequence does not have an
// equals method and Object.equals is called. It will not match
String text = tok.getText(sDoc).toString();
Iterator<Token> it = sDoc.getTokens(0, sDoc.getLength());
while (it.hasNext()) {
Token nextToken = it.next();
String nextText = nextToken.getText(sDoc).toString();
if (text.equals(nextText)) {
Markers.markToken(pane, nextToken, marker);
}
}
sDoc.readUnlock();
}
@Override
public void config(Configuration config) {
Color markerColor = config.getColor(
PROPERTY_COLOR, DEFAULT_COLOR);
this.marker = new Markers.SimpleMarker(markerColor);
String types = config.getString(
PROPERTY_TOKENTYPES, DEFAULT_TOKENTYPES);
for (String type : types.split("\\s*,\\s*")) {
try {
TokenType tt = TokenType.valueOf(type);
tokenTypes.add(tt);
} catch (IllegalArgumentException e) {
LOG.warning("Error in setting up TokenMarker " +
" - Invalid TokenType: " + type);
}
}
}
@Override
public void install(JEditorPane editor) {
this.pane = editor;
pane.addCaretListener(this);
markTokenAt(editor.getCaretPosition());
status = Status.INSTALLING;
}
@Override
public void deinstall(JEditorPane editor) {
status = Status.DEINSTALLING;
removeMarkers();
pane.removeCaretListener(this);
}
private static final Logger LOG = Logger.getLogger(TokenMarker.class.getName());
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("document")) {
pane.removeCaretListener(this);
if (status.equals(Status.INSTALLING)) {
pane.addCaretListener(this);
removeMarkers();
}
}
}
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.lexers;
import java.io.CharArrayReader;
import jsyntaxpane.*;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.Segment;
/**
* This is a default, and abstract implemenatation of a Lexer using JFLex
* with some utility methods that Lexers can implement.
*
* @author Ayman Al-Sairafi
*/
public abstract class DefaultJFlexLexer implements Lexer {
protected int tokenStart;
protected int tokenLength;
protected int offset;
/**
* Helper method to create and return a new Token from of TokenType
* tokenStart and tokenLength will be modified to the newStart and
* newLength params
* @param type
* @param tStart
* @param tLength
* @param newStart
* @param newLength
* @return
*/
protected Token token(TokenType type, int tStart, int tLength,
int newStart, int newLength) {
tokenStart = newStart;
tokenLength = newLength;
return new Token(type, tStart + offset, tLength);
}
/**
* Create and return a Token of given type from start with length
* offset is added to start
* @param type
* @param start
* @param length
* @return
*/
protected Token token(TokenType type, int start, int length) {
return new Token(type, start + offset, length);
}
/**
* Create and return a Token of given type. start is obtained from {@link yychar()}
* and length from {@link yylength()}
* offset is added to start
* @param type
* @return
*/
protected Token token(TokenType type) {
return new Token(type, yychar() + offset, yylength());
}
/**
* Create and return a Token of given type and pairValue.
* start is obtained from {@link yychar()}
* and length from {@link yylength()}
* offset is added to start
*
* @param type
* @param pairValue
* @return
*/
protected Token token(TokenType type, int pairValue) {
return new Token(type, yychar() + offset, yylength(), (byte) pairValue);
}
/**
* The DefaultJFlexLexer simply calls the yylex method of a JFLex compatible
* Lexer and adds the tokens obtained to an ArrayList.
*/
@Override
public void parse(Segment segment, int ofst, List<Token> tokens) {
try {
CharArrayReader reader = new CharArrayReader(segment.array, segment.offset, segment.count);
yyreset(reader);
this.offset = ofst;
for (Token t = yylex(); t != null; t = yylex()) {
tokens.add(t);
}
} catch (IOException ex) {
Logger.getLogger(DefaultJFlexLexer.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* This will be called to reset the the lexer.
* This is created automatically by JFlex.
* @param reader
*/
public abstract void yyreset(Reader reader);
/**
* This is called to return the next Token from the Input Reader
* @return next token, or null if no more tokens.
* @throws java.io.IOException
*/
public abstract Token yylex() throws java.io.IOException;
/**
* Returns the character at position <tt>pos</tt> from the
* matched text.
*
* It is equivalent to yytext().charAt(pos), but faster
*
* @param pos the position of the character to fetch.
* A value from 0 to yylength()-1.
*
* @return the character at position pos
*/
public abstract char yycharat(int pos);
/**
* Returns the length of the matched text region.
* This method is automatically implemented by JFlex lexers
* @return
*/
public abstract int yylength();
/**
* Returns the text matched by the current regular expression.
* This method is automatically implemented by JFlex lexers
* @return
*/
public abstract String yytext();
/**
* Return the char number from beginning of input stream.
* This is NOT implemented by JFLex, so the code must be
* added to create this and return the private yychar field
* @return
*/
public abstract int yychar();
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.lexers;
import jsyntaxpane.*;
import java.util.List;
import javax.swing.text.Segment;
/**
* A lexer that does nothing. Used for plain document editing.
* @author Ayman Al-Sairafi
*/
public class EmptyLexer implements Lexer {
@Override
public void parse(Segment segment, int ofst, List<Token> tokens) {
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.lexers;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.text.Segment;
import jsyntaxpane.Lexer;
import jsyntaxpane.Token;
import jsyntaxpane.TokenComparators;
import jsyntaxpane.TokenType;
/**
* This is a "dynamic" Lexer that will use Regex patterns to parse any document,
* It is NOT as fast as other JFLex generated lexers.
*
* The current implementation is about 20x slower than a JFLex lexer
* (5000 lines in 100ms, vs 5ms for JFlex lexer)
*
* This is still usable for a few 100 lines. 500 lines parse in about 10ms.
*
* It also depends on how complex the Regexp and how many of them will actually
* provide a match.
*
* Since KEYWORD TokenType is by order less than IDENTIFIER, the higher
* precedence of KEYWORD token will be used, even if the same regex matches
* an IDENTIFIER. This is a neat side-effect of the ordering of the TokenTypes.
* We now just need to add any non-overlapping matches. And since longer matches
* are found first, we will properly match the longer identifiers which start with
* a keyword.
*
* This behaviour can easily be modified by overriding the {@link compareTo} method
*
* @author Ayman Al-Sairafi
*/
public class SimpleRegexLexer implements Lexer {
public SimpleRegexLexer(Map props) {
putPatterns(props);
}
public SimpleRegexLexer(String propsLocation) throws IOException {
Properties props = new Properties();
props.load(new FileReader(propsLocation));
putPatterns(props);
}
@Override
public void parse(Segment segment, int ofst, List<Token> tokens) {
TreeSet<Token> allMatches = new TreeSet<Token>(TokenComparators.LONGEST_FIRST);
// add to ourset all the matches by all our regexes
for (Map.Entry<TokenType, Pattern> e : patterns.entrySet()) {
Matcher m = e.getValue().matcher(segment);
while (m.find()) {
Token t = new Token(e.getKey(), m.start() + ofst, m.end() - m.start());
allMatches.add(t);
}
}
int end = -1;
for (Token t : allMatches) {
if (t.start > end) {
tokens.add(t);
end = t.end();
}
}
}
Map<TokenType, Pattern> patterns = new HashMap<TokenType, Pattern>();
public SimpleRegexLexer putPattern(TokenType type, String regex) {
patterns.put(type, Pattern.compile(regex));
return this;
}
public SimpleRegexLexer putPatterns(Map props) {
for (Object key : props.keySet()) {
TokenType t = TokenType.valueOf(key.toString());
patterns.put(t, Pattern.compile(props.get(key).toString()));
}
return this;
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.Lexer;
import jsyntaxpane.lexers.ActionScriptLexer;
/**
*
* @author JPEXS
*/
public class ActionScriptSyntaxKit extends DefaultSyntaxKit {
public ActionScriptSyntaxKit() {
super(new ActionScriptLexer());
}
ActionScriptSyntaxKit(Lexer lexer) {
super(lexer);
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.lexers.BashLexer;
/**
*
* @author Ayman Al-Sairafi
*/
public class BashSyntaxKit extends DefaultSyntaxKit {
public BashSyntaxKit() {
super(new BashLexer());
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.Lexer;
import jsyntaxpane.lexers.CLexer;
/**
*
* @author Ayman Al-Sairafi
*/
public class CSyntaxKit extends DefaultSyntaxKit {
public CSyntaxKit() {
super(new CLexer());
}
/**
* Construct a JavaSyntaxKit user the supplied lexer. This is protected so
* only subclasses may extend this with a new lexer.
* @param lexer
*/
CSyntaxKit(Lexer lexer) {
super(lexer);
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.Lexer;
import jsyntaxpane.lexers.ClojureLexer;
/**
*
* @author Ayman Al-Sairafi
*/
public class ClojureSyntaxKit extends DefaultSyntaxKit {
public ClojureSyntaxKit() {
super(new ClojureLexer());
}
public ClojureSyntaxKit(Lexer lexer) {
super(lexer);
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.lexers.CppLexer;
/**
*
* @author Ayman Al-Sairafi
*/
public class CppSyntaxKit extends CSyntaxKit {
public CppSyntaxKit() {
super(new CppLexer());
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.lexers.DOSBatchLexer;
/**
*
* @author Ayman Al-Sairafi
*/
public class DOSBatchSyntaxKit extends DefaultSyntaxKit {
public DOSBatchSyntaxKit() {
super(new DOSBatchLexer());
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.Lexer;
import jsyntaxpane.lexers.Flasm3MethodInfoLexer;
/**
* @author JPEXS
*/
public class Flasm3MethodInfoSyntaxKit extends DefaultSyntaxKit {
public Flasm3MethodInfoSyntaxKit() {
super(new Flasm3MethodInfoLexer());
}
Flasm3MethodInfoSyntaxKit(Lexer lexer) {
super(lexer);
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.Lexer;
import jsyntaxpane.lexers.Flasm3Lexer;
/**
* @author JPEXS
*/
public class Flasm3SyntaxKit extends DefaultSyntaxKit {
public Flasm3SyntaxKit() {
super(new Flasm3Lexer());
}
Flasm3SyntaxKit(Lexer lexer) {
super(lexer);
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.Lexer;
import jsyntaxpane.lexers.FlasmLexer;
/**
* @author JPEXS
*/
public class FlasmSyntaxKit extends DefaultSyntaxKit {
public FlasmSyntaxKit() {
super(new FlasmLexer());
}
FlasmSyntaxKit(Lexer lexer) {
super(lexer);
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.lexers.GroovyLexer;
/**
*
* @author Ayman Al-Sairafi
*/
public class GroovySyntaxKit extends JavaSyntaxKit {
public GroovySyntaxKit() {
super(new GroovyLexer());
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.lexers.JFlexLexer;
/**
* JFlex lexer
* @author Ayman Al-Sairafi
*/
public class JFlexSyntaxKit extends JavaSyntaxKit {
public JFlexSyntaxKit() {
super(new JFlexLexer());
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.lexers.JavaScriptLexer;
/**
*
* @author Ayman Al-Sairafi
*/
public class JavaScriptSyntaxKit extends DefaultSyntaxKit {
public JavaScriptSyntaxKit() {
super(new JavaScriptLexer());
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.Lexer;
import jsyntaxpane.lexers.JavaLexer;
/**
*
* @author Ayman Al-Sairafi
*/
public class JavaSyntaxKit extends DefaultSyntaxKit {
public JavaSyntaxKit() {
super(new JavaLexer());
}
JavaSyntaxKit(Lexer lexer) {
super(lexer);
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.lexers.LuaLexer;
/**
*
* @author Michael Leung
*/
public class LuaSyntaxKit extends DefaultSyntaxKit {
public LuaSyntaxKit() {
super(new LuaLexer());
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.lexers.EmptyLexer;
/**
*
* @author Ayman Al-Sairafi
*/
public class PlainSyntaxKit extends DefaultSyntaxKit {
public PlainSyntaxKit() {
super(new EmptyLexer());
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.lexers.PropertiesLexer;
/**
*
* @author Ayman Al-Sairafi
*/
public class PropertiesSyntaxKit extends DefaultSyntaxKit {
public PropertiesSyntaxKit() {
super(new PropertiesLexer());
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.lexers.PythonLexer;
/**
*
* @author Ayman Al-Sairafi
*/
public class PythonSyntaxKit extends DefaultSyntaxKit {
public PythonSyntaxKit() {
super(new PythonLexer());
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.lexers.RubyLexer;
/**
*
* @author Ayman Al-Sairafi
*/
public class RubySyntaxKit extends DefaultSyntaxKit {
public RubySyntaxKit() {
super(new RubyLexer());
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed 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 jsyntaxpane.syntaxkits;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.Lexer;
import jsyntaxpane.lexers.SWFTextLexer;
/**
* @author JPEXS
*/
public class SWFTextSyntaxKit extends DefaultSyntaxKit {
public SWFTextSyntaxKit() {
super(new SWFTextLexer());
}
SWFTextSyntaxKit(Lexer lexer) {
super(lexer);
}
}

Some files were not shown because too many files have changed in this diff Show More