ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I'm creating a simple application with Java to make simple SQL-Queries. It's still very simple and even the GUI needs some work. Well, take a look in here please:
As you see, at the bottom of the application I've a JTextArea where you can type SQL commands. My question is, how could I create the effect of real time syntax highlighting? For example, if the user type "select" I want it to change and display "on-the-fly" as SELECT. I should do the same with every SQL command: change color and make everything to upperCase.
Any ideas?
Thanks in advance!
Last edited by Mega Man X; 02-20-2006 at 10:27 AM.
JTextArea text = new JTextArea();
text.addKeyListener
(
new KeyListener()
{
public void keyPressed(KeyEvent e){/*Add the procedures here*/}
public void keyReleased(KeyEvent e){}
public void keyTyped(KeyEvent e){/*Or add the procedures here*/}
}
);
Thanks for your reply mate. Your idea sounds neat . I've been "googling" a lot after this and I came into a bunch of complicated alternatives but your sounds the best. I got a lot to do, so the project is on hold until the weekend. I will let you know if it worked
Hi Mega Man X,
Try this code it is not tested but should work. TODO(Add more sql keywords). It is a simple parser not suited for big applications. To use it :
Code:
JTextArea txt = new JTextArea();
txt.setDocument(new SqlDocument());
Code:
public class SqlDocument extends DefaultStyledDocument {
private DefaultStyledDocument doc;
private Element rootElement;
private boolean multiLineComment;
private MutableAttributeSet normal;
private MutableAttributeSet keyword;
private MutableAttributeSet comment;
private MutableAttributeSet quote;
private Hashtable keywords;
public SqlDocument() {
doc = this;
rootElement = doc.getDefaultRootElement();
putProperty(DefaultEditorKit.EndOfLineStringProperty, "\n");
normal = new SimpleAttributeSet();
StyleConstants.setForeground(normal, Color.black);
comment = new SimpleAttributeSet();
Color green = new Color(0, 120, 0);
StyleConstants.setForeground(comment, green);
//StyleConstants.setItalic(comment, true);
keyword = new SimpleAttributeSet();
Color blue = new Color(0, 0, 140);
StyleConstants.setForeground(keyword, blue);
//StyleConstants.setBold(keyword, true);
quote = new SimpleAttributeSet();
Color red = new Color(140, 0, 0);
StyleConstants.setForeground(quote, red);
Object dummyObject = new Object();
keywords = new Hashtable();
keywords.put("SELECT", dummyObject);
keywords.put("INSERT", dummyObject);
keywords.put("DROP", dummyObject);
}
/*
* Override to apply syntax highlighting after the document has been updated
*/
public void insertString(int offset, String str, AttributeSet a)
throws BadLocationException {
if (str.equals("{"))
str = addMatchingBrace(offset);
super.insertString(offset, str, a);
processChangedLines(offset, str.length());
}
/*
* Override to apply syntax highlighting after the document has been updated
*/
public void remove(int offset, int length) throws BadLocationException {
super.remove(offset, length);
processChangedLines(offset, 0);
}
/*
* Determine how many lines have been changed,
* then apply highlighting to each line
*/
private void processChangedLines(int offset, int length)
throws BadLocationException {
String content = doc.getText(0, doc.getLength());
// The lines affected by the latest document update
int startLine = rootElement.getElementIndex(offset);
int endLine = rootElement.getElementIndex(offset + length);
// Make sure all comment lines prior to the start line are commented
// and determine if the start line is still in a multi line comment
setMultiLineComment(commentLinesBefore(content, startLine));
// Do the actual highlighting
for (int i = startLine; i <= endLine; i++)
applyHighlighting(content, i);
// Resolve highlighting to the next end multi line delimiter
if (isMultiLineComment())
commentLinesAfter(content, endLine);
else
highlightLinesAfter(content, endLine);
}
/*
* Highlight lines when a multi line comment is still 'open'
* (ie. matching end delimiter has not yet been encountered)
*/
private boolean commentLinesBefore(String content, int line) {
int offset = rootElement.getElement(line).getStartOffset();
// Start of comment not found, nothing to do
int startDelimiter = lastIndexOf(content, getStartDelimiter(),
offset - 2);
if (startDelimiter < 0)
return false;
// Matching start/end of comment found, nothing to do
int endDelimiter = indexOf(content, getEndDelimiter(), startDelimiter);
if (endDelimiter < offset & endDelimiter != -1)
return false;
// End of comment not found, highlight the lines
doc.setCharacterAttributes(startDelimiter, offset - startDelimiter + 1,
comment, false);
return true;
}
/*
* Highlight comment lines to matching end delimiter
*/
private void commentLinesAfter(String content, int line) {
int offset = rootElement.getElement(line).getEndOffset();
// End of comment not found, nothing to do
int endDelimiter = indexOf(content, getEndDelimiter(), offset);
if (endDelimiter < 0)
return;
// Matching start/end of comment found, comment the lines
int startDelimiter = lastIndexOf(content, getStartDelimiter(),
endDelimiter);
if (startDelimiter < 0 || startDelimiter <= offset) {
doc.setCharacterAttributes(offset, endDelimiter - offset + 1,
comment, false);
}
}
/*
* Highlight lines to start or end delimiter
*/
private void highlightLinesAfter(String content, int line)
throws BadLocationException {
int offset = rootElement.getElement(line).getEndOffset();
// Start/End delimiter not found, nothing to do
int startDelimiter = indexOf(content, getStartDelimiter(), offset);
int endDelimiter = indexOf(content, getEndDelimiter(), offset);
if (startDelimiter < 0)
startDelimiter = content.length();
if (endDelimiter < 0)
endDelimiter = content.length();
int delimiter = Math.min(startDelimiter, endDelimiter);
if (delimiter < offset)
return;
// Start/End delimiter found, reapply highlighting
int endLine = rootElement.getElementIndex(delimiter);
for (int i = line + 1; i < endLine; i++) {
Element branch = rootElement.getElement(i);
Element leaf = doc.getCharacterElement(branch.getStartOffset());
AttributeSet as = leaf.getAttributes();
if (as.isEqual(comment))
applyHighlighting(content, i);
}
}
/*
* Parse the line to determine the appropriate highlighting
*/
private void applyHighlighting(String content, int line)
throws BadLocationException {
int startOffset = rootElement.getElement(line).getStartOffset();
int endOffset = rootElement.getElement(line).getEndOffset() - 1;
int lineLength = endOffset - startOffset;
int contentLength = content.length();
if (endOffset >= contentLength)
endOffset = contentLength - 1;
// check for multi line comments
// (always set the comment attribute for the entire line)
if (endingMultiLineComment(content, startOffset, endOffset)
|| isMultiLineComment()
|| startingMultiLineComment(content, startOffset, endOffset)) {
doc.setCharacterAttributes(startOffset,
endOffset - startOffset + 1, comment, false);
return;
}
// set normal attributes for the line
doc.setCharacterAttributes(startOffset, lineLength, normal, true);
// check for single line comment
int index = content.indexOf(getSingleLineDelimiter(), startOffset);
if ((index > -1) && (index < endOffset)) {
doc.setCharacterAttributes(index, endOffset - index + 1, comment,
false);
endOffset = index - 1;
}
// check for tokens
checkForTokens(content, startOffset, endOffset);
}
/*
* Does this line contain the start delimiter
*/
private boolean startingMultiLineComment(String content, int startOffset,
int endOffset) throws BadLocationException {
int index = indexOf(content, getStartDelimiter(), startOffset);
if ((index < 0) || (index > endOffset))
return false;
else {
setMultiLineComment(true);
return true;
}
}
/*
* Does this line contain the end delimiter
*/
private boolean endingMultiLineComment(String content, int startOffset,
int endOffset) throws BadLocationException {
int index = indexOf(content, getEndDelimiter(), startOffset);
if ((index < 0) || (index > endOffset))
return false;
else {
setMultiLineComment(false);
return true;
}
}
/*
* We have found a start delimiter
* and are still searching for the end delimiter
*/
private boolean isMultiLineComment() {
return multiLineComment;
}
private void setMultiLineComment(boolean value) {
multiLineComment = value;
}
/*
* Parse the line for tokens to highlight
*/
private void checkForTokens(String content, int startOffset, int endOffset) {
while (startOffset <= endOffset) {
// skip the delimiters to find the start of a new token
while (isDelimiter(content.substring(startOffset, startOffset + 1))) {
if (startOffset < endOffset)
startOffset++;
else
return;
}
// Extract and process the entire token
if (isQuoteDelimiter(content
.substring(startOffset, startOffset + 1)))
startOffset = getQuoteToken(content, startOffset, endOffset);
else
startOffset = getOtherToken(content, startOffset, endOffset);
}
}
/*
* Parse the line to get the quotes and highlight it
*/
private int getQuoteToken(String content, int startOffset, int endOffset) {
String quoteDelimiter = content.substring(startOffset, startOffset + 1);
String escapeString = getEscapeString(quoteDelimiter);
int index;
int endOfQuote = startOffset;
// skip over the escape quotes in this quote
index = content.indexOf(escapeString, endOfQuote + 1);
while ((index > -1) && (index < endOffset)) {
endOfQuote = index + 1;
index = content.indexOf(escapeString, endOfQuote);
}
// now find the matching delimiter
index = content.indexOf(quoteDelimiter, endOfQuote + 1);
if ((index < 0) || (index > endOffset))
endOfQuote = endOffset;
else
endOfQuote = index;
doc.setCharacterAttributes(startOffset, endOfQuote - startOffset + 1,
quote, false);
return endOfQuote + 1;
}
private int getOtherToken(String content, int startOffset, int endOffset) {
int endOfToken = startOffset + 1;
while (endOfToken <= endOffset) {
if (isDelimiter(content.substring(endOfToken, endOfToken + 1)))
break;
endOfToken++;
}
String token = content.substring(startOffset, endOfToken);
if (isKeyword(token))
doc.setCharacterAttributes(startOffset, endOfToken - startOffset,
keyword, false);
return endOfToken + 1;
}
/*
* This updates the colored text and prepares for undo event
*/
protected void fireInsertUpdate(DocumentEvent evt) {
super.fireInsertUpdate(evt);
try {
processChangedLines(evt.getOffset(), evt.getLength());
} catch (BadLocationException ex) {
System.out.println("" + ex);
}
}
/*
* This updates the colored text and does the undo operation
*/
protected void fireRemoveUpdate(DocumentEvent evt) {
super.fireRemoveUpdate(evt);
try {
processChangedLines(evt.getOffset(), evt.getLength());
} catch (BadLocationException ex) {
System.out.println("" + ex);
}
}
/*
* Assume the needle will the found at the start/end of the line
*/
private int indexOf(String content, String needle, int offset) {
int index;
while ((index = content.indexOf(needle, offset)) != -1) {
String text = getLine(content, index).trim();
if (text.startsWith(needle) || text.endsWith(needle))
break;
else
offset = index + 1;
}
return index;
}
/*
* Assume the needle will the found at the start/end of the line
*/
private int lastIndexOf(String content, String needle, int offset) {
int index;
while ((index = content.lastIndexOf(needle, offset)) != -1) {
String text = getLine(content, index).trim();
if (text.startsWith(needle) || text.endsWith(needle))
break;
else
offset = index - 1;
}
return index;
}
private String getLine(String content, int offset) {
int line = rootElement.getElementIndex(offset);
Element lineElement = rootElement.getElement(line);
int start = lineElement.getStartOffset();
int end = lineElement.getEndOffset();
return content.substring(start, end - 1);
}
/*
* Override for other languages
*/
protected boolean isDelimiter(String character) {
String operands = ";:{}()[]+-/%<=>!&|^~*";
if (Character.isWhitespace(character.charAt(0))
|| operands.indexOf(character) != -1)
return true;
else
return false;
}
/*
* Override for other languages
*/
protected boolean isQuoteDelimiter(String character) {
String quoteDelimiters = "\"'";
if (quoteDelimiters.indexOf(character) < 0)
return false;
else
return true;
}
/*
* Override for other languages
*/
protected boolean isKeyword(String token) {
Object o = keywords.get(token.toUpperCase());
return o == null ? false : true;
}
/*
* Override for other languages
*/
protected String getStartDelimiter() {
return "/*";
}
/*
* Override for other languages
*/
protected String getEndDelimiter() {
return "*/";
}
/*
* Override for other languages
*/
protected String getSingleLineDelimiter() {
return "--";
}
/*
* Override for other languages
*/
protected String getEscapeString(String quoteDelimiter) {
return "\\" + quoteDelimiter;
}
/*
* Overide bracket matching for other languages
*/
protected String addMatchingBrace(int offset) throws BadLocationException {
StringBuffer whiteSpace = new StringBuffer();
int line = rootElement.getElementIndex(offset);
int i = rootElement.getElement(line).getStartOffset();
while (true) {
String temp = doc.getText(i, 1);
if (temp.equals(" ") || temp.equals("\t")) {
whiteSpace.append(temp);
i++;
} else
break;
}
return "{\n" + whiteSpace.toString() + whiteSpace.toString() + "\n"
+ whiteSpace.toString() + "}";
}
}
Chances are you'll want to use JTextPane or JEditorPane. I created an assembly editor in Java a while back w/ some basic syntax highlighting, but I can't seem to find the code anywhere.
Thanks a lot guys! I really appreciated all your replies . I've not time to test all that has been suggested, except for mrcheeks code, which I did a quick 'n dirty copy-paste and got a few problems, which has to do with not importing the necessary packages, but that's all my fault. I will try to implement that feature this weekend and see how it goes.
Very interesting that mrcheeks code works with a JTextArea. Everything I've found on the net suggested a JTextPane as 95se suggested.
Well, let's see how it goes. I'm also replacing the JTextAre at the top for a JTable and adding a JTree at the right to display current database and tables.
Useless application, I know... but I'm having a lot of fun
you might find the source code of squirrel ( http://squirrel-sql.sf.net ) useful... it does full SQL hilighting, even hilighting valid/invalid tables and columns in queries
these classes do it I believe (I haven't spent much time looking so I could be wrong though).
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.