org.zaproxy.zap.extension.httppanel.view.syntaxhighlight.HttpPanelSyntaxHighlightTextArea.java Source code

Java tutorial

Introduction

Here is the source code for org.zaproxy.zap.extension.httppanel.view.syntaxhighlight.HttpPanelSyntaxHighlightTextArea.java

Source

/*
 * Zed Attack Proxy (ZAP) and its related class files.
 * 
 * ZAP is an HTTP/HTTPS proxy for assessing web application security.
 * 
 * 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 org.zaproxy.zap.extension.httppanel.view.syntaxhighlight;

import java.awt.Color;
import java.awt.Component;
import java.util.LinkedList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;
import java.util.regex.Pattern;

import javax.swing.Action;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JViewport;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
import javax.swing.text.Highlighter.HighlightPainter;

import org.apache.commons.configuration.FileConfiguration;
import org.apache.log4j.Logger;
import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory;
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rtextarea.RTextArea;
import org.fife.ui.rtextarea.RTextScrollPane;
import org.parosproxy.paros.Constant;
import org.parosproxy.paros.extension.ExtensionPopupMenuItem;
import org.parosproxy.paros.view.View;
import org.zaproxy.zap.extension.httppanel.Message;
import org.zaproxy.zap.extension.httppanel.view.syntaxhighlight.menus.SyntaxMenu;
import org.zaproxy.zap.extension.httppanel.view.syntaxhighlight.menus.ViewMenu;
import org.zaproxy.zap.extension.search.SearchMatch;
import org.zaproxy.zap.utils.FontUtils;
import org.zaproxy.zap.view.HighlightSearchEntry;
import org.zaproxy.zap.view.HighlighterManager;

public abstract class HttpPanelSyntaxHighlightTextArea extends RSyntaxTextArea implements Observer {

    private static final long serialVersionUID = -9082089105656842054L;

    private static Logger log = Logger.getLogger(HttpPanelSyntaxHighlightTextArea.class);

    public static final String PLAIN_SYNTAX_LABEL = Constant.messages
            .getString("http.panel.view.syntaxtext.syntax.plain");

    private static final String ANTI_ALIASING = "aa";
    private static final String SHOW_LINE_NUMBERS = "linenumbers";
    private static final String WORD_WRAP = "wordwrap";
    private static final String HIGHLIGHT_CURRENT_LINE = "highlightline";
    private static final String FADE_CURRENT_HIGHLIGHT_LINE = "fadehighlightline";
    private static final String SHOW_WHITESPACE_CHARACTERS = "whitespaces";
    private static final String SHOW_NEWLINE_CHARACTERS = "newlines";
    private static final String MARK_OCCURRENCES = "markocurrences";
    private static final String ROUNDED_SELECTION_EDGES = "roundedselection";
    private static final String BRACKET_MATCHING = "bracketmatch";
    private static final String ANIMATED_BRACKET_MATCHING = "animatedbracketmatch";

    private Message message;
    private Vector<SyntaxStyle> syntaxStyles;

    private static SyntaxMenu syntaxMenu = null;
    private static ViewMenu viewMenu = null;
    private static TextAreaMenuItem cutAction = null;
    private static TextAreaMenuItem copyAction = null;
    private static TextAreaMenuItem pasteAction = null;
    private static TextAreaMenuItem deleteAction = null;
    private static TextAreaMenuItem undoAction = null;
    private static TextAreaMenuItem redoAction = null;
    private static TextAreaMenuItem selectAllAction = null;

    public HttpPanelSyntaxHighlightTextArea() {
        ((RSyntaxDocument) getDocument()).setTokenMakerFactory(getTokenMakerFactory());
        setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_NONE);

        syntaxStyles = new Vector<>();
        addSyntaxStyle(PLAIN_SYNTAX_LABEL, SyntaxConstants.SYNTAX_STYLE_NONE);

        if (syntaxMenu == null) {
            initActions();
        }

        setPopupMenu(null);

        this.message = null;

        setHyperlinksEnabled(false);

        setAntiAliasingEnabled(true);

        setLineWrap(true);

        setHighlightCurrentLine(false);
        setFadeCurrentLineHighlight(false);

        setWhitespaceVisible(false);
        setEOLMarkersVisible(false);

        setMarkOccurrences(false);

        setBracketMatchingEnabled(false);
        setAnimateBracketMatching(false);

        setAutoIndentEnabled(false);
        setCloseCurlyBraces(false);
        setCloseMarkupTags(false);
        setClearWhitespaceLinesEnabled(false);

        // Correct the font size
        this.setFont(FontUtils.getFont(this.getFont().getFontName()));

        initHighlighter();
    }

    @Override
    protected JPopupMenu createPopupMenu() {
        return null;
    }

    private void initHighlighter() {
        HighlighterManager highlighter = HighlighterManager.getInstance();

        highlighter.addObserver(this);

        if (message != null) {
            highlightAll();
        }
    }

    // Highlight all search strings from HighlightManager
    private void highlightAll() {
        HighlighterManager highlighter = HighlighterManager.getInstance();

        LinkedList<HighlightSearchEntry> highlights = highlighter.getHighlights();
        for (HighlightSearchEntry entry : highlights) {
            highlightEntryParser(entry);
        }
    }

    // Parse the TextArea data and search the HighlightEntry strings
    // Highlight all found strings
    private void highlightEntryParser(HighlightSearchEntry entry) {
        String text;
        int lastPos = 0;

        text = this.getText();

        Highlighter hilite = this.getHighlighter();
        HighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter(entry.getColor());

        while ((lastPos = text.indexOf(entry.getToken(), lastPos)) > -1) {
            try {
                hilite.addHighlight(lastPos, lastPos + entry.getToken().length(), painter);
                lastPos += entry.getToken().length();
            } catch (BadLocationException e) {
                log.warn("Could not highlight entry", e);
            }
        }
    }

    @Override
    // Apply highlights after a setText()
    public void setText(String s) {
        super.setText(s);
        highlightAll();
    }

    public abstract void search(Pattern p, List<SearchMatch> matches);

    // highlight a specific SearchMatch in the editor
    public abstract void highlight(SearchMatch sm);

    protected void highlight(int start, int end) {
        Highlighter hilite = this.getHighlighter();
        HighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter(Color.LIGHT_GRAY);

        try {
            // DOBIN
            removeAllHighlights();
            hilite.addHighlight(start, end, painter);
            this.setCaretPosition(start);
        } catch (BadLocationException e) {
            log.error(e.getMessage(), e);
        }
    }

    public Object highlight(int start, int end, HighlightPainter painter) {
        try {
            Object highlightReference = getHighlighter().addHighlight(start, end, painter);
            this.setCaretPosition(start);
            return highlightReference;
        } catch (BadLocationException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    public void removeHighlight(Object highlightReference) {
        getHighlighter().removeHighlight(highlightReference);
    }

    private void removeAllHighlights() {
        Highlighter hilite = this.getHighlighter();
        hilite.removeAllHighlights();
    }

    @Override
    // HighlighterManager called us
    // there is either
    // - a new highlight
    // - something other (added several, deleted, ...).
    public void update(Observable arg0, Object arg1) {
        if (arg1 == null) {
            // Re-highlight everything
            removeAllHighlights();
            highlightAll();
        } else {
            // Add specific highlight
            HighlightSearchEntry token = (HighlightSearchEntry) arg1;
            highlightEntryParser(token);
        }
        this.invalidate();
    }

    public void setMessage(Message aMessage) {
        this.message = aMessage;
    }

    public Message getMessage() {
        return message;
    }

    public void loadConfiguration(String key, FileConfiguration fileConfiguration) {
        setAntiAliasingEnabled(fileConfiguration.getBoolean(key + ANTI_ALIASING, this.getAntiAliasingEnabled()));

        Component c = getParent();
        if (c instanceof JViewport) {
            c = c.getParent();
            if (c instanceof RTextScrollPane) {
                final RTextScrollPane scrollPane = (RTextScrollPane) c;
                scrollPane.setLineNumbersEnabled(
                        fileConfiguration.getBoolean(key + SHOW_LINE_NUMBERS, scrollPane.getLineNumbersEnabled()));
            }
        }

        setLineWrap(fileConfiguration.getBoolean(key + WORD_WRAP, this.getLineWrap()));

        setHighlightCurrentLine(
                fileConfiguration.getBoolean(key + HIGHLIGHT_CURRENT_LINE, this.getHighlightCurrentLine()));
        setFadeCurrentLineHighlight(fileConfiguration.getBoolean(key + FADE_CURRENT_HIGHLIGHT_LINE,
                this.getFadeCurrentLineHighlight()));

        setWhitespaceVisible(
                fileConfiguration.getBoolean(key + SHOW_WHITESPACE_CHARACTERS, this.isWhitespaceVisible()));
        setEOLMarkersVisible(
                fileConfiguration.getBoolean(key + SHOW_NEWLINE_CHARACTERS, this.getEOLMarkersVisible()));

        setMarkOccurrences(fileConfiguration.getBoolean(key + MARK_OCCURRENCES, this.getMarkOccurrences()));

        setRoundedSelectionEdges(
                fileConfiguration.getBoolean(key + ROUNDED_SELECTION_EDGES, this.getRoundedSelectionEdges()));

        setBracketMatchingEnabled(
                fileConfiguration.getBoolean(key + BRACKET_MATCHING, this.isBracketMatchingEnabled()));
        setAnimateBracketMatching(
                fileConfiguration.getBoolean(key + ANIMATED_BRACKET_MATCHING, this.getAnimateBracketMatching()));
    }

    public void saveConfiguration(String key, FileConfiguration fileConfiguration) {
        fileConfiguration.setProperty(key + ANTI_ALIASING, Boolean.valueOf(this.getAntiAliasingEnabled()));

        Component c = getParent();
        if (c instanceof JViewport) {
            c = c.getParent();
            if (c instanceof RTextScrollPane) {
                final RTextScrollPane scrollPane = (RTextScrollPane) c;
                fileConfiguration.setProperty(key + SHOW_LINE_NUMBERS,
                        Boolean.valueOf(scrollPane.getLineNumbersEnabled()));
            }
        }

        fileConfiguration.setProperty(key + WORD_WRAP, Boolean.valueOf(this.getLineWrap()));

        fileConfiguration.setProperty(key + HIGHLIGHT_CURRENT_LINE,
                Boolean.valueOf(this.getHighlightCurrentLine()));
        fileConfiguration.setProperty(key + FADE_CURRENT_HIGHLIGHT_LINE,
                Boolean.valueOf(this.getFadeCurrentLineHighlight()));

        fileConfiguration.setProperty(key + SHOW_WHITESPACE_CHARACTERS,
                Boolean.valueOf(this.isWhitespaceVisible()));
        fileConfiguration.setProperty(key + SHOW_NEWLINE_CHARACTERS, Boolean.valueOf(this.getEOLMarkersVisible()));

        fileConfiguration.setProperty(key + MARK_OCCURRENCES, Boolean.valueOf(this.getMarkOccurrences()));

        fileConfiguration.setProperty(key + ROUNDED_SELECTION_EDGES,
                Boolean.valueOf(this.getRoundedSelectionEdges()));

        fileConfiguration.setProperty(key + BRACKET_MATCHING, Boolean.valueOf(this.isBracketMatchingEnabled()));
        fileConfiguration.setProperty(key + ANIMATED_BRACKET_MATCHING,
                Boolean.valueOf(this.getAnimateBracketMatching()));
    }

    public Vector<SyntaxStyle> getSyntaxStyles() {
        return syntaxStyles;
    }

    protected void addSyntaxStyle(String label, String styleKey) {
        syntaxStyles.add(new SyntaxStyle(label, styleKey));
    }

    protected abstract CustomTokenMakerFactory getTokenMakerFactory();

    private static synchronized void initActions() {
        if (syntaxMenu == null) {
            syntaxMenu = new SyntaxMenu();
            viewMenu = new ViewMenu();

            undoAction = new TextAreaMenuItem(RTextArea.UNDO_ACTION, true, false);
            redoAction = new TextAreaMenuItem(RTextArea.REDO_ACTION, false, true);

            cutAction = new TextAreaMenuItem(RTextArea.CUT_ACTION, false, false);
            copyAction = new TextAreaMenuItem(RTextArea.COPY_ACTION, false, false);
            pasteAction = new TextAreaMenuItem(RTextArea.PASTE_ACTION, false, false);
            deleteAction = new TextAreaMenuItem(RTextArea.DELETE_ACTION, false, true);

            selectAllAction = new TextAreaMenuItem(RTextArea.SELECT_ALL_ACTION, false, false);

            final List<JMenuItem> mainPopupMenuItems = View.getSingleton().getPopupList();
            mainPopupMenuItems.add(syntaxMenu);
            mainPopupMenuItems.add(viewMenu);

            mainPopupMenuItems.add(undoAction);
            mainPopupMenuItems.add(redoAction);

            mainPopupMenuItems.add(cutAction);
            mainPopupMenuItems.add(copyAction);
            mainPopupMenuItems.add(pasteAction);
            mainPopupMenuItems.add(deleteAction);

            mainPopupMenuItems.add(selectAllAction);
        }
    }

    public static class SyntaxStyle {
        private String label;
        private String styleKey;

        public SyntaxStyle(String label, String styleKey) {
            this.label = label;
            this.styleKey = styleKey;
        }

        public String getLabel() {
            return label;
        }

        public String getStyleKey() {
            return styleKey;
        }
    }

    protected static class CustomTokenMakerFactory extends AbstractTokenMakerFactory {

        @Override
        protected void initTokenMakerMap() {
            String pkg = "org.fife.ui.rsyntaxtextarea.modes.";
            putMapping(SYNTAX_STYLE_NONE, pkg + "PlainTextTokenMaker");
        }
    }

    private static class TextAreaMenuItem extends ExtensionPopupMenuItem {

        private static final long serialVersionUID = -8369459846515841057L;

        private int actionId;
        private boolean precedeWithSeparator;
        private boolean succeedWithSeparator;

        public TextAreaMenuItem(int actionId, boolean precedeWithSeparator, boolean succeedWithSeparator)
                throws IllegalArgumentException {
            this.actionId = actionId;
            this.precedeWithSeparator = precedeWithSeparator;
            this.succeedWithSeparator = succeedWithSeparator;
            Action action = RTextArea.getAction(actionId);
            if (action == null) {
                throw new IllegalArgumentException("Action not found with id: " + actionId);
            }
            setAction(action);
        }

        @Override
        public boolean isEnableForComponent(Component invoker) {
            if (invoker instanceof HttpPanelSyntaxHighlightTextArea) {
                HttpPanelSyntaxHighlightTextArea httpPanelTextArea = (HttpPanelSyntaxHighlightTextArea) invoker;

                switch (actionId) {
                case RTextArea.CUT_ACTION:
                    if (!httpPanelTextArea.isEditable()) {
                        this.setEnabled(false);
                    }
                    break;
                case RTextArea.DELETE_ACTION:
                case RTextArea.PASTE_ACTION:
                    this.setEnabled(httpPanelTextArea.isEditable());
                    break;
                case RTextArea.SELECT_ALL_ACTION:
                    this.setEnabled(httpPanelTextArea.getDocument().getLength() != 0);
                    break;
                }

                return true;
            }
            return false;
        }

        @Override
        public boolean precedeWithSeparator() {
            return precedeWithSeparator;
        }

        @Override
        public boolean succeedWithSeparator() {
            return succeedWithSeparator;
        }

        @Override
        public boolean isSafe() {
            return true;
        }
    }

}