View Javadoc
1   /*
2    * This file is part of the programmer editor demo
3    * Copyright (C) 2001-2005 Stephen Ostermiller
4    * http://ostermiller.org/contact.pl?regarding=Syntax+Highlighting
5    * 
6    * This program is free software; you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation; either version 2 of the License, or
9    * (at your option) any later version.
10   * 
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   * 
16   * See COPYING.TXT for details.
17   */
18  package com.jsql.view.swing.sql.lexer;
19  
20  import com.jsql.util.LogLevelUtil;
21  import com.jsql.view.swing.sql.lexer.syntax.JavaScriptLexer;
22  import com.jsql.view.swing.sql.lexer.syntax.Lexer;
23  import com.jsql.view.swing.sql.lexer.syntax.SQLLexer;
24  import org.apache.logging.log4j.LogManager;
25  import org.apache.logging.log4j.Logger;
26  
27  import javax.swing.text.AttributeSet;
28  import javax.swing.text.BadLocationException;
29  import javax.swing.text.DefaultStyledDocument;
30  import java.io.Reader;
31  import java.lang.reflect.Constructor;
32  import java.lang.reflect.InvocationTargetException;
33  
34  /**
35   * A <a href="http://ostermiller.org/syntax/editor.html">demonstration text
36   * editor</a> that uses syntax highlighting.
37   */
38  public class HighlightedDocument extends DefaultStyledDocument {
39      
40      /**
41       * Log4j logger sent to view.
42       */
43      private static final Logger LOGGER = LogManager.getRootLogger();
44      
45      public static final Object SQL_STYLE = SQLLexer.class;
46      public static final Object JAVASCRIPT_STYLE = JavaScriptLexer.class;
47      
48      public static final Object GRAYED_OUT_STYLE = new Object();
49  
50      /**
51       * A reader wrapped around the document so that the document can be fed into
52       * the lexer.
53       */
54      private final transient DocumentReader documentReader;
55      
56      /** If non-null, all is drawn with this style (no lexing). */
57      private transient AttributeSet globalStyle = null;
58  
59      /**
60       * The lexer that tells us what colors different words should be.
61       */
62      private transient Lexer syntaxLexer;
63  
64      /**
65       * A thread that handles the actual coloring.
66       */
67      private final transient Colorer colorer;
68  
69      /**
70       * A lock for modifying the document, or for actions that depend on the
71       * document not being modified.
72       */
73      private final transient Object docLock = new Object();
74  
75      /**
76       * Create a new Demo
77       */
78      public HighlightedDocument(Object l) {
79  
80          // Start the thread that does the coloring
81          this.colorer = new Colorer(this);
82          this.colorer.start();
83  
84          // create the new document.
85          this.documentReader = new DocumentReader(this);
86          
87          if (l == SQL_STYLE) {
88              this.syntaxLexer = new SQLLexer(this.documentReader);
89          } else {
90              this.syntaxLexer = new JavaScriptLexer(this.documentReader);
91          }
92      }
93  
94      /**
95       * Color or recolor the entire document
96       */
97      public void colorAll() {
98          this.color(0, this.getLength());
99      }
100 
101     /**
102      * Color a section of the document. The actual coloring will start somewhere
103      * before the requested position and continue as long as needed.
104      * 
105      * @param position
106      *            the starting point for the coloring.
107      * @param adjustment
108      *            amount of text inserted or removed at the starting point.
109      */
110     public void color(int position, int adjustment) {
111         this.colorer.color(position, adjustment);
112     }
113     
114     public void setGlobalStyle(AttributeSet value) {
115         
116         this.globalStyle = value;
117         this.colorAll();
118     }
119 
120     public void setHighlightStyle(Object valueSource) {
121         
122         Object value = valueSource;
123         
124         if (value == HighlightedDocument.GRAYED_OUT_STYLE) {
125             
126             this.setGlobalStyle(TokenStyles.getStyle("grayedOut"));
127             return;
128         }
129 
130         if (!(value instanceof Class)) {
131             value = HighlightedDocument.SQL_STYLE;
132         }
133         
134         Class<?> source = (Class<?>) value;
135         Class<?>[] parms = { Reader.class };
136         Object[] args = { this.documentReader };
137         
138         try {
139             Constructor<?> cons = source.getConstructor(parms);
140             this.syntaxLexer = (Lexer) cons.newInstance(args);
141             this.globalStyle = null;
142             this.colorAll();
143         } catch (
144             SecurityException
145             | NoSuchMethodException
146             | InstantiationException
147             | IllegalAccessException
148             | IllegalArgumentException
149             | InvocationTargetException e
150         ) {
151             LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
152         }
153     }
154     
155     //
156     // Intercept inserts and removes to color them.
157     //
158     @Override
159     public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
160         
161         synchronized (this.docLock) {
162             
163             super.insertString(offs, str, a);
164             this.color(offs, str.length());
165             this.documentReader.update(offs, str.length());
166         }
167     }
168 
169     @Override
170     public void remove(int offs, int len) throws BadLocationException {
171         
172         synchronized (this.docLock) {
173             
174             super.remove(offs, len);
175             this.color(offs, -len);
176             this.documentReader.update(offs, -len);
177         }
178     }
179 
180     // methods for Colorer to retrieve information
181     DocumentReader getDocumentReader() { return this.documentReader; }
182     Object getDocumentLock() { return this.docLock; }
183     Lexer getSyntaxLexer() { return this.syntaxLexer; }
184     AttributeSet getGlobalStyle() { return this.globalStyle; }
185 
186     /**
187      * Deactivate the colorer to end the backend thread.
188      */
189     public void stopColorer() {
190         this.colorer.stopThread();
191     }
192 }