Revision 43

View differences:

org.gvsig.expressionfield/trunk/org.gvsig.expressionfield/src/main/java/org/gvsig/expressionfield/project/documents/table/gui/syntaxhighlight/SyntaxtHighlightTextComponent.java
1
package org.gvsig.expressionfield.project.documents.table.gui.syntaxhighlight;
2

  
3
import java.awt.event.ActionListener;
4
import java.awt.event.KeyListener;
5

  
6
import javax.swing.JScrollPane;
7
import javax.swing.text.JTextComponent;
8

  
9
public interface SyntaxtHighlightTextComponent {
10

  
11
	public interface UpdateCaretPositionActionEvent {
12
		public int getLine();
13
		public int getColumn();
14
		public boolean hasLineAndColumn();
15
	}
16
	
17
	public JTextComponent getJTextComponent();
18
	
19
	public JScrollPane getJScrollPane();
20
	
21
	public void setText(String text);
22
	
23
	public String getText();
24
	
25
	public void setContentType(String contentType);
26
	
27
	public String getContentType();
28
	
29
	public void addUpdateCaretPositionActionListener(ActionListener updateCaretPosition);
30
	
31
	public void addKeyListener(KeyListener keyListener);
32
	
33
}
org.gvsig.expressionfield/trunk/org.gvsig.expressionfield/src/main/java/org/gvsig/expressionfield/project/documents/table/gui/syntaxhighlight/JRSyntaxTextArea.java
1
package org.gvsig.expressionfield.project.documents.table.gui.syntaxhighlight;
2

  
3
import java.awt.event.ActionEvent;
4
import java.awt.event.ActionListener;
5
import java.awt.event.KeyListener;
6

  
7
import javax.swing.JScrollPane;
8
import javax.swing.event.CaretEvent;
9
import javax.swing.event.CaretListener;
10
import javax.swing.text.JTextComponent;
11

  
12
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
13
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
14
import org.fife.ui.rtextarea.RTextScrollPane;
15

  
16

  
17
public class JRSyntaxTextArea implements SyntaxtHighlightTextComponent {
18

  
19
	public class DefaultUpdateCaretPositionActionEvent extends ActionEvent implements UpdateCaretPositionActionEvent {
20

  
21
		/**
22
		 * 
23
		 */
24
		private static final long serialVersionUID = 8238486105726094074L;
25
		int line = -1;
26
		int column = -1;
27
		
28
		public DefaultUpdateCaretPositionActionEvent(Object source, int id,
29
				String command, int line, int column) {
30
			super(source, id, command);
31
			this.line = line;
32
			this.column = column;
33
		}
34

  
35
		public int getLine() {
36
			return this.line+1;
37
		}
38

  
39
		public int getColumn() {
40
			return this.column;
41
		}
42

  
43
		public boolean hasLineAndColumn() {
44
			return this.line >=0 && this.column >= 0;
45
		}
46
		
47
	}
48
	
49
	protected ActionListener updateCaretPosition = null;
50
	protected RSyntaxTextArea textArea = null;
51
	
52
	public JRSyntaxTextArea() {
53
		this.textArea = new RSyntaxTextArea(20, 60);
54
		this.init();
55
	}
56
	
57
	protected void init() {
58
		textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_PYTHON);
59
		textArea.setCodeFoldingEnabled(true);
60
		textArea.setClearWhitespaceLinesEnabled(true);
61
		textArea.setAutoIndentEnabled(true);
62
		textArea.setCloseCurlyBraces(true);
63
		textArea.setWhitespaceVisible(true);
64
		textArea.setAnimateBracketMatching(true);
65
		textArea.setBracketMatchingEnabled(true);
66
		textArea.setAutoIndentEnabled(true);
67
		textArea.setTabsEmulated(true);
68
		textArea.setTabSize(2);
69
		textArea.setAntiAliasingEnabled(true);
70
		
71
		textArea.addCaretListener(new CaretListener() {
72
			public void caretUpdate(CaretEvent e) {
73
				if( updateCaretPosition== null ) {
74
					return;
75
				}
76
				updateCaretPosition.actionPerformed(
77
						new DefaultUpdateCaretPositionActionEvent(textArea, 1, "position", textArea.getCaretLineNumber(), textArea.getCaretOffsetFromLineStart() ) 
78
				);
79
			}
80
			
81
		});
82
	}
83
	
84
	public void setContentType(String contentType) {
85
		this.textArea.setSyntaxEditingStyle(contentType);
86
	}
87
	
88
	public JScrollPane getJScrollPane() {
89
		return  new RTextScrollPane(this.textArea);
90
	}
91

  
92
	public JTextComponent getJTextComponent() {
93
		return this.textArea;
94
	}
95

  
96
	public String getContentType() {
97
		return this.textArea.getSyntaxEditingStyle();
98
	}
99
	
100
	public void addUpdateCaretPositionActionListener(ActionListener updateCaretPosition) {
101
		this.updateCaretPosition = updateCaretPosition;  
102
	}
103

  
104
	public void setText(String text) {
105
		this.textArea.setText(text);
106
	}
107

  
108
	public String getText() {
109
		return this.textArea.getText();
110
	}
111
	
112
	public void addKeyListener(KeyListener keyListener) {
113
		this.textArea.addKeyListener(keyListener);
114
	}
115
}
org.gvsig.expressionfield/trunk/org.gvsig.expressionfield/src/main/java/org/gvsig/expressionfield/project/documents/table/gui/syntaxhighlight/styles/JavaStyledDocument.java
1
package org.gvsig.expressionfield.project.documents.table.gui.syntaxhighlight.styles;
2

  
3
import java.awt.Color;
4
import java.util.HashSet;
5
import java.util.Set;
6

  
7
import javax.swing.text.AttributeSet;
8
import javax.swing.text.BadLocationException;
9
import javax.swing.text.DefaultEditorKit;
10
import javax.swing.text.DefaultStyledDocument;
11
import javax.swing.text.Element;
12
import javax.swing.text.MutableAttributeSet;
13
import javax.swing.text.SimpleAttributeSet;
14
import javax.swing.text.StyleConstants;
15

  
16

  
17
public class JavaStyledDocument extends DefaultStyledDocument {
18
	/**
19
	 * 
20
	 */
21
	private static final long serialVersionUID = 2859530660266127826L;
22
	
23
	private final DefaultStyledDocument doc;
24
	private final Element rootElement;
25

  
26
	private boolean multiLineComment;
27
	private final MutableAttributeSet normal;
28
	private final MutableAttributeSet keyword;
29
	private final MutableAttributeSet comment;
30
	private final MutableAttributeSet quote;
31

  
32
    private final Set<String> keywords;
33

  
34
	public JavaStyledDocument()
35
	{
36
		doc = this;
37
		rootElement = doc.getDefaultRootElement();
38
		putProperty( DefaultEditorKit.EndOfLineStringProperty, "\n" );
39

  
40
		normal = new SimpleAttributeSet();
41
		StyleConstants.setForeground(normal, Color.black);
42

  
43
		comment = new SimpleAttributeSet();
44
		StyleConstants.setForeground(comment, Color.gray);
45
		StyleConstants.setItalic(comment, true);
46

  
47
		keyword = new SimpleAttributeSet();
48
		StyleConstants.setForeground(keyword, Color.blue);
49

  
50
		quote = new SimpleAttributeSet();
51
		StyleConstants.setForeground(quote, Color.red);
52

  
53
        keywords = new HashSet<String>();
54
		keywords.add( "abstract" );
55
		keywords.add( "boolean" );
56
		keywords.add( "break" );
57
		keywords.add( "byte" );
58
		keywords.add( "byvalue" );
59
		keywords.add( "case" );
60
		keywords.add( "cast" );
61
		keywords.add( "catch" );
62
		keywords.add( "char" );
63
		keywords.add( "class" );
64
		keywords.add( "const" );
65
		keywords.add( "continue" );
66
		keywords.add( "default" );
67
		keywords.add( "do" );
68
		keywords.add( "double" );
69
		keywords.add( "else" );
70
		keywords.add( "extends" );
71
		keywords.add( "false" );
72
		keywords.add( "final" );
73
		keywords.add( "finally" );
74
		keywords.add( "float" );
75
		keywords.add( "for" );
76
		keywords.add( "future" );
77
		keywords.add( "generic" );
78
		keywords.add( "goto" );
79
		keywords.add( "if" );
80
		keywords.add( "implements" );
81
		keywords.add( "import" );
82
		keywords.add( "inner" );
83
		keywords.add( "instanceof" );
84
		keywords.add( "int" );
85
		keywords.add( "interface" );
86
		keywords.add( "long" );
87
		keywords.add( "native" );
88
		keywords.add( "new" );
89
		keywords.add( "null" );
90
		keywords.add( "operator" );
91
		keywords.add( "outer" );
92
		keywords.add( "package" );
93
		keywords.add( "private" );
94
		keywords.add( "protected" );
95
		keywords.add( "public" );
96
		keywords.add( "rest" );
97
		keywords.add( "return" );
98
		keywords.add( "short" );
99
		keywords.add( "static" );
100
		keywords.add( "super" );
101
		keywords.add( "switch" );
102
		keywords.add( "synchronized" );
103
		keywords.add( "this" );
104
		keywords.add( "throw" );
105
		keywords.add( "throws" );
106
		keywords.add( "transient" );
107
		keywords.add( "true" );
108
		keywords.add( "try" );
109
		keywords.add( "var" );
110
		keywords.add( "void" );
111
		keywords.add( "volatile" );
112
		keywords.add( "while" );
113
	}
114

  
115
	/*
116
	 *  Override to apply syntax highlighting after the document has been updated
117
	 */
118
	@Override
119
    public void insertString(int offset, String str, AttributeSet a) throws BadLocationException
120
	{
121
		if (str.equals("{"))
122
			str = addMatchingBrace(offset);
123

  
124
		super.insertString(offset, str, a);
125
		processChangedLines(offset, str.length());
126
	}
127

  
128
	/*
129
	 *  Override to apply syntax highlighting after the document has been updated
130
	 */
131
	@Override
132
    public void remove(int offset, int length) throws BadLocationException
133
	{
134
		super.remove(offset, length);
135
		processChangedLines(offset, 0);
136
	}
137

  
138
	/*
139
	 *  Determine how many lines have been changed,
140
	 *  then apply highlighting to each line
141
	 */
142
	public void processChangedLines(int offset, int length)
143
		throws BadLocationException
144
	{
145
		String content = doc.getText(0, doc.getLength());
146

  
147
		//  The lines affected by the latest document update
148

  
149
		int startLine = rootElement.getElementIndex( offset );
150
		int endLine = rootElement.getElementIndex( offset + length );
151

  
152
		//  Make sure all comment lines prior to the start line are commented
153
		//  and determine if the start line is still in a multi line comment
154

  
155
		setMultiLineComment( commentLinesBefore( content, startLine ) );
156

  
157
		//  Do the actual highlighting
158

  
159
		for (int i = startLine; i <= endLine; i++)
160
		{
161
			applyHighlighting(content, i);
162
		}
163

  
164
		//  Resolve highlighting to the next end multi line delimiter
165

  
166
		if (isMultiLineComment())
167
			commentLinesAfter(content, endLine);
168
		else
169
			highlightLinesAfter(content, endLine);
170
	}
171

  
172
	/*
173
	 *  Highlight lines when a multi line comment is still 'open'
174
	 *  (ie. matching end delimiter has not yet been encountered)
175
	 */
176
	private boolean commentLinesBefore(String content, int line)
177
	{
178
		int offset = rootElement.getElement( line ).getStartOffset();
179

  
180
		//  Start of comment not found, nothing to do
181

  
182
		int startDelimiter = lastIndexOf( content, getStartDelimiter(), offset - 2 );
183

  
184
		if (startDelimiter < 0)
185
			return false;
186

  
187
		//  Matching start/end of comment found, nothing to do
188

  
189
		int endDelimiter = indexOf( content, getEndDelimiter(), startDelimiter );
190

  
191
		if (endDelimiter < offset & endDelimiter != -1)
192
			return false;
193

  
194
		//  End of comment not found, highlight the lines
195

  
196
		doc.setCharacterAttributes(startDelimiter, offset - startDelimiter + 1, comment, false);
197
		return true;
198
	}
199

  
200
	/*
201
	 *  Highlight comment lines to matching end delimiter
202
	 */
203
	private void commentLinesAfter(String content, int line)
204
	{
205
		int offset = rootElement.getElement( line ).getEndOffset();
206

  
207
		//  End of comment not found, nothing to do
208

  
209
		int endDelimiter = indexOf( content, getEndDelimiter(), offset );
210

  
211
		if (endDelimiter < 0)
212
			return;
213

  
214
		//  Matching start/end of comment found, comment the lines
215

  
216
		int startDelimiter = lastIndexOf( content, getStartDelimiter(), endDelimiter );
217

  
218
		if (startDelimiter < 0 || startDelimiter <= offset)
219
		{
220
			doc.setCharacterAttributes(offset, endDelimiter - offset + 1, comment, false);
221
		}
222
	}
223

  
224
	/*
225
	 *  Highlight lines to start or end delimiter
226
	 */
227
	private void highlightLinesAfter(String content, int line)
228
		throws BadLocationException
229
	{
230
		int offset = rootElement.getElement( line ).getEndOffset();
231

  
232
		//  Start/End delimiter not found, nothing to do
233

  
234
		int startDelimiter = indexOf( content, getStartDelimiter(), offset );
235
		int endDelimiter = indexOf( content, getEndDelimiter(), offset );
236

  
237
		if (startDelimiter < 0)
238
			startDelimiter = content.length();
239

  
240
		if (endDelimiter < 0)
241
			endDelimiter = content.length();
242

  
243
		int delimiter = Math.min(startDelimiter, endDelimiter);
244

  
245
		if (delimiter < offset)
246
			return;
247

  
248
		//	Start/End delimiter found, reapply highlighting
249

  
250
		int endLine = rootElement.getElementIndex( delimiter );
251

  
252
		for (int i = line + 1; i < endLine; i++)
253
		{
254
			Element branch = rootElement.getElement( i );
255
			Element leaf = doc.getCharacterElement( branch.getStartOffset() );
256
			AttributeSet as = leaf.getAttributes();
257

  
258
			if ( as.isEqual(comment) )
259
				applyHighlighting(content, i);
260
		}
261
	}
262

  
263
	/*
264
	 *  Parse the line to determine the appropriate highlighting
265
	 */
266
	private void applyHighlighting(String content, int line)
267
		throws BadLocationException
268
	{
269
		int startOffset = rootElement.getElement( line ).getStartOffset();
270
		int endOffset = rootElement.getElement( line ).getEndOffset() - 1;
271

  
272
		int lineLength = endOffset - startOffset;
273
		int contentLength = content.length();
274

  
275
		if (endOffset >= contentLength)
276
			endOffset = contentLength - 1;
277

  
278
		//  check for multi line comments
279
		//  (always set the comment attribute for the entire line)
280

  
281
		if (endingMultiLineComment(content, startOffset, endOffset)
282
		||  isMultiLineComment()
283
		||  startingMultiLineComment(content, startOffset, endOffset) )
284
		{
285
			doc.setCharacterAttributes(startOffset, endOffset - startOffset + 1, comment, false);
286
			return;
287
		}
288

  
289
		//  set normal attributes for the line
290

  
291
		doc.setCharacterAttributes(startOffset, lineLength, normal, true);
292

  
293
		//  check for single line comment
294

  
295
		int index = content.indexOf(getSingleLineDelimiter(), startOffset);
296

  
297
		if ( (index > -1) && (index < endOffset) )
298
		{
299
			doc.setCharacterAttributes(index, endOffset - index + 1, comment, false);
300
			endOffset = index - 1;
301
		}
302

  
303
		//  check for tokens
304

  
305
		checkForTokens(content, startOffset, endOffset);
306
	}
307

  
308
	/*
309
	 *  Does this line contain the start delimiter
310
	 */
311
	private boolean startingMultiLineComment(String content, int startOffset, int endOffset)
312
		throws BadLocationException
313
	{
314
		int index = indexOf( content, getStartDelimiter(), startOffset );
315

  
316
		if ( (index < 0) || (index > endOffset) )
317
			return false;
318
		else
319
		{
320
			setMultiLineComment( true );
321
			return true;
322
		}
323
	}
324

  
325
	/*
326
	 *  Does this line contain the end delimiter
327
	 */
328
	private boolean endingMultiLineComment(String content, int startOffset, int endOffset)
329
		throws BadLocationException
330
	{
331
		int index = indexOf( content, getEndDelimiter(), startOffset );
332

  
333
		if ( (index < 0) || (index > endOffset) )
334
			return false;
335
		else
336
		{
337
			setMultiLineComment( false );
338
			return true;
339
		}
340
	}
341

  
342
	/*
343
	 *  We have found a start delimiter
344
	 *  and are still searching for the end delimiter
345
	 */
346
	private boolean isMultiLineComment()
347
	{
348
		return multiLineComment;
349
	}
350

  
351
	private void setMultiLineComment(boolean value)
352
	{
353
		multiLineComment = value;
354
	}
355

  
356
	/*
357
	 *	Parse the line for tokens to highlight
358
	 */
359
	private void checkForTokens(String content, int startOffset, int endOffset)
360
	{
361
		while (startOffset <= endOffset)
362
		{
363
			//  skip the delimiters to find the start of a new token
364

  
365
			while ( isDelimiter( content.substring(startOffset, startOffset + 1) ) )
366
			{
367
				if (startOffset < endOffset)
368
					startOffset++;
369
				else
370
					return;
371
			}
372

  
373
			//  Extract and process the entire token
374

  
375
			if ( isQuoteDelimiter( content.substring(startOffset, startOffset + 1) ) )
376
				startOffset = getQuoteToken(content, startOffset, endOffset);
377
			else
378
				startOffset = getOtherToken(content, startOffset, endOffset);
379
		}
380
	}
381

  
382
	/*
383
	 *
384
	 */
385
	private int getQuoteToken(String content, int startOffset, int endOffset)
386
	{
387
		String quoteDelimiter = content.substring(startOffset, startOffset + 1);
388
		String escapeString = getEscapeString(quoteDelimiter);
389

  
390
		int index;
391
		int endOfQuote = startOffset;
392

  
393
		//  skip over the escape quotes in this quote
394

  
395
		index = content.indexOf(escapeString, endOfQuote + 1);
396

  
397
		while ( (index > -1) && (index < endOffset) )
398
		{
399
			endOfQuote = index + 1;
400
			index = content.indexOf(escapeString, endOfQuote);
401
		}
402

  
403
		// now find the matching delimiter
404

  
405
		index = content.indexOf(quoteDelimiter, endOfQuote + 1);
406

  
407
		if ( (index < 0) || (index > endOffset) )
408
			endOfQuote = endOffset;
409
		else
410
			endOfQuote = index;
411

  
412
		doc.setCharacterAttributes(startOffset, endOfQuote - startOffset + 1, quote, false);
413

  
414
		return endOfQuote + 1;
415
	}
416

  
417
	/*
418
	 *
419
	 */
420
	private int getOtherToken(String content, int startOffset, int endOffset)
421
	{
422
		int endOfToken = startOffset + 1;
423

  
424
		while ( endOfToken <= endOffset )
425
		{
426
			if ( isDelimiter( content.substring(endOfToken, endOfToken + 1) ) )
427
				break;
428

  
429
			endOfToken++;
430
		}
431

  
432
		String token = content.substring(startOffset, endOfToken);
433

  
434
		if ( isKeyword( token ) )
435
		{
436
			doc.setCharacterAttributes(startOffset, endOfToken - startOffset, keyword, false);
437
		}
438

  
439
		return endOfToken + 1;
440
	}
441

  
442
	/*
443
	 *  Assume the needle will the found at the start/end of the line
444
	 */
445
	private int indexOf(String content, String needle, int offset)
446
	{
447
		int index;
448

  
449
		while ( (index = content.indexOf(needle, offset)) != -1 )
450
		{
451
			String text = getLine( content, index ).trim();
452

  
453
			if (text.startsWith(needle) || text.endsWith(needle))
454
				break;
455
			else
456
				offset = index + 1;
457
		}
458

  
459
		return index;
460
	}
461

  
462
	/*
463
	 *  Assume the needle will the found at the start/end of the line
464
	 */
465
	private int lastIndexOf(String content, String needle, int offset)
466
	{
467
		int index;
468

  
469
		while ( (index = content.lastIndexOf(needle, offset)) != -1 )
470
		{
471
			String text = getLine( content, index ).trim();
472

  
473
			if (text.startsWith(needle) || text.endsWith(needle))
474
				break;
475
			else
476
				offset = index - 1;
477
		}
478

  
479
		return index;
480
	}
481

  
482
	private String getLine(String content, int offset)
483
	{
484
		int line = rootElement.getElementIndex( offset );
485
		Element lineElement = rootElement.getElement( line );
486
		int start = lineElement.getStartOffset();
487
		int end = lineElement.getEndOffset();
488
		return content.substring(start, end - 1);
489
	}
490

  
491
	/*
492
	 *  Override for other languages
493
	 */
494
	protected boolean isDelimiter(String character)
495
	{
496
		String operands = ";:{}()[]+-/%<=>!&|^~*";
497

  
498
		if (Character.isWhitespace( character.charAt(0) ) ||
499
			operands.indexOf(character) != -1 )
500
			return true;
501
		else
502
			return false;
503
	}
504

  
505
	/*
506
	 *  Override for other languages
507
	 */
508
	protected boolean isQuoteDelimiter(String character)
509
	{
510
		String quoteDelimiters = "\"'";
511

  
512
		if (quoteDelimiters.indexOf(character) < 0)
513
			return false;
514
		else
515
			return true;
516
	}
517

  
518
	/*
519
	 *  Override for other languages
520
	 */
521
	protected boolean isKeyword(String token)
522
	{
523
		return keywords.contains( token );
524
	}
525

  
526
	/*
527
	 *  Override for other languages
528
	 */
529
	protected String getStartDelimiter()
530
	{
531
		return "/*";
532
	}
533

  
534
	/*
535
	 *  Override for other languages
536
	 */
537
	protected String getEndDelimiter()
538
	{
539
		return "*/";
540
	}
541

  
542
	/*
543
	 *  Override for other languages
544
	 */
545
	protected String getSingleLineDelimiter()
546
	{
547
		return "//";
548
	}
549

  
550
	/*
551
	 *  Override for other languages
552
	 */
553
	protected String getEscapeString(String quoteDelimiter)
554
	{
555
		return "\\" + quoteDelimiter;
556
	}
557

  
558
	/*
559
	 *
560
	 */
561
	protected String addMatchingBrace(int offset) throws BadLocationException
562
	{
563
		StringBuffer whiteSpace = new StringBuffer();
564
		int line = rootElement.getElementIndex( offset );
565
		int i = rootElement.getElement(line).getStartOffset();
566

  
567
		while (true)
568
		{
569
			String temp = doc.getText(i, 1);
570

  
571
			if (temp.equals(" ") || temp.equals("\t"))
572
			{
573
				whiteSpace.append(temp);
574
				i++;
575
			}
576
			else
577
				break;
578
		}
579

  
580
		return "{\n" + whiteSpace.toString() + "\t\n" + whiteSpace.toString() + "}";
581
	}
582

  
583
}
584

  
org.gvsig.expressionfield/trunk/org.gvsig.expressionfield/src/main/java/org/gvsig/expressionfield/project/documents/table/gui/syntaxhighlight/styles/PythonStyledDocument.java
1
package org.gvsig.expressionfield.project.documents.table.gui.syntaxhighlight.styles;
2

  
3
import java.awt.Color;
4
import java.util.HashSet;
5
import java.util.Set;
6

  
7
import javax.swing.text.AttributeSet;
8
import javax.swing.text.BadLocationException;
9
import javax.swing.text.DefaultEditorKit;
10
import javax.swing.text.DefaultStyledDocument;
11
import javax.swing.text.Element;
12
import javax.swing.text.MutableAttributeSet;
13
import javax.swing.text.SimpleAttributeSet;
14
import javax.swing.text.StyleConstants;
15

  
16
public class PythonStyledDocument extends DefaultStyledDocument {
17
    /**
18
     * 
19
     */
20
    private static final long serialVersionUID = 2859530660266127826L;
21

  
22
    private static int TABSIZE = 4;
23
    
24
    private final DefaultStyledDocument doc;
25
    private final Element rootElement;
26

  
27
    private boolean multiLineComment;
28
    private final MutableAttributeSet normal;
29
    private final MutableAttributeSet keyword1;
30
    private final MutableAttributeSet keyword2;
31
    private final MutableAttributeSet keyword3;
32
    private final MutableAttributeSet keyword4;
33
    private final MutableAttributeSet builtin;
34
    private final MutableAttributeSet comment;
35
    private final MutableAttributeSet quote;
36
    private final MutableAttributeSet identifiers;
37
    
38
    private final Set<String> keywords1;
39
    private final Set<String> keywords2;
40
    private final Set<String> keywords3;
41
    private final Set<String> keywords4;
42
    private final Set<String> builtins;
43

  
44
//    private int lineNumber;
45

  
46
    private int columnNumber;
47

  
48
    public PythonStyledDocument() {
49
        doc = this;
50
        rootElement = doc.getDefaultRootElement();
51
        putProperty(DefaultEditorKit.EndOfLineStringProperty, "\n");
52
        
53
        int fontSize = 14;
54

  
55
        normal = new SimpleAttributeSet();
56
        StyleConstants.setForeground(normal, Color.BLACK);
57
        StyleConstants.setFontFamily(normal, "monospaced");
58
        StyleConstants.setBold(normal, true);
59
        StyleConstants.setFontSize(normal, fontSize);
60

  
61
        comment = new SimpleAttributeSet();
62
        StyleConstants.setForeground(comment,Color.GRAY);
63
        StyleConstants.setItalic(comment, true);
64
        StyleConstants.setBold(comment, true);
65
        StyleConstants.setFontFamily(comment, "monospaced");
66
        StyleConstants.setFontSize(comment, fontSize);
67

  
68

  
69
        keyword1 = new SimpleAttributeSet();
70
        StyleConstants.setForeground(keyword1, Color.BLACK);
71
        StyleConstants.setFontFamily(keyword1, "monospaced");
72
        StyleConstants.setBold(keyword1, true);
73
        StyleConstants.setFontSize(keyword1, fontSize);
74

  
75
        keyword2 = new SimpleAttributeSet();
76
        StyleConstants.setForeground(keyword2, Color.CYAN);
77
        StyleConstants.setFontFamily(keyword2, "monospaced");
78
        StyleConstants.setBold(keyword2, false);
79
        StyleConstants.setFontSize(keyword2, fontSize);
80

  
81
        keyword3 = new SimpleAttributeSet();
82
        StyleConstants.setForeground(keyword3, Color.GREEN.darker());
83
        StyleConstants.setFontFamily(keyword3, "monospaced");
84
        StyleConstants.setBold(keyword3, false);
85
        StyleConstants.setFontSize(keyword3, fontSize);
86

  
87
        keyword4 = new SimpleAttributeSet();
88
        StyleConstants.setForeground(keyword4, Color.BLUE.darker());
89
        StyleConstants.setFontFamily(keyword4, "monospaced");
90
        StyleConstants.setBold(keyword4, true);
91
        StyleConstants.setFontSize(keyword4, fontSize);
92

  
93
        builtin = new SimpleAttributeSet();
94
        StyleConstants.setForeground(builtin, Color.RED.darker());
95
        StyleConstants.setFontFamily(builtin, "monospaced");
96
        StyleConstants.setBold(builtin, false);
97
        StyleConstants.setFontSize(builtin, fontSize);
98

  
99
        identifiers = new SimpleAttributeSet();
100
        StyleConstants.setForeground(identifiers, Color.BLACK);
101
        StyleConstants.setFontFamily(identifiers, "monospaced");
102
        StyleConstants.setBold(identifiers, false);
103
        StyleConstants.setFontSize(identifiers, fontSize);
104

  
105
        
106
        quote = new SimpleAttributeSet();
107
        StyleConstants.setForeground(quote,  Color.RED.darker());
108
        StyleConstants.setFontFamily(quote, "monospaced");
109
        StyleConstants.setBold(quote, true);
110
        StyleConstants.setFontSize(quote, fontSize);
111
        
112
        keywords1 = new HashSet<String>();
113
        keywords1.add("except");
114
        keywords1.add("class");
115
        keywords1.add("continue");
116
        keywords1.add("else");
117
        keywords1.add("finally");
118
        keywords1.add("if");
119
        keywords1.add("elif");
120
        keywords1.add("in");
121
        keywords1.add("return");
122
        keywords1.add("raise");
123
        keywords1.add("try");
124
        keywords1.add("while");
125
        keywords1.add("def");
126
        keywords1.add("print");
127
        keywords1.add("globals");
128
        keywords1.add("for");
129
        keywords1.add("pass");
130

  
131
        keywords2 = new HashSet<String>();
132
        keywords2.add("from");
133
        keywords2.add("import");
134

  
135
        keywords3 = new HashSet<String>();
136
        keywords3.add("True");
137
        keywords3.add("False");
138
        keywords3.add("None");
139
        keywords3.add("self");
140

  
141
        keywords4 = new HashSet<String>();
142
        keywords4.add("__init__");
143
        keywords4.add("__len__");
144
        keywords4.add("__str__");
145
        keywords4.add("__repr__");
146
        keywords4.add("__call__");
147
        keywords4.add("__iter__");
148
        keywords4.add("__class__");
149

  
150
        keywords4.add("__getattr__");
151
        keywords4.add("__setattr__");
152
        keywords4.add("__delattr__");
153

  
154
        keywords4.add("__getitem__");
155
        keywords4.add("__setitem__");
156
        keywords4.add("__delitem__");
157

  
158
        keywords4.add("__getslice__");
159
        keywords4.add("__setslice__");
160
        keywords4.add("__delslice__");
161

  
162
        keywords4.add("__getattribute__");
163
        keywords4.add("__setattribute__");
164

  
165
        keywords4.add("__contains__");
166
        keywords4.add("__reduce__");
167
        keywords4.add("__cmp__");
168
        keywords4.add("__eq__");
169
        keywords4.add("__ne__");
170
        keywords4.add("__lt__");
171
        keywords4.add("__le__");
172
        keywords4.add("__gt__");
173
        keywords4.add("__ge__");
174
        keywords4.add("__mul__");
175
        keywords4.add("__imul__");
176
        keywords4.add("__rmul__");
177
        keywords4.add("__add__");
178
        keywords4.add("__iadd__");
179
        keywords4.add("__radd__");
180
        keywords4.add("__mod__");
181
        keywords4.add("__rmod__");
182

  
183
        builtins = new HashSet<String>();
184
        builtins.add("int");
185
        builtins.add("unicode");
186
        builtins.add("str");
187
        builtins.add("float");
188
        builtins.add("long");
189
        builtins.add("list");
190
        builtins.add("tuple");
191
        builtins.add("dict");
192
        builtins.add("iter");
193
        builtins.add("vars");
194
        builtins.add("isinstance");
195
        builtins.add("dir");
196
        builtins.add("repr");
197
        builtins.add("reduce");
198
        builtins.add("zip");
199
        builtins.add("chr");
200
        builtins.add("hex");
201
        builtins.add("id");
202
        builtins.add("max");
203
        builtins.add("min");
204
        builtins.add("oct");
205
        builtins.add("pow");
206
        builtins.add("ord");
207
        builtins.add("unichr");
208
        builtins.add("range");
209
        builtins.add("xrange");
210
        builtins.add("abs");
211
        builtins.add("len");
212
        builtins.add("apply");
213
        builtins.add("open");
214
        builtins.add("getattr");
215
        builtins.add("setattr");
216
        builtins.add("hasattr");
217

  
218
    }
219

  
220
    /*
221
     * Override to apply syntax highlighting after the document has been updated
222
     */
223
    @Override
224
    public void insertString(int offset, String str, AttributeSet a)
225
            throws BadLocationException {
226
        super.insertString(offset, processTab(offset, str, a), a);
227
        processChangedLines(offset, str.length());
228
    }
229

  
230
    public void setPosition(int lineNumber, int columnNumber) {
231
//        this.lineNumber= lineNumber;
232
        this.columnNumber= columnNumber; 
233
    }
234

  
235
    private String processTab(int offset, String str, AttributeSet a ) {
236
        if( !"\t".equals(str)) {
237
            return str;
238
        }
239
        try {
240
            int numberOfSpacesToInsert = (TABSIZE -((this.columnNumber -1)%TABSIZE));
241
            
242
            str = "                                                   ".substring(0, numberOfSpacesToInsert);
243
        } catch (Exception e) {
244
            return  "                    ".substring(0, TABSIZE);
245
        }
246
        return str; 
247
    }
248
    
249
    /*
250
     * Override to apply syntax highlighting after the document has been updated
251
     */
252
    @Override
253
    public void remove(int offset, int length) throws BadLocationException {
254
        super.remove(offset, length);
255
        processChangedLines(offset, 0);
256
    }
257

  
258
    /*
259
     * Determine how many lines have been changed, then apply highlighting to
260
     * each line
261
     */
262
    public void processChangedLines(int offset, int length)
263
            throws BadLocationException {
264
        String content = doc.getText(0, doc.getLength());
265

  
266
        // The lines affected by the latest document update
267

  
268
        int startLine = rootElement.getElementIndex(offset);
269
        int endLine = rootElement.getElementIndex(offset + length);
270

  
271
        // Make sure all comment lines prior to the start line are commented
272
        // and determine if the start line is still in a multi line comment
273

  
274
        setMultiLineComment(commentLinesBefore(content, startLine));
275

  
276
        // Do the actual highlighting
277

  
278
        for (int i = startLine; i <= endLine; i++) {
279
            applyHighlighting(content, i);
280
        }
281

  
282
        // Resolve highlighting to the next end multi line delimiter
283

  
284
        if (isMultiLineComment())
285
            commentLinesAfter(content, endLine);
286
        else
287
            highlightLinesAfter(content, endLine);
288
    }
289

  
290
    /*
291
     * Highlight lines when a multi line comment is still 'open' (ie. matching
292
     * end delimiter has not yet been encountered)
293
     */
294
    private boolean commentLinesBefore(String content, int line) {
295
        int offset = rootElement.getElement(line).getStartOffset();
296

  
297
        // Start of comment not found, nothing to do
298

  
299
        int startDelimiter = lastIndexOf(content, getStartDelimiter(),
300
                offset - 2);
301

  
302
        if (startDelimiter < 0)
303
            return false;
304

  
305
        // Matching start/end of comment found, nothing to do
306

  
307
        int endDelimiter = indexOf(content, getEndDelimiter(), startDelimiter);
308

  
309
        if (endDelimiter < offset & endDelimiter != -1)
310
            return false;
311

  
312
        // End of comment not found, highlight the lines
313

  
314
        doc.setCharacterAttributes(startDelimiter, offset - startDelimiter + 1,
315
                comment, false);
316
        return true;
317
    }
318

  
319
    /*
320
     * Highlight comment lines to matching end delimiter
321
     */
322
    private void commentLinesAfter(String content, int line) {
323
        int offset = rootElement.getElement(line).getEndOffset();
324

  
325
        // End of comment not found, nothing to do
326

  
327
        int endDelimiter = indexOf(content, getEndDelimiter(), offset);
328

  
329
        if (endDelimiter < 0)
330
            return;
331

  
332
        // Matching start/end of comment found, comment the lines
333

  
334
        int startDelimiter = lastIndexOf(content, getStartDelimiter(),
335
                endDelimiter);
336

  
337
        if (startDelimiter < 0 || startDelimiter <= offset) {
338
            doc.setCharacterAttributes(offset, endDelimiter - offset + 1,
339
                    comment, false);
340
        }
341
    }
342

  
343
    /*
344
     * Highlight lines to start or end delimiter
345
     */
346
    private void highlightLinesAfter(String content, int line)
347
            throws BadLocationException {
348
        int offset = rootElement.getElement(line).getEndOffset();
349

  
350
        // Start/End delimiter not found, nothing to do
351

  
352
        int startDelimiter = indexOf(content, getStartDelimiter(), offset);
353
        int endDelimiter = indexOf(content, getEndDelimiter(), offset);
354

  
355
        if (startDelimiter < 0)
356
            startDelimiter = content.length();
357

  
358
        if (endDelimiter < 0)
359
            endDelimiter = content.length();
360

  
361
        int delimiter = Math.min(startDelimiter, endDelimiter);
362

  
363
        if (delimiter < offset)
364
            return;
365

  
366
        // Start/End delimiter found, reapply highlighting
367

  
368
        int endLine = rootElement.getElementIndex(delimiter);
369

  
370
        for (int i = line + 1; i < endLine; i++) {
371
            Element branch = rootElement.getElement(i);
372
            Element leaf = doc.getCharacterElement(branch.getStartOffset());
373
            AttributeSet as = leaf.getAttributes();
374

  
375
            if (as.isEqual(comment))
376
                applyHighlighting(content, i);
377
        }
378
    }
379

  
380
    /*
381
     * Parse the line to determine the appropriate highlighting
382
     */
383
    private void applyHighlighting(String content, int line)
384
            throws BadLocationException {
385
        int startOffset = rootElement.getElement(line).getStartOffset();
386
        int endOffset = rootElement.getElement(line).getEndOffset() - 1;
387

  
388
        int lineLength = endOffset - startOffset;
389
        int contentLength = content.length();
390

  
391
        if (endOffset >= contentLength)
392
            endOffset = contentLength - 1;
393

  
394
        // check for multi line comments
395
        // (always set the comment attribute for the entire line)
396

  
397
        if (endingMultiLineComment(content, startOffset, endOffset)
398
                || isMultiLineComment()
399
                || startingMultiLineComment(content, startOffset, endOffset)) {
400
            doc.setCharacterAttributes(startOffset,
401
                    endOffset - startOffset + 1, comment, false);
402
            return;
403
        }
404

  
405
        // set normal attributes for the line
406

  
407
        doc.setCharacterAttributes(startOffset, lineLength, normal, true);
408

  
409
        // check for single line comment
410

  
411
        int index = content.indexOf(getSingleLineDelimiter(), startOffset);
412

  
413
        if ((index > -1) && (index < endOffset)) {
414
            doc.setCharacterAttributes(index, endOffset - index + 1, comment,
415
                    false);
416
            endOffset = index - 1;
417
        }
418

  
419
        // check for tokens
420

  
421
        checkForTokens(content, startOffset, endOffset);
422
    }
423

  
424
    /*
425
     * Does this line contain the start delimiter
426
     */
427
    private boolean startingMultiLineComment(String content, int startOffset,
428
            int endOffset) throws BadLocationException {
429
        int index = indexOf(content, getStartDelimiter(), startOffset);
430

  
431
        if ((index < 0) || (index > endOffset))
432
            return false;
433
        else {
434
            setMultiLineComment(true);
435
            return true;
436
        }
437
    }
438

  
439
    /*
440
     * Does this line contain the end delimiter
441
     */
442
    private boolean endingMultiLineComment(String content, int startOffset,
443
            int endOffset) throws BadLocationException {
444
        int index = indexOf(content, getEndDelimiter(), startOffset);
445

  
446
        if ((index < 0) || (index > endOffset))
447
            return false;
448
        else {
449
            setMultiLineComment(false);
450
            return true;
451
        }
452
    }
453

  
454
    /*
455
     * We have found a start delimiter and are still searching for the end
456
     * delimiter
457
     */
458
    private boolean isMultiLineComment() {
459
        return multiLineComment;
460
    }
461

  
462
    private void setMultiLineComment(boolean value) {
463
        multiLineComment = value;
464
    }
465

  
466
    /*
467
     * Parse the line for tokens to highlight
468
     */
469
    private void checkForTokens(String content, int startOffset, int endOffset) {
470
        while (startOffset <= endOffset) {
471
            // skip the delimiters to find the start of a new token
472

  
473
            while (isDelimiter(content.substring(startOffset, startOffset + 1))) {
474
                if (startOffset < endOffset)
475
                    startOffset++;
476
                else
477
                    return;
478
            }
479

  
480
            // Extract and process the entire token
481

  
482
            if (isQuoteDelimiter(content
483
                    .substring(startOffset, startOffset + 1)))
484
                startOffset = getQuoteToken(content, startOffset, endOffset);
485
            else
486
                startOffset = getOtherToken(content, startOffset, endOffset);
487
        }
488
    }
489

  
490
    /*
491
     *
492
     */
493
    private int getQuoteToken(String content, int startOffset, int endOffset) {
494
        String quoteDelimiter = content.substring(startOffset, startOffset + 1);
495
        String escapeString = getEscapeString(quoteDelimiter);
496

  
497
        int index;
498
        int endOfQuote = startOffset;
499

  
500
        // skip over the escape quotes in this quote
501

  
502
        index = content.indexOf(escapeString, endOfQuote + 1);
503

  
504
        while ((index > -1) && (index < endOffset)) {
505
            endOfQuote = index + 1;
506
            index = content.indexOf(escapeString, endOfQuote);
507
        }
508

  
509
        // now find the matching delimiter
510

  
511
        index = content.indexOf(quoteDelimiter, endOfQuote + 1);
512

  
513
        if ((index < 0) || (index > endOffset))
514
            endOfQuote = endOffset;
515
        else
516
            endOfQuote = index;
517

  
518
        doc.setCharacterAttributes(startOffset, endOfQuote - startOffset + 1,
519
                quote, false);
520

  
521
        return endOfQuote + 1;
522
    }
523

  
524
    /*
525
     *
526
     */
527
    private int getOtherToken(String content, int startOffset, int endOffset) {
528
        int endOfToken = startOffset + 1;
529

  
530
        while (endOfToken <= endOffset) {
531
            if (isDelimiter(content.substring(endOfToken, endOfToken + 1)))
532
                break;
533

  
534
            endOfToken++;
535
        }
536

  
537
        String token = content.substring(startOffset, endOfToken);
538

  
539
        if (isKeyword(token)) {
540
            doc.setCharacterAttributes(startOffset, endOfToken - startOffset,
541
                    keyword1, false);
542

  
543
        } else if ( keywords2.contains(token) ) {
544
            doc.setCharacterAttributes(startOffset, endOfToken - startOffset,
545
                    keyword2, false);
546

  
547
        } else if ( keywords3.contains(token) ) {
548
            doc.setCharacterAttributes(startOffset, endOfToken - startOffset,
549
                    keyword3, false);
550

  
551
        } else if ( keywords4.contains(token) ) {
552
            doc.setCharacterAttributes(startOffset, endOfToken - startOffset,
553
                    keyword4, false);
554

  
555
        } else if (isBuiltin(token)) {
556
            doc.setCharacterAttributes(startOffset, endOfToken - startOffset,
557
                builtin, false);
558
        } else if (isIdentifier(token)) {
559
            doc.setCharacterAttributes(startOffset, endOfToken - startOffset,
560
                identifiers, false);
561
        }
562
                
563

  
564
        return endOfToken + 1;
565
    }
566

  
567
    private boolean isIdentifier(String token) {
568
        return token.matches("[A-Za-z_][A-Za-z0-9_]*");
569
    }
570

  
571
    /*
572
     * Assume the needle will the found at the start/end of the line
573
     */
574
    private int indexOf(String content, String needle, int offset) {
575
        int index;
576

  
577
        while ((index = content.indexOf(needle, offset)) != -1) {
578
            String text = getLine(content, index).trim();
579

  
580
            if (text.startsWith(needle) || text.endsWith(needle))
581
                break;
582
            else
583
                offset = index + 1;
584
        }
585

  
586
        return index;
587
    }
588

  
589
    /*
590
     * Assume the needle will the found at the start/end of the line
591
     */
592
    private int lastIndexOf(String content, String needle, int offset) {
593
        int index;
594

  
595
        while ((index = content.lastIndexOf(needle, offset)) != -1) {
596
            String text = getLine(content, index).trim();
597

  
598
            if (text.startsWith(needle) || text.endsWith(needle))
599
                break;
600
            else
601
                offset = index - 1;
602
        }
603

  
604
        return index;
605
    }
606

  
607
    private String getLine(String content, int offset) {
608
        int line = rootElement.getElementIndex(offset);
609
        Element lineElement = rootElement.getElement(line);
610
        int start = lineElement.getStartOffset();
611
        int end = lineElement.getEndOffset();
612
        return content.substring(start, end - 1);
613
    }
614

  
615
    /*
616
     * Override for other languages
617
     */
618
    protected boolean isDelimiter(String character) {
619
        String operands = ";:()[]+-/%<=>!&|^~*.,";
620

  
621
        if (Character.isWhitespace(character.charAt(0))
622
                || operands.indexOf(character) != -1)
623
            return true;
624
        else
625
            return false;
626
    }
627

  
628
    /*
629
     * Override for other languages
630
     */
631
    protected boolean isQuoteDelimiter(String character) {
632
        String quoteDelimiters = "\"'";
633

  
634
        if (quoteDelimiters.indexOf(character) < 0)
635
            return false;
636
        else
637
            return true;
638
    }
639

  
640
    /*
641
     * Override for other languages
642
     */
643
    protected boolean isKeyword(String token) {
644
        return keywords1.contains(token);
645
    }
646

  
647
    protected boolean isBuiltin(String token) {
648
        return builtins.contains(token);
649
    }
650

  
651
    /*
652
     * Override for other languages
653
     */
654
    protected String getStartDelimiter() {
655
        return "\"\"\"";
656
    }
657

  
658
    /*
659
     * Override for other languages
660
     */
661
    protected String getEndDelimiter() {
662
        return "\"\"\"";
663
    }
664

  
665
    /*
666
     * Override for other languages
667
     */
668
    protected String getSingleLineDelimiter() {
669
        return "#";
670
    }
671

  
672
    /*
673
     * Override for other languages
674
     */
675
    protected String getEscapeString(String quoteDelimiter) {
676
        return "\\" + quoteDelimiter;
677
    }
678

  
679
    /*
680
     *
681
    protected String addMatchingBrace(int offset) throws BadLocationException {
682
        StringBuffer whiteSpace = new StringBuffer();
683
        int line = rootElement.getElementIndex(offset);
684
        int i = rootElement.getElement(line).getStartOffset();
685

  
686
        while (true) {
687
            String temp = doc.getText(i, 1);
688

  
689
            if (temp.equals(" ") || temp.equals("\t")) {
690
                whiteSpace.append(temp);
691
                i++;
692
            } else
693
                break;
694
        }
695

  
696
        return "{\n" + whiteSpace.toString() + "\t\n" + whiteSpace.toString()
697
                + "}";
698
    }
699
     */
700

  
701
}
702

  
703

  
org.gvsig.expressionfield/trunk/org.gvsig.expressionfield/src/main/java/org/gvsig/expressionfield/project/documents/table/gui/AdvancedPanelLayout.java
1
/*
2
 * To change this license header, choose License Headers in Project Properties.
3
 * To change this template file, choose Tools | Templates
4
 * and open the template in the editor.
5
 */
