LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 02-20-2006, 10:21 AM   #1
Mega Man X
LQ Guru
 
Registered: Apr 2003
Location: ~
Distribution: Ubuntu, FreeBSD, Solaris, DSL
Posts: 5,339

Rep: Reputation: 65
Java: JTextArea and Syntax Highlighting?


Hi there!

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:

http://goto.glocalnet.net/torch/temp/java_sql.JPG

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.
 
Old 02-21-2006, 01:09 AM   #2
MRMadhav
Member
 
Registered: Nov 2005
Location: Mauritius
Distribution: PCQLinux, SUSE Linux,Fedora Core 5, Fedora Core 6, Knoppix Live, Kubuntu Edgy, PCLinuxOS
Posts: 167

Rep: Reputation: 30
well as long as you know the syntax then place the functions you need in the KeyListener abstract function keyTyped(KeyEvent)
 
Old 02-21-2006, 01:14 AM   #3
MRMadhav
Member
 
Registered: Nov 2005
Location: Mauritius
Distribution: PCQLinux, SUSE Linux,Fedora Core 5, Fedora Core 6, Knoppix Live, Kubuntu Edgy, PCLinuxOS
Posts: 167

Rep: Reputation: 30
eg:

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*/}
}
);
 
Old 02-21-2006, 06:33 AM   #4
Mega Man X
LQ Guru
 
Registered: Apr 2003
Location: ~
Distribution: Ubuntu, FreeBSD, Solaris, DSL
Posts: 5,339

Original Poster
Rep: Reputation: 65
Hi MRMadhav!

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

Thanks again!
 
Old 02-21-2006, 12:13 PM   #5
mrcheeks
Senior Member
 
Registered: Mar 2004
Location: far enough
Distribution: OS X 10.6.7
Posts: 1,690

Rep: Reputation: 52
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() + "}";
	}
}
 
Old 02-21-2006, 05:40 PM   #6
95se
Member
 
Registered: Apr 2002
Location: Windsor, ON, CA
Distribution: Ubuntu
Posts: 740

Rep: Reputation: 32
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.
 
Old 02-22-2006, 05:42 PM   #7
Mega Man X
LQ Guru
 
Registered: Apr 2003
Location: ~
Distribution: Ubuntu, FreeBSD, Solaris, DSL
Posts: 5,339

Original Poster
Rep: Reputation: 65
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
 
Old 02-22-2006, 10:07 PM   #8
german
Member
 
Registered: Jul 2003
Location: Toronto, Canada
Distribution: Debian etch, Gentoo
Posts: 312

Rep: Reputation: 30
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).

http://cvs.sourceforge.net/viewcvs.p...rge/jcomplete/

Last edited by german; 02-22-2006 at 10:11 PM.
 
Old 02-23-2006, 10:31 AM   #9
foo_bar_foo
Senior Member
 
Registered: Jun 2004
Posts: 2,553

Rep: Reputation: 53
there is a GPLd version of JEditTextArea on sourceforge that has plug and play syntax highlighting.

http://sourceforge.net/projects/jedit-syntax
says it's a bean but i don't think it used to be ?

i put the original released version of the gpld JEditTextArea in this so its code might help you.
http://patriot.net/~gary/JEditPad1.4.src.zip
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
syntax highlighting rohr Programming 3 07-06-2005 06:07 AM
vim syntax highlighting MiniMe001 Linux - General 2 06-19-2005 11:08 AM
Java syntax highlighting in vim Phantomas Linux - Software 0 08-16-2003 04:34 AM
xemacs syntax highlighting jclark00001 Linux - Software 2 04-13-2003 04:40 PM
Vim syntax highlighting NSKL Linux - Software 2 11-09-2002 02:39 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 07:11 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration