| 1 | /*
|
|---|
| 2 | * Copyright 2006-2008 Kees de Kooter
|
|---|
| 3 | *
|
|---|
| 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
|---|
| 5 | * you may not use this file except in compliance with the License.
|
|---|
| 6 | * You may obtain a copy of the License at
|
|---|
| 7 | *
|
|---|
| 8 | * http://www.apache.org/licenses/LICENSE-2.0
|
|---|
| 9 | *
|
|---|
| 10 | * Unless required by applicable law or agreed to in writing, software
|
|---|
| 11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
|---|
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|---|
| 13 | * See the License for the specific language governing permissions and
|
|---|
| 14 | * limitations under the License.
|
|---|
| 15 | */
|
|---|
| 16 | package net.boplicity.xmleditor;
|
|---|
| 17 |
|
|---|
| 18 | import java.awt.Color;
|
|---|
| 19 | import java.awt.Graphics;
|
|---|
| 20 | import java.util.Collection;
|
|---|
| 21 | import java.util.LinkedHashMap;
|
|---|
| 22 | import java.util.Map;
|
|---|
| 23 | import java.util.SortedMap;
|
|---|
| 24 | import java.util.TreeMap;
|
|---|
| 25 | import java.util.regex.Matcher;
|
|---|
| 26 | import java.util.regex.Pattern;
|
|---|
| 27 |
|
|---|
| 28 | import javax.swing.text.BadLocationException;
|
|---|
| 29 | import javax.swing.text.Document;
|
|---|
| 30 | import javax.swing.text.Element;
|
|---|
| 31 | import javax.swing.text.PlainDocument;
|
|---|
| 32 | import javax.swing.text.PlainView;
|
|---|
| 33 | import javax.swing.text.Segment;
|
|---|
| 34 | import javax.swing.text.Utilities;
|
|---|
| 35 |
|
|---|
| 36 | /**
|
|---|
| 37 | * Thanks: http://groups.google.com/group/de.comp.lang.java/msg/2bbeb016abad270
|
|---|
| 38 | *
|
|---|
| 39 | * IMPORTANT NOTE: regex should contain 1 group.
|
|---|
| 40 | *
|
|---|
| 41 | * Using PlainView here because we don't want line wrapping to occur.
|
|---|
| 42 | *
|
|---|
| 43 | * @author kees
|
|---|
| 44 | */
|
|---|
| 45 | public class XmlView extends PlainView {
|
|---|
| 46 |
|
|---|
| 47 | private static Map<Pattern, Color> patternColors;
|
|---|
| 48 | private static String GENERIC_XML_NAME = "[A-Za-z]+[A-Za-z0-9\\-_]*(:[A-Za-z]+[A-Za-z0-9\\-_]+)?";
|
|---|
| 49 | private static String TAG_PATTERN = "(</?" + GENERIC_XML_NAME + ")";
|
|---|
| 50 | private static String TAG_END_PATTERN = "(>|/>)";
|
|---|
| 51 | private static String TAG_ATTRIBUTE_PATTERN = "(" + GENERIC_XML_NAME + ")\\w*\\=";
|
|---|
| 52 | private static String TAG_ATTRIBUTE_VALUE = "\\w*\\=\\w*(\"[^\"]*\")";
|
|---|
| 53 | private static String TAG_COMMENT = "(<\\!--[\\w ]*-->)";
|
|---|
| 54 | private static String TAG_CDATA = "(<\\!\\[CDATA\\[.*\\]\\]>)";
|
|---|
| 55 |
|
|---|
| 56 | static {
|
|---|
| 57 | // NOTE: the order is important!
|
|---|
| 58 | patternColors = new LinkedHashMap<>();
|
|---|
| 59 | patternColors
|
|---|
| 60 | .put(Pattern.compile(TAG_PATTERN), new Color(63, 127, 127));
|
|---|
| 61 | patternColors.put(Pattern.compile(TAG_CDATA), Color.GRAY);
|
|---|
| 62 | patternColors.put(Pattern.compile(TAG_ATTRIBUTE_PATTERN), new Color(
|
|---|
| 63 | 127, 0, 127));
|
|---|
| 64 | patternColors.put(Pattern.compile(TAG_ATTRIBUTE_VALUE), new Color(42,
|
|---|
| 65 | 0, 255));
|
|---|
| 66 | patternColors.put(Pattern.compile(TAG_COMMENT), Color.BLUE);
|
|---|
| 67 | }
|
|---|
| 68 |
|
|---|
| 69 | /**
|
|---|
| 70 | * Constructs a new {@code XmlView}.
|
|---|
| 71 | * @param element the element
|
|---|
| 72 | */
|
|---|
| 73 | public XmlView(Element element) {
|
|---|
| 74 |
|
|---|
| 75 | super(element);
|
|---|
| 76 |
|
|---|
| 77 | // Set tabsize to 4 (instead of the default 8)
|
|---|
| 78 | getDocument().putProperty(PlainDocument.tabSizeAttribute, 4);
|
|---|
| 79 | }
|
|---|
| 80 |
|
|---|
| 81 | @Override
|
|---|
| 82 | protected int drawUnselectedText(Graphics graphics, int x, int y, int p0, int p1)
|
|---|
| 83 | throws BadLocationException {
|
|---|
| 84 |
|
|---|
| 85 | Document doc = getDocument();
|
|---|
| 86 | String text = doc.getText(p0, p1 - p0);
|
|---|
| 87 |
|
|---|
| 88 | Segment segment = getLineBuffer();
|
|---|
| 89 |
|
|---|
| 90 | SortedMap<Integer, Integer> startMap = new TreeMap<>();
|
|---|
| 91 | SortedMap<Integer, Color> colorMap = new TreeMap<>();
|
|---|
| 92 |
|
|---|
| 93 | // Match all regexes on this snippet, store positions
|
|---|
| 94 | for (Map.Entry<Pattern, Color> entry : patternColors.entrySet()) {
|
|---|
| 95 |
|
|---|
| 96 | Matcher matcher = entry.getKey().matcher(text);
|
|---|
| 97 |
|
|---|
| 98 | while (matcher.find()) {
|
|---|
| 99 | startMap.put(matcher.start(1), matcher.end());
|
|---|
| 100 | colorMap.put(matcher.start(1), entry.getValue());
|
|---|
| 101 | }
|
|---|
| 102 | }
|
|---|
| 103 | /* Fix end tag duplication for CDATA and comments */
|
|---|
| 104 | Matcher matcher = Pattern.compile(TAG_END_PATTERN).matcher(text);
|
|---|
| 105 | Color c = new Color(63, 127, 127);
|
|---|
| 106 | Collection<Integer> ends = startMap.values();
|
|---|
| 107 |
|
|---|
| 108 | while (matcher.find()) {
|
|---|
| 109 | if(!ends.contains(matcher.end())) {
|
|---|
| 110 | startMap.put(matcher.start(1), matcher.end());
|
|---|
| 111 | colorMap.put(matcher.start(1), c);
|
|---|
| 112 | }
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | // TODO: check the map for overlapping parts
|
|---|
| 116 |
|
|---|
| 117 | int i = 0;
|
|---|
| 118 |
|
|---|
| 119 | // Colour the parts
|
|---|
| 120 | for (Map.Entry<Integer, Integer> entry : startMap.entrySet()) {
|
|---|
| 121 | int start = entry.getKey();
|
|---|
| 122 | int end = entry.getValue();
|
|---|
| 123 |
|
|---|
| 124 | if (i < start) {
|
|---|
| 125 | graphics.setColor(Color.black);
|
|---|
| 126 | doc.getText(p0 + i, start - i, segment);
|
|---|
| 127 | x = Utilities.drawTabbedText(segment, x, y, graphics, this, i);
|
|---|
| 128 | }
|
|---|
| 129 |
|
|---|
| 130 | graphics.setColor(colorMap.get(start));
|
|---|
| 131 | i = end;
|
|---|
| 132 | doc.getText(p0 + start, i - start, segment);
|
|---|
| 133 | x = Utilities.drawTabbedText(segment, x, y, graphics, this, start);
|
|---|
| 134 | }
|
|---|
| 135 |
|
|---|
| 136 | // Paint possible remaining text black
|
|---|
| 137 | if (i < text.length()) {
|
|---|
| 138 | graphics.setColor(Color.black);
|
|---|
| 139 | doc.getText(p0 + i, text.length() - i, segment);
|
|---|
| 140 | x = Utilities.drawTabbedText(segment, x, y, graphics, this, i);
|
|---|
| 141 | }
|
|---|
| 142 |
|
|---|
| 143 | return x;
|
|---|
| 144 | }
|
|---|
| 145 |
|
|---|
| 146 | }
|
|---|