6
package org.gvsig.expressionfield.project.documents.table.gui;
7

  
8
/**
9
 *
10
 * @author jjdelcerro
11
 */
12
public class AdvancedPanelLayout extends javax.swing.JPanel {
13

  
14
    /**
15
     * Creates new form AdvancedPanel
16
     */
17
    public AdvancedPanelLayout() {
18
        initComponents();
19
    }
20

  
21
    /**
22
     * This method is called from within the constructor to initialize the form.
23
     * WARNING: Do NOT modify this code. The content of this method is always
24
     * regenerated by the Form Editor.
25
     */
26
    @SuppressWarnings("unchecked")
27
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
28
    private void initComponents() {
29
        java.awt.GridBagConstraints gridBagConstraints;
30

  
31
        filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(4, 4), new java.awt.Dimension(4, 4), new java.awt.Dimension(4, 4));
32
        butLoad = new javax.swing.JButton();
33
        butSave = new javax.swing.JButton();
34
        butTest = new javax.swing.JButton();
35
        filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
36
        filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(4, 4), new java.awt.Dimension(4, 4), new java.awt.Dimension(4, 4));
37
        editorContainer = new javax.swing.JPanel();
38

  
39
        java.awt.GridBagLayout layout = new java.awt.GridBagLayout();
40
        layout.columnWidths = new int[] {0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0};
41
        layout.rowHeights = new int[] {0, 5, 0, 5, 0, 5, 0};
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff