blob: 8c109d477550c783fd9fdde593993ac1e780d19d [file] [log] [blame]
// Copyright (C) 2011 Chan Wai Shing
//
// 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 prettify;
import prettify.parser.Job;
import prettify.parser.Prettify;
import prettify.gui.SyntaxHighlighterPane;
import prettify.gui.JTextComponentRowHeader;
import prettify.theme.Theme;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JScrollPane;
/**
* The syntax highlighter.
*
* @author Chan Wai Shing <cws1989@gmail.com>
*/
public class SyntaxHighlighter extends JScrollPane {
private static final long serialVersionUID = 1L;
/**
* The script text panel.
*/
protected SyntaxHighlighterPane highlighter;
/**
* The gutter panel (line number).
*/
protected JTextComponentRowHeader highlighterRowHeader;
/**
* The theme.
*/
protected Theme theme;
/**
* The Prettify object.
*/
protected Prettify prettify;
/**
* The content of the syntax highlighter, null if there is no content so far.
*/
protected String content;
/**
* Constructor.
*
* @param theme the theme for the syntax highlighter
*/
public SyntaxHighlighter(Theme theme) {
this(theme, new SyntaxHighlighterPane());
}
/**
* Constructor.
*
* @param theme the theme for the syntax highlighter
* @param highlighterPane the script text pane of the syntax highlighter
*/
public SyntaxHighlighter(Theme theme, SyntaxHighlighterPane highlighterPane) {
super();
if (theme == null) {
throw new NullPointerException("argument 'theme' cannot be null");
}
if (highlighterPane == null) {
throw new NullPointerException("argument 'highlighterPane' cannot be null");
}
this.theme = theme;
prettify = new Prettify();
setBorder(null);
highlighter = highlighterPane;
highlighter.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
highlighter.setTheme(theme);
setViewportView(highlighter);
highlighterRowHeader = new JTextComponentRowHeader(this, highlighter);
theme.setTheme(highlighterRowHeader);
setRowHeaderView(highlighterRowHeader);
}
/**
* Re-render the script text pane. Invoke this when any change of setting that
* affect the rendering was made.
* This will re-parse the content and set the style.
*/
protected void render() {
if (content != null) {
// stop the change listener on the row header to speed up rendering
highlighterRowHeader.setListenToDocumentUpdate(false);
Job job = new Job(0, content);
prettify.langHandlerForExtension(null, content).decorate(job);
highlighter.setStyle(job.getDecorations());
// resume the change listener on the row header
highlighterRowHeader.setListenToDocumentUpdate(true);
// notify the row header to update its information related to the SyntaxHighlighterPane
// need to call this because we have stopped the change listener of the row header in previous code
highlighterRowHeader.checkPanelSize();
}
}
/**
* Get the SyntaxHighlighterPane (the script text panel).
* <b>Note: Normally should not operate on the SyntaxHighlighterPane directly.</b>
*
* @return the SyntaxHighlighterPane
*/
public SyntaxHighlighterPane getHighlighter() {
return highlighter;
}
/**
* Get the JTextComponentRowHeader, the line number panel.
* <b>Note: Normally should not operate on the JTextComponentRowHeader
* directly.</b>
*
* @return the JTextComponentRowHeader
*/
public JTextComponentRowHeader getHighlighterRowHeader() {
return highlighterRowHeader;
}
/**
* Get current theme.
*
* @return the current theme
*/
public Theme getTheme() {
return theme;
}
/**
* Set the theme.
* Setting the theme will not re-parse the content, but will clear and apply
* the new theme on the script text pane.
*
* @param theme the theme
*/
public void setTheme(Theme theme) {
if (theme == null) {
throw new NullPointerException("argument 'theme' cannot be null");
}
if (!this.theme.equals(theme)) {
this.theme = theme;
highlighter.setTheme(theme);
theme.setTheme(highlighterRowHeader);
}
}
/**
* Set the line number of the first line. E.g. if set 10, the line number will
* start count from 10 instead of 1.
*
* @param firstLine the line number of the first line
*/
public void setFirstLine(int firstLine) {
highlighterRowHeader.setLineNumberOffset(firstLine - 1);
highlighter.setLineNumberOffset(firstLine - 1);
}
/**
* Get the list of highlighted lines.
*
* @return a copy of the list
*/
public List<Integer> getHighlightedLineList() {
return highlighter.getHighlightedLineList();
}
/**
* Set highlighted lines. Note that this will clear all previous recorded
* highlighted lines.
*
* @param highlightedLineList the list that contain the highlighted lines,
* null means highlight no lines
*/
public void setHighlightedLineList(List<Integer> highlightedLineList) {
highlighterRowHeader.setHighlightedLineList(highlightedLineList);
highlighter.setHighlightedLineList(highlightedLineList);
}
/**
* Add highlighted line.
*
* @param lineNumber the line number to highlight
*/
public void addHighlightedLine(int lineNumber) {
highlighterRowHeader.addHighlightedLine(lineNumber);
highlighter.addHighlightedLine(lineNumber);
}
/**
* Check the visibility of the gutter.
*
* @return true if the gutter is visible, false if not
*/
public boolean isGutterVisible() {
return getRowHeader() != null && getRowHeader().getView() != null;
}
/**
* Set the visibility of the gutter.
*
* @param visible true to make visible, false to hide it
*/
public void setGutterVisible(boolean visible) {
if (visible) {
setRowHeaderView(highlighterRowHeader);
highlighter.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
} else {
setRowHeaderView(null);
highlighter.setBorder(null);
}
}
/**
* Check the status of the mouse-over highlight effect. Default is on.
*
* @return true if turned on, false if turned off
*/
public boolean isHighlightOnMouseOver() {
return highlighter.isHighlightOnMouseOver();
}
/**
* Set turn on the mouse-over highlight effect or not.
* If set true, there will be a highlight effect on the line that the mouse
* cursor currently is pointing on (on the script text panel only, not on the
* line number panel).
*
* @param highlightWhenMouseOver true to turn on, false to turn off
*/
public void setHighlightOnMouseOver(boolean highlightWhenMouseOver) {
highlighter.setHighlightOnMouseOver(highlightWhenMouseOver);
}
/**
* Set the content of the syntax highlighter. Better set it last after setting
* all other settings.
*
* @param file the file to read
*
* @throws IOException error occurred when reading the file
*/
public void setContent(File file) throws IOException {
setContent(readFile(file));
}
/**
* Set the content of the syntax highlighter. It is better to set other
* settings first and set this the last.
*
* @param content the content to set, null means no content
*/
public void setContent(String content) {
this.content = content;
highlighter.setContent(content);
render();
}
/**
* Get the string content of a file.
*
* @param file the file to retrieve the content from
*
* @return the string content
*
* @throws IOException error occured when reading the file
*/
protected static String readFile(File file) throws IOException {
if (file == null) {
throw new IOException("argument 'file' cannot be null");
}
byte[] buffer = new byte[(int) file.length()];
FileInputStream fileIn = null;
try {
fileIn = new FileInputStream(file);
fileIn.read(buffer);
} finally {
if (fileIn != null) {
try {
fileIn.close();
} catch (IOException ex) {
}
}
}
return new String(buffer);
}
}